Created
January 12, 2023 22:00
-
-
Save Powerz/5c97b1f116ea3db0fe718e70e0d92f2b to your computer and use it in GitHub Desktop.
Encrypt and decrypt a string with a pass phrase.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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