diff --git a/src/Encryptamajig/Encryptamajig.Tester/Encryptamajig.Tester.csproj b/src/Encryptamajig/Encryptamajig.Tester/Encryptamajig.Tester.csproj index 33aac46..b9c3be4 100644 --- a/src/Encryptamajig/Encryptamajig.Tester/Encryptamajig.Tester.csproj +++ b/src/Encryptamajig/Encryptamajig.Tester/Encryptamajig.Tester.csproj @@ -35,6 +35,9 @@ prompt 4 + + Encryptamajig.Tester.Program + diff --git a/src/Encryptamajig/Encryptamajig.Tester/Program.cs b/src/Encryptamajig/Encryptamajig.Tester/Program.cs index ad982c6..2a04008 100644 --- a/src/Encryptamajig/Encryptamajig.Tester/Program.cs +++ b/src/Encryptamajig/Encryptamajig.Tester/Program.cs @@ -19,9 +19,11 @@ static void Main(string[] args) var encrypted = AesEncryptamajig.Encrypt(_plainText, _key); var roundtrip = AesEncryptamajig.Decrypt(encrypted, _key); - Debug.WriteLine(_plainText); - Debug.WriteLine(encrypted); - Debug.WriteLine(roundtrip); + Console.WriteLine(_plainText); + Console.WriteLine(encrypted); + Console.WriteLine(roundtrip); + + Console.ReadLine(); } } } diff --git a/src/Encryptamajig/Encryptamajig/AesEncryptamajig.cs b/src/Encryptamajig/Encryptamajig/AesEncryptamajig.cs index f33de3d..b40c37e 100644 --- a/src/Encryptamajig/Encryptamajig/AesEncryptamajig.cs +++ b/src/Encryptamajig/Encryptamajig/AesEncryptamajig.cs @@ -5,6 +5,8 @@ using System.Linq; using System.Security.Cryptography; + + /// /// A simple wrapper to the AesManaged class and the AES algorithm. /// Requires a securely stored key which should be a random string of characters that an attacker could never guess. @@ -13,7 +15,13 @@ /// public class AesEncryptamajig { - private static readonly int _saltSize = 32; + // Preconfigured Encryption Parameters + public static readonly int BlockBitSize = 128; // To be sure we get the correct IV size, set the block size + public static readonly int KeyBitSize = 256; // AES 256 bit key encryption + + // Preconfigured Password Key Derivation Parameters + public static readonly int SaltBitSize = 128; + public static readonly int Iterations = 10000; /// /// Encrypts the plainText input using the given Key. @@ -24,40 +32,53 @@ public class AesEncryptamajig /// The salt and the ciphertext, Base64 encoded for convenience. public static string Encrypt(string plainText, string key) { - if (string.IsNullOrEmpty(plainText)) - throw new ArgumentNullException("plainText"); + //User Error Checks if (string.IsNullOrEmpty(key)) throw new ArgumentNullException("key"); + if (string.IsNullOrEmpty(plainText)) + throw new ArgumentNullException("plainText"); - // Derive a new Salt and IV from the Key - using (var keyDerivationFunction = new Rfc2898DeriveBytes(key, _saltSize)) - { - var saltBytes = keyDerivationFunction.Salt; - var keyBytes = keyDerivationFunction.GetBytes(32); - var ivBytes = keyDerivationFunction.GetBytes(16); - - // Create an encryptor to perform the stream transform. - // Create the streams used for encryption. - using (var aesManaged = new AesManaged()) - using (var encryptor = aesManaged.CreateEncryptor(keyBytes, ivBytes)) - using (var memoryStream = new MemoryStream()) + // Derive a new Salt and IV from the Key, using a 128 bit salt and 10,000 iterations + using (var keyDerivationFunction = new Rfc2898DeriveBytes(key, SaltBitSize / 8, Iterations)) + using (var aesManaged = new AesManaged() { KeySize = KeyBitSize, BlockSize = BlockBitSize }) { - using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) - using (var streamWriter = new StreamWriter(cryptoStream)) + // Generate random IV + aesManaged.GenerateIV(); + + // Retrieve the Salt, Key and IV + byte[] saltBytes = keyDerivationFunction.Salt; + byte[] keyBytes = keyDerivationFunction.GetBytes(KeyBitSize / 8); + byte[] ivBytes = aesManaged.IV; + + // Create an encryptor to perform the stream transform. + // Create the streams used for encryption. + using (var encryptor = aesManaged.CreateEncryptor(keyBytes, ivBytes)) + using (var memoryStream = new MemoryStream()) { - // Send the data through the StreamWriter, through the CryptoStream, to the underlying MemoryStream - streamWriter.Write(plainText); - } - // Return the encrypted bytes from the memory stream, in Base64 form so we can send it right to a database (if we want). - var cipherTextBytes = memoryStream.ToArray(); - Array.Resize(ref saltBytes, saltBytes.Length + cipherTextBytes.Length); - Array.Copy(cipherTextBytes, 0, saltBytes, _saltSize, cipherTextBytes.Length); + using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) + using (var streamWriter = new StreamWriter(cryptoStream)) + { + // Send the data through the StreamWriter, through the CryptoStream, to the underlying MemoryStream + streamWriter.Write(plainText); + } + + // Return the encrypted bytes from the memory stream in Base64 form. + var cipherTextBytes = memoryStream.ToArray(); - return Convert.ToBase64String(saltBytes); + // Resize saltBytes and append IV + Array.Resize(ref saltBytes, saltBytes.Length + ivBytes.Length); + Array.Copy(ivBytes, 0, saltBytes, SaltBitSize / 8, ivBytes.Length); + + // Resize saltBytes with IV and append cipherText + Array.Resize(ref saltBytes, saltBytes.Length + cipherTextBytes.Length); + Array.Copy(cipherTextBytes, 0, saltBytes, (SaltBitSize / 8 ) + ivBytes.Length, cipherTextBytes.Length); + + return Convert.ToBase64String(saltBytes); + } } } - } + /// /// Decrypts the ciphertext using the Key. @@ -71,22 +92,31 @@ public static string Decrypt(string ciphertext, string key) throw new ArgumentNullException("cipherText"); if (string.IsNullOrEmpty(key)) throw new ArgumentNullException("key"); + + // Prepare the Salt and IV arrays + byte[] saltBytes = new byte[SaltBitSize / 8]; + byte[] ivBytes = new byte[BlockBitSize / 8]; + + // Read all the bytes from the cipher text + byte[] allTheBytes = Convert.FromBase64String(ciphertext); + + // Extract the Salt, IV from our ciphertext + Array.Copy(allTheBytes, 0, saltBytes, 0, saltBytes.Length); + Array.Copy(allTheBytes, saltBytes.Length, ivBytes, 0, ivBytes.Length); - // Extract the salt from our ciphertext - var allTheBytes = Convert.FromBase64String(ciphertext); - var saltBytes = allTheBytes.Take(_saltSize).ToArray(); - var ciphertextBytes = allTheBytes.Skip(_saltSize).Take(allTheBytes.Length - _saltSize).ToArray(); + // Extract the Ciphered bytes + byte[] ciphertextBytes = new byte[allTheBytes.Length - saltBytes.Length - ivBytes.Length]; + Array.Copy(allTheBytes, saltBytes.Length + ivBytes.Length, ciphertextBytes, 0, ciphertextBytes.Length); - using (var keyDerivationFunction = new Rfc2898DeriveBytes(key, saltBytes)) + using (var keyDerivationFunction = new Rfc2898DeriveBytes(key, saltBytes,Iterations)) { - // Derive the previous IV from the Key and Salt - var keyBytes = keyDerivationFunction.GetBytes(32); - var ivBytes = keyDerivationFunction.GetBytes(16); - + // Get the Key bytes + var keyBytes = keyDerivationFunction.GetBytes(KeyBitSize / 8); + // Create a decrytor to perform the stream transform. // Create the streams used for decryption. // The default Cipher Mode is CBC and the Padding is PKCS7 which are both good - using (var aesManaged = new AesManaged()) + using (var aesManaged = new AesManaged() { KeySize = KeyBitSize, BlockSize = BlockBitSize }) using (var decryptor = aesManaged.CreateDecryptor(keyBytes, ivBytes)) using (var memoryStream = new MemoryStream(ciphertextBytes)) using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) @@ -97,5 +127,24 @@ public static string Decrypt(string ciphertext, string key) } } } + + /// + /// A simple method to hash a string using SHA512 hashing algorithm. + /// + /// The string to be hashed. + /// The hashed text. + public static string HashString(string inputString) + { + // Create the object used for hashing + using (var hasher = SHA512Managed.Create()) + { + // Get the bytes of the input string and hash them + var inputBytes = System.Text.Encoding.UTF8.GetBytes(inputString); + var hashedBytes = hasher.ComputeHash(inputBytes); + + return Convert.ToBase64String(hashedBytes); + } + } + } } \ No newline at end of file