/trunk/WingMan/Utilities/AES.cs |
@@ -19,14 +19,15 @@ |
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Encrypts a string given a key and initialization vector. |
/// Encrypts an input stream given a key and initialization vector. |
/// </summary> |
/// <param name="data">the string to encrypt</param> |
/// <param name="inputStream">the stream to encrypt</param> |
/// <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 async Task<byte[]> Encrypt(byte[] data, string key, string separator = ":") |
/// <returns>an encrypted stream containing the salt and the data</returns> |
public static async Task<MemoryStream> Encrypt(Stream inputStream, string key) |
{ |
var outputStream = new MemoryStream(); |
|
using (var rijdanelManaged = new RijndaelManaged()) |
{ |
// FIPS-197 / CBC |
@@ -47,12 +48,60 @@ |
{ |
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) |
{ |
await inputStream.CopyToAsync(cryptoStream); |
cryptoStream.FlushFinalBlock(); |
|
memoryStream.Position = 0L; |
|
await outputStream.WriteAsync(salt, 0, AesKeySaltBytes); |
await memoryStream.CopyToAsync(outputStream); |
|
outputStream.Position = 0L; |
|
return outputStream; |
} |
} |
} |
} |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Encrypts a byte array given a key and initialization vector. |
/// </summary> |
/// <param name="data">the byte array to encrypt</param> |
/// <param name="key">the encryption key</param> |
/// <returns>an encrypted byte array</returns> |
public static async Task<byte[]> Encrypt(byte[] data, string key) |
{ |
using (var rijdanelManaged = new RijndaelManaged()) |
{ |
// FIPS-197 / CBC |
rijdanelManaged.BlockSize = AesBlockSize; |
rijdanelManaged.Mode = AesCipherMode; |
rijdanelManaged.Padding = AesPaddingMode; |
|
// Compute the salt and the IV from the key. |
var salt = new byte[AesKeySaltBytes]; |
Rng.GetBytes(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)) |
{ |
using (var memoryStream = new MemoryStream()) |
{ |
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) |
{ |
using (var inputStream = new MemoryStream(data)) |
{ |
await inputStream.CopyToAsync(cryptoStream); |
cryptoStream.FlushFinalBlock(); |
|
inputStream.Position = 0L; |
memoryStream.Position = 0L; |
|
return salt.Concat(memoryStream.ToArray()).ToArray(); |
} |
@@ -66,17 +115,64 @@ |
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Decrypts a Base64 encoded string using AES with a given key and initialization vector. |
/// Decrypts a byte array using a salt and a key. |
/// </summary> |
/// <param name="data"> |
/// a string consisting of the cyphertext to decrypt in Base64 and the IV in Base64 separated by the |
/// separator |
/// </param> |
/// <param name="inputStream">a salt and data stream to decrypt</param> |
/// <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 async Task<byte[]> Decrypt(byte[] data, string key, string separator = ":") |
/// <returns>a memory stream containing the decrypted data</returns> |
public static async Task<MemoryStream> Decrypt(Stream inputStream, string key) |
{ |
var outputStream = new MemoryStream(); |
|
var salt = new byte[AesKeySaltBytes]; |
await inputStream.ReadAsync(salt, 0, AesKeySaltBytes); |
|
var text = new byte[inputStream.Length - AesKeySaltBytes]; |
await inputStream.ReadAsync(text, 0, (int) (inputStream.Length - AesKeySaltBytes)); |
|
//var salt = data.Take(AesKeySaltBytes).ToArray(); |
//var text = data.Skip(AesKeySaltBytes).ToArray(); |
|
using (var rijdanelManaged = new RijndaelManaged()) |
{ |
// FIPS-197 / CBC |
rijdanelManaged.BlockSize = AesBlockSize; |
rijdanelManaged.Mode = AesCipherMode; |
rijdanelManaged.Padding = AesPaddingMode; |
|
// Retrieve the key and the IV from the salt. |
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)) |
{ |
using (var memoryStream = new MemoryStream(text)) |
{ |
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) |
{ |
await cryptoStream.CopyToAsync(outputStream); |
|
outputStream.Position = 0L; |
|
return outputStream; |
} |
} |
} |
} |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Decrypts a byte array using a salt and a key. |
/// </summary> |
/// <param name="data">a salt and data byte array to decrypt</param> |
/// <param name="key">the encryption key</param> |
/// <returns>a byte array containing the decrypted data</returns> |
public static async Task<byte[]> Decrypt(byte[] data, string key) |
{ |
var salt = data.Take(AesKeySaltBytes).ToArray(); |
var text = data.Skip(AesKeySaltBytes).ToArray(); |
|
@@ -123,4 +219,4 @@ |
return sb.ToString(0, size); |
} |
} |
} |
} |