WingMan

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 32  →  ?path2? @ 34
/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);
}
}
}
}