Hush – Rev 1
?pathlinks?
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;
namespace Hush.Utilities
{
public static class Aes
{
private const int AesKeySize = 256;
private const int AesKeyIterations = 4096;
private const int AesBlockSize = 128;
private const CipherMode AesCipherMode = CipherMode.CBC;
private const PaddingMode AesPaddingMode = PaddingMode.PKCS7;
private const int AesKeySaltBytes = 16;
private static readonly RNGCryptoServiceProvider Rng = new RNGCryptoServiceProvider();
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Encrypts an input stream given a key and initialization vector.
/// </summary>
/// <param name="inputStream">the stream to encrypt</param>
/// <param name="key">the encryption key</param>
/// <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 aesManaged = new AesManaged())
{
// FIPS-197 / CBC
aesManaged.BlockSize = AesBlockSize;
aesManaged.Mode = AesCipherMode;
aesManaged.Padding = AesPaddingMode;
aesManaged.KeySize = AesKeySize;
// Compute the salt and the IV from the key.
var salt = new byte[AesKeySaltBytes];
Rng.GetBytes(salt);
var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations);
aesManaged.Key = derivedKey.GetBytes(aesManaged.KeySize / 8);
aesManaged.IV = derivedKey.GetBytes(aesManaged.BlockSize / 8);
using (var encryptor = aesManaged.CreateEncryptor(aesManaged.Key, aesManaged.IV))
{
using (var memoryStream = new MemoryStream())
{
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 aesManaged = new AesManaged())
{
// FIPS-197 / CBC
aesManaged.BlockSize = AesBlockSize;
aesManaged.Mode = AesCipherMode;
aesManaged.Padding = AesPaddingMode;
aesManaged.KeySize = AesKeySize;
// Compute the salt and the IV from the key.
var salt = new byte[AesKeySaltBytes];
Rng.GetBytes(salt);
var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations);
aesManaged.Key = derivedKey.GetBytes(aesManaged.KeySize / 8);
aesManaged.IV = derivedKey.GetBytes(aesManaged.BlockSize / 8);
using (var encryptor = aesManaged.CreateEncryptor(aesManaged.Key, aesManaged.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();
memoryStream.Position = 0L;
return salt.Concat(memoryStream.ToArray()).ToArray();
}
}
}
}
}
}
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// Decrypts a byte array using a salt and a key.
/// </summary>
/// <param name="inputStream">a salt and data stream to decrypt</param>
/// <param name="key">the encryption key</param>
/// <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 aesManaged = new AesManaged())
{
// FIPS-197 / CBC
aesManaged.BlockSize = AesBlockSize;
aesManaged.Mode = AesCipherMode;
aesManaged.Padding = AesPaddingMode;
aesManaged.KeySize = AesKeySize;
// Retrieve the key and the IV from the salt.
var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations);
aesManaged.Key = derivedKey.GetBytes(aesManaged.KeySize / 8);
aesManaged.IV = derivedKey.GetBytes(aesManaged.BlockSize / 8);
using (var decryptor = aesManaged.CreateDecryptor(aesManaged.Key, aesManaged.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();
using (var aesManaged = new AesManaged())
{
// FIPS-197 / CBC
aesManaged.BlockSize = AesBlockSize;
aesManaged.Mode = AesCipherMode;
aesManaged.Padding = AesPaddingMode;
aesManaged.KeySize = AesKeySize;
// Retrieve the key and the IV from the salt.
var derivedKey = new Rfc2898DeriveBytes(key, salt, AesKeyIterations);
aesManaged.Key = derivedKey.GetBytes(aesManaged.KeySize / 8);
aesManaged.IV = derivedKey.GetBytes(aesManaged.BlockSize / 8);
using (var decryptor = aesManaged.CreateDecryptor(aesManaged.Key, aesManaged.IV))
{
using (var memoryStream = new MemoryStream(text))
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
using (var outputStream = new MemoryStream())
{
await cryptoStream.CopyToAsync(outputStream);
outputStream.Position = 0L;
return outputStream.ToArray();
}
}
}
}
}
}
public static string ExpandKey(string password, int length = 32)
{
if (length <= password.Length) return password.Substring(0, length);
while (password.Length * 2 <= length) password += password;
if (password.Length < length) password += password.Substring(0, length - password.Length);
return password;
}
}
}
Generated by GNU Enscript 1.6.5.90.