Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject>Encryptamajig.Tester.Program</StartupObject>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
Expand Down
8 changes: 5 additions & 3 deletions src/Encryptamajig/Encryptamajig.Tester/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
}
121 changes: 85 additions & 36 deletions src/Encryptamajig/Encryptamajig/AesEncryptamajig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using System.Linq;
using System.Security.Cryptography;



/// <summary>
/// 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.
Expand All @@ -13,7 +15,13 @@
/// </summary>
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;

/// <summary>
/// Encrypts the plainText input using the given Key.
Expand All @@ -24,40 +32,53 @@ public class AesEncryptamajig
/// <returns>The salt and the ciphertext, Base64 encoded for convenience.</returns>
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);
}
}
}
}


/// <summary>
/// Decrypts the ciphertext using the Key.
Expand All @@ -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))
Expand All @@ -97,5 +127,24 @@ public static string Decrypt(string ciphertext, string key)
}
}
}

/// <summary>
/// A simple method to hash a string using SHA512 hashing algorithm.
/// </summary>
/// <param name="inputString">The string to be hashed.</param>
/// <returns>The hashed text.</returns>
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);
}
}

}
}