/trunk/WingMan/Utilities/AES.cs |
@@ -1,12 +1,15 @@ |
using System; |
using System.IO; |
using System.Linq; |
using System.Security.Cryptography; |
using System.Text; |
using System.Threading.Tasks; |
|
namespace WingMan.Utilities |
{ |
public static class AES |
{ |
private const int AesKeyIterations = 4096; |
private const int AesBlockSize = 128; |
private const CipherMode AesCipherMode = CipherMode.CBC; |
private const PaddingMode AesPaddingMode = PaddingMode.PKCS7; |
@@ -23,7 +26,7 @@ |
/// <param name="key">the encryption key</param> |
/// <param name="separator">the separator to use between the cyphertext and the IV</param> |
/// <returns>Base64 encoded encrypted data</returns> |
public static byte[] Encrypt(byte[] data, string key, string separator = ":") |
public static async Task<byte[]> Encrypt(byte[] data, string key, string separator = ":") |
{ |
using (var rijdanelManaged = new RijndaelManaged()) |
{ |
@@ -35,31 +38,24 @@ |
// Compute the salt and the IV from the key. |
var salt = new byte[AesKeySaltBytes]; |
Rng.GetBytes(salt); |
using (var derivedKey = new Rfc2898DeriveBytes(key, salt)) |
var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations); |
rijdanelManaged.Key = derivedKey.GetBytes(rijdanelManaged.KeySize / 8); |
rijdanelManaged.IV = derivedKey.GetBytes(rijdanelManaged.BlockSize / 8); |
|
using (var encryptor = rijdanelManaged.CreateEncryptor(rijdanelManaged.Key, rijdanelManaged.IV)) |
{ |
rijdanelManaged.Key = derivedKey.GetBytes(rijdanelManaged.KeySize / 8); |
rijdanelManaged.IV = derivedKey.GetBytes(rijdanelManaged.BlockSize / 8); |
|
using (var encryptor = rijdanelManaged.CreateEncryptor(rijdanelManaged.Key, rijdanelManaged.IV)) |
using (var memoryStream = new MemoryStream()) |
{ |
using (var memoryStream = new MemoryStream()) |
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) |
{ |
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) |
using (var inputStream = new MemoryStream(data)) |
{ |
using (var inputStream = new MemoryStream(data)) |
{ |
inputStream.CopyTo(cryptoStream); |
cryptoStream.FlushFinalBlock(); |
await inputStream.CopyToAsync(cryptoStream); |
cryptoStream.FlushFinalBlock(); |
|
inputStream.Position = 0L; |
inputStream.Position = 0L; |
|
var payload = memoryStream.ToArray(); |
|
var base64Salt = Convert.ToBase64String(salt); |
var base64Payload = Convert.ToBase64String(payload); |
|
return Encoding.UTF8.GetBytes($"{base64Salt}{separator}{base64Payload}"); |
} |
return salt.Concat(memoryStream.ToArray()).ToArray(); |
} |
} |
} |
@@ -80,15 +76,11 @@ |
/// <param name="key">the encryption key</param> |
/// <param name="separator">the separator to use between the cyphertext and the IV</param> |
/// <returns>the decrypted data</returns> |
public static byte[] Decrypt(byte[] data, string key, string separator = ":") |
public static async Task<byte[]> Decrypt(byte[] data, string key, string separator = ":") |
{ |
var input = Encoding.UTF8.GetString(data); |
var salt = data.Take(AesKeySaltBytes).ToArray(); |
var text = data.Skip(AesKeySaltBytes).ToArray(); |
|
// retrieve the salt from the data. |
var segments = input.Split(new[] {separator}, StringSplitOptions.None); |
if (segments.Length != 2) |
throw new ArgumentException("Invalid data: " + input); |
|
using (var rijdanelManaged = new RijndaelManaged()) |
{ |
// FIPS-197 / CBC |
@@ -97,21 +89,23 @@ |
rijdanelManaged.Padding = AesPaddingMode; |
|
// Retrieve the key and the IV from the salt. |
using (var derivedKey = new Rfc2898DeriveBytes(key, Convert.FromBase64String(segments[0].Trim()))) |
var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations); |
rijdanelManaged.Key = derivedKey.GetBytes(rijdanelManaged.KeySize / 8); |
rijdanelManaged.IV = derivedKey.GetBytes(rijdanelManaged.BlockSize / 8); |
|
using (var decryptor = rijdanelManaged.CreateDecryptor(rijdanelManaged.Key, rijdanelManaged.IV)) |
{ |
rijdanelManaged.Key = derivedKey.GetBytes(rijdanelManaged.KeySize / 8); |
rijdanelManaged.IV = derivedKey.GetBytes(rijdanelManaged.BlockSize / 8); |
|
using (var decryptor = rijdanelManaged.CreateDecryptor(rijdanelManaged.Key, rijdanelManaged.IV)) |
using (var memoryStream = new MemoryStream(text)) |
{ |
using (var memoryStream = new MemoryStream(Convert.FromBase64String(segments[1].Trim()))) |
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) |
{ |
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) |
using (var outputStream = new MemoryStream()) |
{ |
using (var streamReader = new StreamReader(cryptoStream)) |
{ |
return Encoding.UTF8.GetBytes(streamReader.ReadToEnd()); |
} |
await cryptoStream.CopyToAsync(outputStream); |
|
outputStream.Position = 0L; |
|
return outputStream.ToArray(); |
} |
} |
} |