added symmetric encrypt/decrypt support

This commit is contained in:
Kevin Froman 2020-05-25 03:52:39 -05:00
parent 1aeb224be8
commit c6325a9925
9 changed files with 175 additions and 49 deletions

View File

@ -1,8 +1,8 @@
using System.IO; using System.IO;
using System; using System;
using Sodium;
using treasurechest.STDIOWrapper; using treasurechest.STDIOWrapper;
using getpass; using getpass;
using ShannonEntropyCal;
namespace treasurechestCLI{ namespace treasurechestCLI{
@ -10,8 +10,8 @@ namespace treasurechestCLI{
public static void EncryptMessage(){ public static void EncryptMessage(){
int choice = 0; int choice = 0;
int counter = 1; int counter = 1;
byte[] key = new byte[32];
string message; string message;
string passphrase;
string encrypted; string encrypted;
translations.Strings strings = new translations.Strings(); translations.Strings strings = new translations.Strings();
@ -53,8 +53,9 @@ namespace treasurechestCLI{
catch(System.NullReferenceException){ catch(System.NullReferenceException){
continue; continue;
} }
passphrase = GetPass.getPass(strings.PASSPHRASE); key = SecretBox.GenerateKey();
encrypted = //encrypted =
} }
else if (choice == encryptMenuOptions.Length){ else if (choice == encryptMenuOptions.Length){
break; break;

85
tests/testSymmetric.cs Normal file
View File

@ -0,0 +1,85 @@
using NUnit.Framework;
using chestcrypto.symmetric;
using System;
using System.Text;
using System.Linq;
using Sodium;
namespace SymmetricTests
{
public class Tests
{
[SetUp]
public void Setup()
{
}
[Test]
public void TestDecrypt()
{
byte[] message = UTF8Encoding.UTF8.GetBytes("Hello world");
byte[] message2 = UTF8Encoding.UTF8.GetBytes("Hello worl2");
int nonceSize = 24;
byte[] nonce = SecretBox.GenerateNonce();
byte[] key = SecretBox.GenerateKey();
byte[] encrypted = SecretBox.Create(message, nonce, key);
byte[] both = new byte[nonceSize + encrypted.Length];
Buffer.BlockCopy(nonce, 0, both, 0, nonce.Length);
Buffer.BlockCopy(encrypted, 0, both, nonce.Length, encrypted.Length);
Assert.IsTrue(both.Length >= message.Length + 24);
Assert.IsTrue(Enumerable.SequenceEqual(Symmetric.decrypt(both, key), message));
Assert.IsFalse(Enumerable.SequenceEqual(Symmetric.decrypt(both, key), message2));
}
[Test]
public void TestEncryptBytesNoKey()
{
byte[] message = UTF8Encoding.UTF8.GetBytes("Hello world");
byte[] message2 = UTF8Encoding.UTF8.GetBytes("Hello worl2");
(byte[] encrypted, byte[] key) = Symmetric.encrypt(message);
int nonceSize = 24;
byte[] justCiphertext = new byte[encrypted.Length - nonceSize];
byte[] nonce = new byte[nonceSize];
int counter = 0;
for (int i = 0; i < encrypted.Length; i++){
if (i < nonceSize){
nonce[i] = encrypted[i];
continue;
}
justCiphertext[counter] = encrypted[i];
counter += 1;
}
Assert.IsTrue(Enumerable.SequenceEqual(SecretBox.Open(justCiphertext, nonce, key), message));
Assert.IsFalse(Enumerable.SequenceEqual(SecretBox.Open(justCiphertext, nonce, key), message2));
}
[Test]
public void TestEncryptBytes()
{
byte[] message = UTF8Encoding.UTF8.GetBytes("Hello world");
byte[] message2 = UTF8Encoding.UTF8.GetBytes("Hello worl2");
byte[] key = SecretBox.GenerateKey();
byte[] encrypted = Symmetric.encrypt(message, key);
int nonceSize = 24;
byte[] justCiphertext = new byte[encrypted.Length - nonceSize];
byte[] nonce = new byte[nonceSize];
int counter = 0;
for (int i = 0; i < encrypted.Length; i++){
if (i < nonceSize){
nonce[i] = encrypted[i];
continue;
}
justCiphertext[counter] = encrypted[i];
counter += 1;
}
Assert.IsTrue(Enumerable.SequenceEqual(SecretBox.Open(justCiphertext, nonce, key), message));
Assert.IsFalse(Enumerable.SequenceEqual(SecretBox.Open(justCiphertext, nonce, key), message2));
}
}
}

View File

@ -1,26 +0,0 @@
using System.Text;
using Sodium;
namespace chestcrypto{
namespace kdf{
public class DeterministicSymmetricKey{
// Test
public static byte[] generate(string passphrase, bool extraSensitive=false){
var nonce = SecretBox.GenerateNonce();
int strength = 2;
if (extraSensitive){
strength = 3;
}
return PasswordHash.ArgonHashBinary(Encoding.UTF8.GetBytes(passphrase), // Passphrase converted to bytes
PasswordHash.ArgonGenerateSalt(), // Salt
strength, strength,
32);
}
}
}
}

View File

@ -1,19 +0,0 @@
using Sodium;
using System;
using chestcrypto.kdf;
namespace treasurechest{
namespace symmetric{
public class EncryptWithPassphrase{
/* Class name is somewhat misleading as we actually derive a key from a string pass and use the key for secret key crypto*/
public static byte[] encrypt(byte[] data, string passphrase, bool extraSensitive = false){
byte[] key = DeterministicSymmetricKey.generate(passphrase, extraSensitive);
return SecretBox.Create(data, SecretBox.GenerateNonce(), key);
}
}
}
}

View File

@ -0,0 +1,23 @@
using System;
namespace chestcrypto{
namespace exceptions{
public class InvalidKeyLength : Exception
{
public InvalidKeyLength()
{
}
public InvalidKeyLength(string message)
: base(message)
{
}
public InvalidKeyLength(string message, Exception inner)
: base(message, inner)
{
}
}
}
}

View File

@ -0,0 +1,45 @@
using System.Collections.Generic;
using Sodium;
namespace chestcrypto{
namespace symmetric{
public class Symmetric{
public static byte[] encrypt(byte[] plaintext, byte[] key){
if (key.Length != 32){
throw new exceptions.InvalidKeyLength();
}
List<byte> encrypted = new List<byte>();
byte[] nonce = SecretBox.GenerateNonce();
encrypted.AddRange(nonce);
byte[] ciphertext = SecretBox.Create(plaintext, nonce, key);
encrypted.AddRange(ciphertext);
return encrypted.ToArray();
}
public static (byte[] ciphertext, byte[] key) encrypt(byte[] plaintext){
byte[] key = SecretBox.GenerateKey();
return (encrypt(plaintext, key), key);
}
public static byte[] decrypt(byte[] ciphertext, byte[] key){
// Nonce is first 24 bytes of ciphertext, unencrypted (this is safe according to libsodium docs)
int nonceSize = 24;
byte[] nonce = new byte[nonceSize];
List<byte> message = new List<byte>();
for (int i = 0; i < ciphertext.Length; i++){
if (i < nonceSize){
nonce[i] = ciphertext[i];
continue;
}
message.Add(ciphertext[i]);
}
return SecretBox.Open(message.ToArray(), nonce, key);
}
}
}
}

View File

@ -0,0 +1,16 @@
namespace chestcrypto{
namespace simplepack{
public class Packed{
//private string
//public override string ToString(){
//}
public Packed(){
}
}
}
}

View File

@ -7,6 +7,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Base58Check" Version="0.2.0" /> <PackageReference Include="Base58Check" Version="0.2.0" />
<PackageReference Include="MessagePack" Version="2.1.115" /> <PackageReference Include="MessagePack" Version="2.1.115" />
<PackageReference Include="niceware" Version="0.1.0.1" />
<PackageReference Include="Sodium.Core" Version="1.2.3" /> <PackageReference Include="Sodium.Core" Version="1.2.3" />
</ItemGroup> </ItemGroup>