skip to Main Content

I need to convert an Rijndael encryption function from C# to Node. But I cannot match the result, even with the same Key, IV, Mode and Block Size. What am I doing wrong?

C# MRE:

using System.Security.Cryptography;
byte[] encrypted;

using (Rijndael rijAlg = Rijndael.Create())
{
    rijAlg.Key = new byte[] {  63, 115,  38, 206,  45, 102, 229,  13,
    161, 196, 250, 133, 149,  70, 153,  33,
    218,  32, 135, 149, 150,  21, 143,  11,
    210, 115, 185, 163,  24,  70, 145, 141 };

    rijAlg.IV = new byte[] { 151, 121, 168, 83, 221, 99, 206, 230, 74, 190, 106, 212, 232, 117, 192, 37 };

    ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

    using (MemoryStream msEncrypt = new MemoryStream())
    {
        using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
        {
            using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
            {
                swEncrypt.Write("1234");
            }
            encrypted = msEncrypt.ToArray();
        }
    }

    Console.WriteLine(rijAlg.BlockSize); //128
    Console.WriteLine(rijAlg.Mode); //CBC
    Console.WriteLine(rijAlg.Padding); //PKCS7
    Console.WriteLine(Convert.ToBase64String(encrypted)); //6d9SB6t9dktDJ+siSlFtOQ==
}

Node / Javascript MRE:

import Rijndael from "rijndael-js";

const key = Buffer.from([63, 115, 38, 206, 45, 102, 229, 13, 161, 196, 250, 133, 149, 70, 153, 33, 218, 32, 135, 149, 150, 21, 143, 11, 210, 115, 185, 163, 24, 70, 145, 141]);
const IV = Buffer.from([151, 121, 168, 83, 221, 99, 206, 230, 74, 190, 106, 212, 232, 117, 192, 37]);
const cipher = new Rijndael(key, "cbc");

const buffer = cipher.encrypt("1234", "128", IV);
console.log(Buffer.from(buffer).toString("base64")); //6ewzPyaxUgFX8IXW9iLJfw==

The result of encrypting "1234" in C# is "6d9SB6t9dktDJ+siSlFtOQ==" while in Node is "6ewzPyaxUgFX8IXW9iLJfw=="

2

Answers


  1. This can be a bit tricky due to differences in how each environment handles encryption, especially with things like padding and block sizes.

    In your C# code, you’re using Rijndael with a block size of 128 bits (as indicated by rijAlg.BlockSize output), and the padding mode is PKCS7. This is pretty standard for Rijndael/AES encryption.

    However, in your Node.js code, when you use rijndael-js and call cipher.encrypt, you’re specifying "256" as the block size. This might be causing the mismatch. Rijndael supports various block sizes, but AES, which is a subset of Rijndael, is fixed at a block size of 128 bits.

    So, a couple of things you might want to check:

    • Block Size: Make sure you’re using a consistent block size across
      both your C# and Node implementations. If you’re aiming for AES
      compatibility, this should be 128 bits.
    • Padding: Ensure that the padding scheme matches in both
      implementations. Mismatches in padding can lead to different results.
    • Encoding: Check that you’re handling text and byte encoding
      consistently in both environments. Sometimes, issues can arise due to
      differences in default character encoding.

    Try aligning these parameters and see if that resolves the discrepancy. Encryption can be a bit finicky with these details, so it’s all about making sure everything lines up perfectly.

    Hope this helps and best of luck with your project!

    Login or Signup to reply.
  2. Both codes use different paddings: PKCS#7 padding in the C# code, Zero padding in the NodeJS code. rijndael-js does not seem to support PKCS#7 padding, only Zero padding, s. here. Although PKCS#7 padding can easily be implemented by yourself, an alternative to the rijndael-js library is the built-in crypto module of NodeJS, which supports PKCS#7 padding by default.

    Also note that rijndael-js implements the Rijndael algorithm, while in the C# code AES is used. This works because AES is a subset of Rijndael, s. here. On the other hand, AES and not Rijndael is the standard, and since the C# side uses AES, it is obvious to use a pure AES implementation on the NodeJS side as well, which applies to the crypto module of NodeJS.

    A possible implementation with the crypto module of NodeJS is:

    import crypto from 'crypto';
    const key = Buffer.from([63, 115, 38, 206, 45, 102, 229, 13, 161, 196, 250, 133, 149, 70, 153, 33, 218, 32, 135, 149, 150, 21, 143, 11, 210, 115, 185, 163, 24, 70, 145, 141]);
    const IV = Buffer.from([151, 121, 168, 83, 221, 99, 206, 230, 74, 190, 106, 212, 232, 117, 192, 37]);
    const cipher = crypto.createCipheriv('aes-256-cbc', key, IV);
    const ciphertext = Buffer.concat([cipher.update('1234', 'utf8'), cipher.final()]).toString('base64');
    console.log(ciphertext); // 6d9SB6t9dktDJ+siSlFtOQ==
    

    This implementation gives the same ciphertext as the C# code.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search