Files
Common-VS2019/SacsStandardBase/Base/Data/SacsAesIvCrypter.cs
T
2025-11-20 17:17:40 +00:00

115 lines
5.0 KiB
C#

using Sarand.Net.Standard.Base.App;
using System;
using System.IO;
using System.Security.Cryptography;
namespace Sarand.Net.Standard.Base.Data
{
//=======================================================================
public static class SacsAesIvCrypter
{
//-------------------------------------------------------------------
// Properties.
public static String AesIvDelimiter { get; } = ";";
public static String AesIvPrefix { get; } = "AESIV:";
//-------------------------------------------------------------------
// Ref. https://xamarinhelp.com/cryptography-in-xamarin-forms/
// For reversible encryption, AES is generally the recommended standard.
// AES 256 requires a 32 byte key to encrypt.
// Either generate a 32 byte key or use any string and convert it into a key with CreateKey.
// NB The salt will remain the same here for each key generated - it does not need to be randomized as with hashing.
//-------------------------------------------------------------------
private static byte[] CreateKey(string password, int keyBytes = 32)
{
byte[] salt = new byte[] { 80, 70, 60, 50, 40, 30, 20, 10 };
int iterations = 300;
DeriveBytes keyGenerator = new Rfc2898DeriveBytes(password, salt, iterations, HashAlgorithmName.SHA256);
return keyGenerator.GetBytes(keyBytes);
}
//-------------------------------------------------------------------
// Encrypt String.
// Return the encrypted text with the IV appended to the end.
// In AES, the IV is a randomizer, making sure that no two identical messages ever give the same encrypted output.
// The IV can be public and does not need to be hidden.
//-------------------------------------------------------------------
public static string Encrypt(this string clearValue, string encryptionKey)
{
using (Aes aes = Aes.Create())
{
aes.Key = CreateKey(encryptionKey);
byte[] aesIV = aes.IV;
byte[] encrypted = Encrypt(clearValue, aes.Key, aesIV);
return Convert.ToBase64String(encrypted) + AesIvDelimiter + Convert.ToBase64String(aesIV);
}
}
//-------------------------------------------------------------------
public static byte[] Encrypt(string plainText, byte[] key, byte[] iv)
{
if (plainText == null || plainText.Length <= 0) throw new ArgumentNullException($"{nameof(plainText)}");
if (key == null || key.Length <= 0) throw new ArgumentNullException($"{nameof(key)}");
if (iv == null || iv.Length <= 0) throw new ArgumentNullException($"{nameof(iv)}");
byte[] encrypted;
using (Aes aes = Aes.Create())
{
aes.Key = key;
aes.IV = iv;
using (MemoryStream memoryStream = new MemoryStream())
{
using (ICryptoTransform encryptor = aes.CreateEncryptor())
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
using (StreamWriter streamWriter = new StreamWriter(cryptoStream))
{
streamWriter.Write(plainText);
}
encrypted = memoryStream.ToArray();
}
}
return encrypted;
}
//-------------------------------------------------------------------
// Decrypt String.
// Decryption requires the encrypted value and the secret key.
// This function is directly related to the above encryption process and will
// assume that the IV is at the end of the string passed in.
// To decrypt a message encrypted by another function, the IV will have to be passed explicitly.
//-------------------------------------------------------------------
public static string Decrypt(this string encryptedValue, string encryptionKey)
{
String[] valueParts = encryptedValue.Split(new String[] { AesIvDelimiter }, StringSplitOptions.None);
if (valueParts.Length != 2)
{
SaLogger.Warn("SacsAesIvCrypter.Decrypt Missing IV - assuming not encrypted");
return encryptedValue;
//throw new CryptographicException("Decrypt failure: Missing IV");
}
return Decrypt(Convert.FromBase64String(valueParts[0]), CreateKey(encryptionKey), Convert.FromBase64String(valueParts[1]));
}
//-------------------------------------------------------------------
public static string Decrypt(byte[] cipherText, byte[] key, byte[] iv)
{
if (cipherText == null || cipherText.Length <= 0) throw new ArgumentNullException($"{nameof(cipherText)}");
if (key == null || key.Length <= 0) throw new ArgumentNullException($"{nameof(key)}");
if (iv == null || iv.Length <= 0) throw new ArgumentNullException($"{nameof(iv)}");
string plaintext = "";
using (Aes aes = Aes.Create())
{
aes.Key = key;
aes.IV = iv;
using (MemoryStream memoryStream = new MemoryStream(cipherText))
using (ICryptoTransform decryptor = aes.CreateDecryptor())
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
using (StreamReader streamReader = new StreamReader(cryptoStream))
plaintext = streamReader.ReadToEnd();
}
return plaintext;
}
//-------------------------------------------------------------------
}
//=======================================================================
}