Intentando obtener el cifrado AES de una cadena en node.js para que coincida con el valor cifrado en .net

Estoy tratando de cifrar un valor en node.js que puedo descifrar en .net. Me dieron el código que usan en el lado .net de las cosas para cifrar un valor y estoy tratando de lograr el mismo valor cifrado en mi script node.js.

Definitivamente no soy un aficionado a la encriptación, así que, por favor, ayúdame a averiguar dónde me voy mal. El valor encriptado de node.js no coincide con el valor encriptado de .net, y el valor encriptado de node.js en realidad no devuelve el mismo valor cada vez que ejecuto el script.

Aquí está la lógica de cifrado .net:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Security.Cryptography; using System.IO; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Console.WriteLine("start:"); string key = "mysecretkey"; string secret = "encryptThisMessage"; string crypto = EncryptString(secret, key); Console.WriteLine(crypto); string returnValue = DecryptString(crypto, key); Console.WriteLine(returnValue); Console.ReadKey(); } ///  /// Encrpyts the sourceString, returns this result as an Aes encrpyted, BASE64 encoded string ///  /// a plain, Framework string (ASCII, null terminated) /// The pass phrase. ///  /// returns an Aes encrypted, BASE64 encoded string ///  public static string EncryptString(string plainSourceStringToEncrypt, string passPhrase) { //Set up the encryption objects using (AesCryptoServiceProvider acsp = GetProvider(Encoding.Default.GetBytes(passPhrase))) { byte[] sourceBytes = Encoding.ASCII.GetBytes(plainSourceStringToEncrypt); ICryptoTransform ictE = acsp.CreateEncryptor(); //Set up stream to contain the encryption MemoryStream msS = new MemoryStream(); //Perform the encrpytion, storing output into the stream CryptoStream csS = new CryptoStream(msS, ictE, CryptoStreamMode.Write); csS.Write(sourceBytes, 0, sourceBytes.Length); csS.FlushFinalBlock(); //sourceBytes are now encrypted as an array of secure bytes byte[] encryptedBytes = msS.ToArray(); //.ToArray() is important, don't mess with the buffer //return the encrypted bytes as a BASE64 encoded string return Convert.ToBase64String(encryptedBytes); } } ///  /// Decrypts a BASE64 encoded string of encrypted data, returns a plain string ///  /// an Aes encrypted AND base64 encoded string /// The passphrase. /// returns a plain string public static string DecryptString(string base64StringToDecrypt, string passphrase) { //Set up the encryption objects using (AesCryptoServiceProvider acsp = GetProvider(Encoding.Default.GetBytes(passphrase))) { byte[] RawBytes = Convert.FromBase64String(base64StringToDecrypt); ICryptoTransform ictD = acsp.CreateDecryptor(); //RawBytes now contains original byte array, still in Encrypted state //Decrypt into stream MemoryStream msD = new MemoryStream(RawBytes, 0, RawBytes.Length); CryptoStream csD = new CryptoStream(msD, ictD, CryptoStreamMode.Read); //csD now contains original byte array, fully decrypted //return the content of msD as a regular string return (new StreamReader(csD)).ReadToEnd(); } } private static AesCryptoServiceProvider GetProvider(byte[] key) { AesCryptoServiceProvider result = new AesCryptoServiceProvider(); result.BlockSize = 128; result.KeySize = 128; result.Mode = CipherMode.CBC; result.Padding = PaddingMode.PKCS7; result.GenerateIV(); result.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; byte[] RealKey = GetKey(key, result); result.Key = RealKey; // result.IV = RealKey; return result; } private static byte[] GetKey(byte[] suggestedKey, SymmetricAlgorithm p) { byte[] kRaw = suggestedKey; List kList = new List(); for (int i = 0; i < p.LegalKeySizes[0].MinSize; i += 8) { kList.Add(kRaw[(i / 8) % kRaw.Length]); } byte[] k = kList.ToArray(); return k; } } } 

Mi script node.js:

 var crypto = require('crypto-js'); var key = "mysecretkey"; var secret = "encryptThisMessage"; e1 = crypto.AES.encrypt(secret, key, {mode: crypto.mode.CBC, padding: crypto.pad.Pkcs7}); e2 = crypto.AES.encrypt(secret, key, {mode: crypto.mode.CBC, padding: crypto.pad.Pkcs7}); console.log('e1'); console.log(crypto.enc.Hex.stringify(e1)); console.log(e1.toString()); console.log(e1.salt.toString()); console.log(e1.iv.toString()); console.log(e1.ciphertext.toString()); console.log(e1.ciphertext.toString(crypto.enc.Base64)); console.log('e2'); console.log(e2.toString()); console.log(e2.salt.toString()); console.log(e2.iv.toString()); console.log(e2.ciphertext.toString(crypto.enc.Base64)); 

