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; } } }