diff --git a/Rijndael256.Tests/RijndaelEtMTests.cs b/Rijndael256.Tests/RijndaelEtMTests.cs index f30ec1d..dbf1fbc 100644 --- a/Rijndael256.Tests/RijndaelEtMTests.cs +++ b/Rijndael256.Tests/RijndaelEtMTests.cs @@ -142,5 +142,16 @@ public void GenerateAeKeyRing() Assert.Equal(keyRing.CipherKey, AeKeyRingProof.CipherKey); Assert.True(keyRing.MacKey.SequenceEqual(AeKeyRingProof.MacKey)); } + + [Fact] + public void BinaryBlob() + { + var plainblob = UTF8Encoding.UTF8.GetBytes(Plaintext); + + var cipherblob = RijndaelEtM.EncryptBinary(plainblob, Password, KeySize.Aes128); + var plainresult = RijndaelEtM.DecryptBinary(cipherblob, Password, KeySize.Aes128); + + Assert.Equal(plainblob, plainresult); + } } } diff --git a/Rijndael256.Tests/RijndaelTests.cs b/Rijndael256.Tests/RijndaelTests.cs index c2e4b3e..45bc7f5 100644 --- a/Rijndael256.Tests/RijndaelTests.cs +++ b/Rijndael256.Tests/RijndaelTests.cs @@ -98,5 +98,16 @@ public void RandomIv256() Assert.Equal(plaintext, Plaintext); Assert.NotEqual(ciphertext1, ciphertext2); } + + [Fact] + public void BinaryBlob() + { + var plainblob = UTF8Encoding.UTF8.GetBytes(Plaintext); + + var cipherblob = Rijndael.EncryptBinary(plainblob, Password, KeySize.Aes128); + var plainresult = Rijndael.DecryptBinary(cipherblob, Password, KeySize.Aes128); + + Assert.Equal(plainblob, plainresult); + } } } diff --git a/Rijndael256/Rijndael.cs b/Rijndael256/Rijndael.cs index 3f11a8d..9769425 100644 --- a/Rijndael256/Rijndael.cs +++ b/Rijndael256/Rijndael.cs @@ -54,6 +54,26 @@ public static string Encrypt(byte[] plaintext, string password, KeySize keySize) return Convert.ToBase64String(ciphertext); } + /// + /// Encrypts plaintext using the Rijndael cipher in CBC mode with a password derived HMAC SHA-512 salt. + /// A random 128-bit Initialization Vector is generated for the cipher. + /// + /// The plaintext to encrypt. + /// The password to encrypt the plaintext with. + /// The cipher key size. 256-bit is stronger, but slower. + /// The encoded ciphertext. + public static byte[] EncryptBinary(byte[] plaintext, string password, KeySize keySize) + { + // Generate a random IV + var iv = Rng.GenerateRandomBytes(InitializationVectorSize); + + // Encrypt the plaintext + var ciphertext = Encrypt(plaintext, password, iv, keySize); + + // Encode the ciphertext + return ciphertext; + } + /// /// Encrypts plaintext using the Rijndael cipher in CBC mode with a password derived HMAC SHA-512 salt. /// @@ -142,6 +162,34 @@ public static string Decrypt(string ciphertext, string password, KeySize keySize return Decrypt(Convert.FromBase64String(ciphertext), password, keySize); } + /// + /// Decrypts ciphertext using the Rijndael cipher in CBC mode with a password derived HMAC SHA-512 salt. + /// + /// The ciphertext to decrypt. + /// The password to decrypt the ciphertext with. + /// The size of the cipher key used to create the ciphertext. + /// The plaintext. + public static byte[] DecryptBinary(byte[] ciphertext, string password, KeySize keySize) + { + using (var ms = new MemoryStream(ciphertext)) + { + // Extract the IV from the ciphertext + var iv = new byte[InitializationVectorSize]; + ms.Read(iv, 0, iv.Length); + + // Create a CryptoStream to decrypt the ciphertext + using (var cs = new CryptoStream(ms, CreateDecryptor(password, iv, keySize), CryptoStreamMode.Read)) + { + // Decrypt the ciphertext + using (var buffer = new MemoryStream()) + { + cs.CopyTo(buffer); + return buffer.ToArray(); + } + } + } + } + /// /// Decrypts ciphertext using the Rijndael cipher in CBC mode with a password derived HMAC SHA-512 salt. /// diff --git a/Rijndael256/RijndaelEtM.cs b/Rijndael256/RijndaelEtM.cs index d41345b..4468b83 100644 --- a/Rijndael256/RijndaelEtM.cs +++ b/Rijndael256/RijndaelEtM.cs @@ -54,6 +54,27 @@ public class RijndaelEtM : Rijndael return Convert.ToBase64String(etmCiphertext); } + /// + /// Encrypts plaintext using the Encrypt-then-MAC (EtM) mode via the Rijndael cipher in + /// CBC mode with a password derived HMAC SHA-512 salt. A random 128-bit Initialization + /// Vector is generated for the cipher. + /// + /// The plaintext to encrypt. + /// The password to encrypt the plaintext with. + /// The cipher key size. 256-bit is stronger, but slower. + /// The encoded EtM ciphertext. + public static new byte[] EncryptBinary(byte[] plaintext, string password, KeySize keySize) + { + // Generate a random IV + var iv = Rng.GenerateRandomBytes(InitializationVectorSize); + + // Encrypt the plaintext + var etmCiphertext = Encrypt(plaintext, password, iv, keySize); + + // Encode the EtM ciphertext + return etmCiphertext; + } + /// /// Encrypts plaintext using the Encrypt-then-MAC (EtM) mode via the Rijndael cipher in /// CBC mode with a password derived HMAC SHA-512 salt. @@ -96,6 +117,41 @@ public class RijndaelEtM : Rijndael return Decrypt(Convert.FromBase64String(etmCiphertext), password, keySize); } + /// + /// Decrypts authenticated ciphertext using the Rijndael cipher in CBC mode with a password derived + /// HMAC SHA-512 salt. + /// + /// The EtM ciphertext to decrypt. + /// The password to decrypt the EtM ciphertext with. + /// The size of the cipher key used to create the EtM ciphertext. + /// The plaintext. + public static new byte[] DecryptBinary(byte[] etmCiphertext, string password, KeySize keySize) + { + // Generate AE keys + var keyRing = AeKeyRing.Generate(password); + + // Extract the ciphertext and MAC from the EtM ciphertext + var mac = new byte[keyRing.MacKey.Length]; + var ciphertext = new byte[etmCiphertext.Length - mac.Length]; + using (var ms = new MemoryStream(etmCiphertext)) + { + // Extract the ciphertext + ms.Read(ciphertext, 0, ciphertext.Length); + + // Extract the MAC + ms.Read(mac, 0, mac.Length); + } + + // Calculate the MAC from the ciphertext + var newMac = CalculateMac(ciphertext, keyRing.MacKey); + + // Authenticate ciphertext + if (!mac.SequenceEqual(newMac)) throw new Exception("Authentication failed!"); + + // Decrypt the ciphertext + return Rijndael.DecryptBinary(ciphertext, keyRing.CipherKey, keySize); + } + /// /// Decrypts authenticated ciphertext using the Rijndael cipher in CBC mode with a password derived /// HMAC SHA-512 salt.