Skip to content

Instantly share code, notes, and snippets.

@Powerz
Created January 12, 2023 22:00
Show Gist options
  • Save Powerz/5c97b1f116ea3db0fe718e70e0d92f2b to your computer and use it in GitHub Desktop.
Save Powerz/5c97b1f116ea3db0fe718e70e0d92f2b to your computer and use it in GitHub Desktop.
Encrypt and decrypt a string with a pass phrase.
using System.Security.Cryptography;
using System.Text;
/// <summary>
/// Encrypt and decrypt a string with a pass phrase.
/// // https://stackoverflow.com/questions/10168240/encrypting-decrypting-a-string-in-c-sharp
/// </summary>
public class CryptoService : ICryptoService
{
public const string DefaultPassPhrase = "WXk1CNr4m8B9JEUKI0ry355WMCwH4VUMZmuWuy8G1ieG1G7xRzjdb0Ty0YjM718n";
private const int BlockSizeBits = 128;
// This constant is used to determine the key size of the encryption algorithm in bytes.
private const int KeySizeBytes = BlockSizeBits / 8; // 16 bytes
// This constant determines the number of iterations for the password bytes generation function.
private const int DerivationIterations = 100;
public string Encrypt(string text, string passPhrase = DefaultPassPhrase)
{
// Salt and IV is randomly generated each time, but is prepended to encrypted cipher text
// so that the same Salt and IV values can be used when decrypting.
var saltStringBytes = RandomNumberGenerator.GetBytes(KeySizeBytes);
var ivStringBytes = RandomNumberGenerator.GetBytes(KeySizeBytes);
var plainTextBytes = Encoding.UTF8.GetBytes(text);
using var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations);
var keyBytes = password.GetBytes(KeySizeBytes);
using var symmetricKey = Aes.Create();
symmetricKey.BlockSize = BlockSizeBits;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes);
using var memoryStream = new MemoryStream();
using var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
var encryptedTextBytes = saltStringBytes.Concat(ivStringBytes)
.Concat(memoryStream.ToArray())
.ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(encryptedTextBytes);
}
public string Decrypt(string encryptedText, string passPhrase = DefaultPassPhrase)
{
// Get the complete stream of bytes that represent:
// [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
var encryptedTextBytesWithSaltAndIv = Convert.FromBase64String(encryptedText);
// Get the salt bytes by extracting the first 32 bytes from the supplied cipherText bytes.
var saltStringBytes = encryptedTextBytesWithSaltAndIv.Take(KeySizeBytes).ToArray();
// Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
var ivStringBytes = encryptedTextBytesWithSaltAndIv.Skip(KeySizeBytes).Take(KeySizeBytes).ToArray();
// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
var encryptedTextBytes = encryptedTextBytesWithSaltAndIv.Skip(KeySizeBytes * 2).ToArray();
using var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations);
var keyBytes = password.GetBytes(KeySizeBytes);
using var symmetricKey = Aes.Create();
symmetricKey.BlockSize = BlockSizeBits;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes);
using var memoryStream = new MemoryStream(encryptedTextBytes);
using var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
var plainTextBytes = new byte[encryptedTextBytes.Length];
var decryptedByteCount = 0;
int readBytes;
do
{
readBytes = cryptoStream.Read(plainTextBytes, decryptedByteCount, plainTextBytes.Length - decryptedByteCount);
decryptedByteCount += readBytes;
} while (readBytes > 0);
// var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
public interface ICryptoService
{
string Encrypt(string text, string passPhrase = CryptoService.DefaultPassPhrase);
string Decrypt(string encryptedText, string passPhrase = CryptoService.DefaultPassPhrase);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment