using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace ServiceShared.Crypto
{
public static class AES
{
private static byte[] MemoryMasterKey = null;
///
/// Sets the memory master key
///
/// master key that should be set in the memory
public static void SetMemoryMasterKey(byte[] deriveKey)
{
MemoryMasterKey = deriveKey;
}
///
/// Encrypts string with password
///
/// string value that should be encrypted
/// shared deriveKey that should be used for encryption(max. 32 bytes)
/// returns encrypted base64 string
public static string Encrypt(string value, byte[] deriveKey = null)
{
string result = null;
try
{
if (deriveKey == null)
{
deriveKey = MemoryMasterKey;
}
using (AesGcm aes = new AesGcm(deriveKey))
{
byte[] nonce = new byte[AesGcm.NonceByteSizes.MaxSize];
RandomNumberGenerator.Fill(nonce);
byte[] plainText = Encoding.UTF8.GetBytes(value);
byte[] chiperBuffer = new byte[plainText.Length];
byte[] tag = new byte[AesGcm.TagByteSizes.MaxSize];
aes.Encrypt(nonce, plainText, chiperBuffer, tag);
byte[] resultBuffer = nonce.Concat(chiperBuffer).Concat(tag).ToArray();
result = Convert.ToBase64String(resultBuffer);
}
}
catch
{
result = null;
}
return result;
}
///
/// Decrypts encrypted base64 string with password
///
/// base64 string that should be decrypted
/// HKDF.DeriveKey of sharedSecret
/// returns plain string
public static string Decrypt(string value, byte[] deriveKey = null)
{
string result = null;
try
{
if (deriveKey == null)
{
deriveKey = MemoryMasterKey;
}
if (!string.IsNullOrEmpty(value) && deriveKey != null && deriveKey.Length == 32)
{
using (AesGcm aes = new AesGcm(deriveKey))
{
byte[] combined = Convert.FromBase64String(value);
byte[] tag = combined.Skip(combined.Length - AesGcm.TagByteSizes.MaxSize).ToArray();
byte[] nonce = combined.Take(AesGcm.NonceByteSizes.MaxSize).ToArray();
byte[] chiperText = combined.Skip(nonce.Length).Take(combined.Length - nonce.Length - tag.Length).ToArray();
byte[] plainTextBuffer = new byte[chiperText.Length];
aes.Decrypt(nonce, chiperText, tag, plainTextBuffer);
result = Encoding.UTF8.GetString(plainTextBuffer);
}
}
}
catch
{
result = null;
}
return result;
}
///
/// Converts the text passed password to the 32 byte array
///
/// Text based password
///
public static byte[] GetKey(string password)
{
byte[] result = null;
try
{
if (!string.IsNullOrEmpty(password))
{
if (password.Length < 32)
{
password = password.PadRight(32, '@');
}
else if (password.Length > 32)
{
password = MD5.Encrypt(password);
}
result = Encoding.ASCII.GetBytes(password);
}
}
catch (Exception ex)
{
Log.Critical(ex, "ServiceShared.Crypto.AES", "GetKey");
}
return result;
}
}
}