/trunk/WingMan/Utilities/AES.cs |
@@ -0,0 +1,131 @@ |
using System; |
using System.IO; |
using System.Security.Cryptography; |
using System.Text; |
using System.Threading.Tasks; |
|
namespace WingMan.Utilities |
{ |
public static class AES |
{ |
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 a string given a key and initialization vector. |
/// </summary> |
/// <param name="data">the string 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 = ":") |
{ |
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); |
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).ConfigureAwait(false); |
cryptoStream.FlushFinalBlock(); |
|
inputStream.Position = 0L; |
|
var payload = memoryStream.ToArray(); |
|
var base64Salt = Convert.ToBase64String(salt); |
var base64Payload = Convert.ToBase64String(payload); |
|
return Encoding.UTF8.GetBytes($"{base64Salt}{separator}{base64Payload}"); |
} |
} |
} |
} |
} |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Decrypts a Base64 encoded string using AES with a given key and initialization vector. |
/// </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="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 = ":") |
{ |
var input = Encoding.UTF8.GetString(data); |
|
// retrieve the salt from the data. |
var segments = input.Split(new[] {separator}, StringSplitOptions.None); |
if (segments.Length != 2) |
throw new ArgumentException("Invalid data."); |
|
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, Convert.FromBase64String(segments[0].Trim())); |
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(Convert.FromBase64String(segments[1].Trim()))) |
{ |
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) |
{ |
using (var streamReader = new StreamReader(cryptoStream)) |
{ |
return Encoding.UTF8.GetBytes(await streamReader.ReadToEndAsync() |
.ConfigureAwait(false)); |
} |
} |
} |
} |
} |
} |
|
public static string LinearFeedbackShiftPassword(string password, int size = 32) |
{ |
var sb = new StringBuilder(password); |
do |
{ |
sb.Append(password); |
} while (sb.Length < size); |
|
return sb.ToString(0, size); |
} |
} |
} |