简体   繁体   中英

How to use CryptoJS in Angular 9 to get same encrypted string like C# Rfc2898DeriveBytes

I am trying to convert below C# code to angular 9 using CryptoJS because when I tried to convert C# code to angular, it gives different encrypted string.

How to convert C# code using Rfc2898DeriveBytes into angular 9 using CryptoJS?

C# code:

public static string Encrypt(string clearText)
{
   clearText = '123456';
   let EncryptionKey:any = "secret key string";
   let clearBytes :any= Encoding.Unicode.GetBytes(clearText);
   using (Aes encryptor = Aes.Create())
   {
       Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
       encryptor.Key = pdb.GetBytes(32);
       encryptor.IV = pdb.GetBytes(16);
       using (MemoryStream ms = new MemoryStream())
       {
           using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
           {
               cs.Write(clearBytes, 0, clearBytes.Length);
               cs.Close();
           }
           clearText = Convert.ToBase64String(ms.ToArray());
       }
   }
   return clearText;
}

Angular 9 code:

import * as CryptoJS from 'crypto-js';

encryptionKey: any = 'secret key string';

let encryptedStr = CryptoJS.AES.encrypt('123456', this.encryptionKey.trim()).toString();

Can anyone please help me to get the same encryption like C# using angular 9?

Alright, I know it's probably frowned upon on Stackoverflow as it is not a code-writing service but I found this challenge to be a good sport, so here goes:

let clearText = '123456';
let encryptionKey = CryptoJS.enc.Utf8.parse('secret key string');
let salt = CryptoJS.enc.Base64.parse('SXZhbiBNZWR2ZWRldg=='); // this is the byte array in .net fiddle
  
let iterations = 1000; // https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.rfc2898derivebytes?view=netcore-3.1
let keyAndIv = CryptoJS.PBKDF2(encryptionKey, salt, { keySize: 256/32 + 128/32, iterations: iterations, hasher: CryptoJS.algo.SHA1 }); // so PBKDF2 in CryptoJS is direct in that it
// always begins at the beginning of the password, whereas the .net
// implementation offsets by the last length each time .GetBytes() is called
 // so we had to generate a Iv + Salt password and then split it
let hexKeyAndIv = CryptoJS.enc.Hex.stringify(keyAndIv);

let key = CryptoJS.enc.Hex.parse(hexKeyAndIv.substring(0, 64));
let iv = CryptoJS.enc.Hex.parse(hexKeyAndIv.substring(64, hexKeyAndIv.length));

// As you're using Encoding.Unicde in .net, we have to use CryptoJS.enc.Utf16LE here.
let encryptedStr = CryptoJS.AES.encrypt(CryptoJS.enc.Utf16LE.parse(clearText), key, {iv: iv}).toString();

console.log(encryptedStr)

JSFiddle: https://jsfiddle.net/nhupdk6q/1/

Here's the corresponding code I used in.Net fiddle (sadly that does not allow to 'save' without logging in), I used the.Net Core 3.1 runtime with System.Security.Cryptography.Algorithms nuget package.

using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;

public class Program
{
    public static void Main()
    {
        var clearText = "123456";
        var EncryptionKey = "secret key string";

        var clearBytes = Encoding.Unicode.GetBytes(clearText);
        using (System.Security.Cryptography.Aes encryptor = Aes.Create())
        {
             Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
             encryptor.Key = pdb.GetBytes(32);
             encryptor.IV = pdb.GetBytes(16);
             using (MemoryStream ms = new MemoryStream())
             {     
               using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
               {
                   cs.Write(clearBytes, 0, clearBytes.Length);
                   cs.Close();
               }
               clearText = Convert.ToBase64String(ms.ToArray());
            } 
        }
    
        Console.WriteLine(clearText);
    }
}

Both listings print the same string.

The biggest challenge, as mentioned in the comments, was that since your.Net code re-uses the same PBKDF2 instance, each .GetBytes() call is essentially the next cb of the password. (cb is parameter name in .net code https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.rfc2898derivebytes.getbytes?view=netcore-3.1#System_Security_Cryptography_Rfc2898DeriveBytes_GetBytes_System_Int32_ )

The PBKDF2 in CryptoJS does not have this so we need to call it once and get both Key and Iv and then do the parsing ourselves.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM