added symmetric encrypt/decrypt support
This commit is contained in:
parent
1aeb224be8
commit
c6325a9925
@ -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
85
tests/testSymmetric.cs
Normal 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));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
23
treasurechest/chestcrypto/symmetric/exceptions.cs
Normal file
23
treasurechest/chestcrypto/symmetric/exceptions.cs
Normal 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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
45
treasurechest/chestcrypto/symmetric/symmetric-encryption.cs
Normal file
45
treasurechest/chestcrypto/symmetric/symmetric-encryption.cs
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
16
treasurechest/simplepack/Packed.cs
Normal file
16
treasurechest/simplepack/Packed.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
namespace chestcrypto{
|
||||||
|
|
||||||
|
namespace simplepack{
|
||||||
|
|
||||||
|
public class Packed{
|
||||||
|
//private string
|
||||||
|
//public override string ToString(){
|
||||||
|
//}
|
||||||
|
public Packed(){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user