Cuando se ejecuta la pieza de cifrado en el código c #, el valor se ve así: (ligeramente modificado por motivos de seguridad) dp+8cjr/ajEw5oePdiG+4g== . ¿Cómo puedo cambiar mi código node.js para generar este valor cifrado coincidente?

Salida del script node.js:

introduzca la descripción de la imagen aquí

Estás mezclando manzanas y naranjas .

Cuando pasa una cadena como clave a CryptoJS , deriva una clave y iv que utiliza para el descifrado. La cadena se trata como una frase de contraseña , que está salada . Ejecuta este código un par de veces en node.js:

 var key = "mysecretkey"; var secret = "encryptThisMessage"; e1 = crypto.AES.encrypt(secret, key, {mode: crypto.mode.CBC, padding: crypto.pad.Pkcs7}); console.log("key: " + crypto.enc.Base64.stringify(e1.key)); console.log("iv: " + crypto.enc.Base64.stringify(e1.iv)); console.log("salt: " + crypto.enc.Base64.stringify(e1.salt)); console.log("ciphertext: " + crypto.enc.Base64.stringify(e1.ciphertext)); p = crypto.AES.decrypt(e1, key, {mode: crypto.mode.CBC, padding: crypto.pad.Pkcs7}); console.log("decrypted: " + crypto.enc.Utf8.stringify(p)); 

Tenga en cuenta que produce diferentes claves e IV cada vez, pero siempre se descifra al original (porque e1 lleva la sal que permite descifrar derivar la misma clave). Echa un vistazo a esta documentación para CryptoJS aquí .

En su código C # , siempre está utilizando la misma clave y IV . Estos no coinciden con la clave y IV en CryptoJS. Pruebe este código que coincide exactamente con la clave y IV que produce su código C #:

 var key = crypto.enc.Base64.parse('bXlzZWNyZXRrZXlteXNlYw=='); // Matching C# code's key var iv = crypto.enc.Base64.parse('AAAAAAAAAAAAAAAAAAAAAA=='); // 16 ZERO bytes, same as C# code var secret = "encryptThisMessage"; e1 = crypto.AES.encrypt(secret, key, {iv: iv, mode: crypto.mode.CBC, padding: crypto.pad.Pkcs7}); console.log("ciphertext: " + crypto.enc.Base64.stringify(e1.ciphertext)); 

Tenga en cuenta que esta vez no le estoy pasando a CryptoJS una cadena para que la clave se interprete como una frase de contraseña, sino una matriz de palabras CryptoJS que debe interpretarse directamente como bytes de clave . Además, estoy pasando la IV en los params.

Ese último bit de código produce el mismo texto cifrado que su código C #. Estoy usando Base64 aquí para la clave y IV como un atajo conveniente para crear matrices de palabras. Use la misma llave y IV en ambos extremos y funcionará.

EDITAR:

Me pareció interesante mostrar la derivación de la clave CryptoJS (es decir, OpenSSL) en el código, de modo que, en lugar de que CryptoJS coincida con C #, tenga C # que coincida con CryptoJS.

La derivación de la clave OpenSSL se describe aquí .

Esto deriva la clave y IV – simple para mayor claridad:

 public byte[] Derive48(string passphrase, byte[] salt) { using (var md5 = new MD5CryptoServiceProvider()) { var source = Encoding.UTF8.GetBytes(passphrase).Concat(salt).ToArray(); var data = md5.ComputeHash(source); var output = data; while (output.Length < 48) { data = md5.ComputeHash(data.Concat(source).ToArray()); output = output.Concat(data).ToArray(); } return output.Take(48).ToArray(); } } 

Puedes usarlo así:

 string key = "mysecretkey"; string secret = "encryptThisMessage"; byte[] salt = Convert.FromBase64String("zTEeMVPN2eY="); string crypto = EncryptString(secret, key, salt); Console.WriteLine(crypto); string returnValue = DecryptString(crypto, key, salt); Console.WriteLine(returnValue); 

...

 public string EncryptString(string plainSourceStringToEncrypt, string passPhrase, byte[] salt) { //Set up the encryption objects using (AesCryptoServiceProvider acsp = GetProvider(passPhrase, salt)) { 

...

 private AesCryptoServiceProvider GetProvider(string passphrase, byte[] salt) { AesCryptoServiceProvider result = new AesCryptoServiceProvider(); result.BlockSize = 128; result.KeySize = 128; result.Mode = CipherMode.CBC; result.Padding = PaddingMode.PKCS7; var derived = this.Derive48(passphrase, salt); result.Key = derived.Take(32).ToArray(); result.IV = derived.Skip(32).Take(16).ToArray(); return result; }