Skip to content

Instantly share code, notes, and snippets.

@scottrudy
Created July 29, 2022 17:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save scottrudy/3bc255b8f601b0e15f6f76a533fe1253 to your computer and use it in GitHub Desktop.
Save scottrudy/3bc255b8f601b0e15f6f76a533fe1253 to your computer and use it in GitHub Desktop.
Example of AES-256-CBC encryption and decryption functions, which use a shared key and a SHA-256 HMAC, that works across .NET (tested on 6) and Node (tested on 16.16).
using System.Security.Cryptography;
using System.Text;
internal class Program
{
private static async Task Main(string[] args)
{
var passKey = "0102030405060708091011121314151617181920212223242526272829303132"; // some 64 character hex string (32 bytes)
var testString = "Hello, World! How are you today? I am doing fine and thought I would drop you a line and say hello, because you're pretty cool.";
var encryptedString = await EncryptAsync(testString, passKey).ConfigureAwait(false);
Console.WriteLine(encryptedString);
var decryptedString = await DecryptAsync(encryptedString, passKey).ConfigureAwait(false);
Console.WriteLine(decryptedString);
}
private static async Task<string> EncryptAsync(string plainText, string hexKey) {
var key = Convert.FromHexString(hexKey);
using Aes aes = Aes.Create();
aes.Key = key;
aes.GenerateIV();
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.Zeros;
ICryptoTransform cipher = aes.CreateEncryptor();
using var ms = new MemoryStream();
using var cs = new CryptoStream(ms, cipher, CryptoStreamMode.Write);
await cs.WriteAsync(Encoding.UTF8.GetBytes(plainText)).ConfigureAwait(false);
await cs.FlushFinalBlockAsync().ConfigureAwait(false);
var encryptedStringHex = Convert.ToHexString(ms.ToArray());
var ivStr = Convert.ToHexString(aes.IV);
using var hmacsha256 = new HMACSHA256(key);
var hmac = Convert.ToHexString(hmacsha256.ComputeHash(Encoding.ASCII.GetBytes(ivStr+encryptedStringHex)));
return ivStr+encryptedStringHex+hmac;
}
private static async Task<string> DecryptAsync(string encrypted, string hexKey) {
var key = Convert.FromHexString(hexKey);
var ivStr = encrypted.Substring(0, 32);
var encryptedStringHex = encrypted.Substring(32, encrypted.Length - 64 - 32);
var encryptedString = Convert.FromHexString(encryptedStringHex);
var hashHex = encrypted.Substring(encrypted.Length - 64, 64);
using var hmacsha256 = new HMACSHA256(key);
var hmac = Convert.ToHexString(hmacsha256.ComputeHash(Encoding.ASCII.GetBytes(ivStr+encryptedStringHex)));
if (!hmac.Equals(hashHex, StringComparison.OrdinalIgnoreCase)) {
Console.WriteLine("Error: HMAC did not match.");
}
using Aes aes = Aes.Create();
aes.Key = key;
aes.IV = Convert.FromHexString(ivStr);
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.None;
ICryptoTransform decipher = aes.CreateDecryptor(aes.Key, aes.IV);
using var ms = new MemoryStream(encryptedString);
using var cs = new CryptoStream(ms, decipher, CryptoStreamMode.Read);
using var sr = new StreamReader(cs);
var plainText = await sr.ReadToEndAsync().ConfigureAwait(false);
return plainText;
}
}
let crypto = require("crypto");
function encrypt(plainText, hexKey) {
let key = Buffer.from(hexKey,'hex');
let iv = crypto.randomBytes(16);
// create cipher
let cipher = crypto.createCipheriv('aes-256-cbc', key, iv).setAutoPadding(false);
let padLength = Buffer.byteLength(plainText, 'utf8') % 16;
padLength = padLength === 0 ? 0 : 16 - padLength;
plainText = plainText.padEnd(plainText.length + padLength);
let cipherText = cipher.update(plainText, 'utf8', 'hex');
cipherText += cipher.final('hex');
cipherText = cipherText.toUpperCase();
const ivStr = iv.toString('hex').toUpperCase();
let concat = ivStr + cipherText;
let hmac = crypto.createHmac('sha256', key).update(ivStr + cipherText).digest('hex').toUpperCase();
console.log(ivStr);
console.log(cipherText);
console.log(hmac);
return (ivStr + cipherText + hmac);
}
function decrypt(encrypted, hexKey) {
let key = Buffer.from(hexKey, 'hex');
let ivStr = encrypted.substr(0, 32);
let encryptedStringHex = encrypted.substr(32, encrypted.length - 64 - 32);
let encryptedString = Buffer.from(encryptedStringHex, 'hex');
let hashHex = encrypted.substr(encrypted.length - 64, 64);
let hmac = crypto.createHmac('sha256', key).update(ivStr + encryptedStringHex).digest('hex').toUpperCase();
if (hmac !== hashHex) {
console.log("Error: HMAC did not match.");
}
let iv = Buffer.from(ivStr, 'hex');
let decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
decipher.setAutoPadding(false);
let plainText = '';
decipher.on('readable', () => {
let data = decipher.read();
if (data) {
plainText += data.toString('utf8');
}
});
decipher.write(encryptedString, 'hex');
decipher.end();
return plainText.trim();
}
let passKey = "0102030405060708091011121314151617181920212223242526272829303132"; // some 64 character hex string (32 bytes)
let testString = "How are you today? I am doing fine and thought I would drop you a line and say hello, because you're pretty cool.";
let encryptedString = encrypt(testString, passKey)
console.log(encryptedString);
let decryptedString = decrypt(encryptedString, passKey);
console.log(decryptedString);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment