115 lines
5.0 KiB
C#
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;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
}
|
|
//=======================================================================
|
|
}
|