Node.JS RC2-CBC 加密和解密密码与 C# 不匹配

标签 node.js rc2-cipher

我有一个现有的加密和解密登录,使用 key 和 IV 使用 RSC2-cbc 算法在 C# 中实现。现在我将在 node.js 中实现相同的功能。所以我写了下面的代码来加密和解密。我面临的问题是 node.js 加密字符串 (chiper) 或解密字符串与 C# encryptrd 字符串不匹配。

现有的C#代码

byte[] arrbIV = Encoding.ASCII.GetBytes("dleftaba");
byte[] arrbKey = Encoding.ASCII.GetBytes(Key); 
byte[] arrbData = Encoding.ASCII.GetBytes(sData); //Text to be encryptrd

RC2 oEncryptor = new RC2CryptoServiceProvider();

oEncryptor.Mode = CipherMode.CBC;
oEncryptor.Key = arrbKey;
oEncryptor.IV = arrbIV;

// Create memory stream to store encrypted string
MemoryStream oMemoryStream = new MemoryStream();
CryptoStream oCryptoStream = new CryptoStream(oMemoryStream, oEncryptor.CreateEncryptor(),      
CryptoStreamMode.Write);

 // Peform the encryption
 oCryptoStream.Write(arrbData, 0, arrbData.Length);
 // We have written all the data in the stream and now we can apply padding
 oCryptoStream.Close();
 string sRetVal = Convert.ToBase64String(oMemoryStream.ToArray());

等效/翻译的 node.js 代码

var crypto = require('crypto')

var SECRET_KEY = "435353553" 

var IV = "dleftaba"

var ENCODING = 'base64'

var text = "My Text"


Encryption 

var cipher = crypto.createCipheriv('rc2-cbc',key,  iv) 
var cryptedPassword = cipher.update(text, 'utf-8', 'base64')
cryptedPassword+= cipher.final('base64')

Decryption

var decipher = crypto.createDecipheriv('rc2-cbc', SECRET_KEY, IV)
var decryptedPassword = decipher.update(cryptedPassword, 'base64','utf-8')
decryptedPassword += decipher.final('utf-8')

Please suggest what is going wrong over here. Why node. js is not resulting into the identical chiper like C#.

最佳答案

虽然您使用的算法不同...这是我的 reference implementation in C# ...我已经对 Node 实现应该是什么发表了评论...并且它匹配...

我当时的目标是保持 .Net 端与 Node 端的默认值兼容...

相关:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace T1.CoreUtils
{
    public static class CryptoUtility
    {
        /*  Wanting to stay compatible with NodeJS
         *  https://stackoverflow.com/questions/18502375/aes256-encryption-decryption-in-both-nodejs-and-c-sharp-net/
         *  https://stackoverflow.com/questions/12261540/decrypting-aes256-encrypted-data-in-net-from-node-js-how-to-obtain-iv-and-key
         *  https://stackoverflow.com/questions/8008253/c-sharp-version-of-openssl-evp-bytestokey-method
         */

        /* EncrypteDefault - as NodeJS
         * var cipher = crypto.createCipher('aes-256-cbc', 'passphrase');
         * var encrypted = cipher.update("test", 'utf8', 'base64') + cipher.final('base64');
         */
        public static string EncryptDefault(string input, string passphrase = null)
        {
            byte[] key, iv;
            PassphraseToDefaultKeyAndIV(RawBytesFromString(passphrase), null, 1, out key, out iv);

            return Convert.ToBase64String(EncryptBytes(Encoding.UTF8.GetBytes(input), key, iv));
        }

        /* DecryptDefault - as NodeJS
         * var decipher = crypto.createDecipher('aes-256-cbc', 'passphrase');
         * var plain = decipher.update(encrypted, 'base64', 'utf8') + decipher.final('utf8');
         */
        public static string DecryptDefault(string inputBase64, string passphrase = null)
        {
            byte[] key, iv;
            PassphraseToDefaultKeyAndIV(RawBytesFromString(passphrase), null, 1, out key, out iv);

            return Encoding.UTF8.GetString(DecryptBytes(Convert.FromBase64String(inputBase64), key, iv));
        }

        public static string Encrypt(string input, string passphrase = null)
        {
            byte[] key, iv;
            PassphraseToSCryptKeyAndIV(passphrase, out key, out iv);

            return Convert.ToBase64String(EncryptBytes(Encoding.UTF8.GetBytes(input), key, iv));
        }

        public static string Decrypt(string inputBase64, string passphrase = null)
        {
            byte[] key, iv;
            PassphraseToSCryptKeyAndIV(passphrase, out key, out iv);

            return Encoding.UTF8.GetString(DecryptBytes(Convert.FromBase64String(inputBase64), key, iv));

        }

        static byte[] RawBytesFromString(string input)
        {
            var ret = new List<Byte>();

            foreach (char x in input)
            {
                var c = (byte)((ulong)x & 0xFF);
                ret.Add(c);
            }

            return ret.ToArray();
        }

        public static void PassphraseToSCryptKeyAndIV(string passphrase, out byte[] key, out byte[] iv)
        {
            var hashList = HashUtility.HashSCrypt(Encoding.UTF8.GetBytes(passphrase)).ToList();
            key = new byte[32];
            iv = new byte[16];
            hashList.CopyTo(0, key, 0, 32);
            hashList.CopyTo(32, iv, 0, 16);
        }

        public static void PassphraseToDefaultKeyAndIV(byte[] data, byte[] salt, int count, out byte[] key, out byte[] iv)
        {
            List<byte> hashList = new List<byte>();
            byte[] currentHash = new byte[0];

            int preHashLength = data.Length + ((salt != null) ? salt.Length : 0);
            byte[] preHash = new byte[preHashLength];

            System.Buffer.BlockCopy(data, 0, preHash, 0, data.Length);
            if (salt != null)
                System.Buffer.BlockCopy(salt, 0, preHash, data.Length, salt.Length);

            MD5 hash = MD5.Create();
            currentHash = hash.ComputeHash(preHash);

            for (int i = 1; i < count; i++)
            {
                currentHash = hash.ComputeHash(currentHash);
            }

            hashList.AddRange(currentHash);

            while (hashList.Count < 48) // for 32-byte key and 16-byte iv
            {
                preHashLength = currentHash.Length + data.Length + ((salt != null) ? salt.Length : 0);
                preHash = new byte[preHashLength];

                System.Buffer.BlockCopy(currentHash, 0, preHash, 0, currentHash.Length);
                System.Buffer.BlockCopy(data, 0, preHash, currentHash.Length, data.Length);
                if (salt != null)
                    System.Buffer.BlockCopy(salt, 0, preHash, currentHash.Length + data.Length, salt.Length);

                currentHash = hash.ComputeHash(preHash);

                for (int i = 1; i < count; i++)
                {
                    currentHash = hash.ComputeHash(currentHash);
                }

                hashList.AddRange(currentHash);
            }
            hash.Clear();
            key = new byte[32];
            iv = new byte[16];
            hashList.CopyTo(0, key, 0, 32);
            hashList.CopyTo(32, iv, 0, 16);
        }

        public static byte[] EncryptBytes(byte[] input, byte[] Key, byte[] IV)
        {
            // Check arguments. 
            if (input == null || input.Length <= 0)
                return new byte[0]; //nothing to encode
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("Key");

            // Create an RijndaelManaged object 
            // with the specified key and IV. 
            using (RijndaelManaged cipher = new RijndaelManaged())
            {
                cipher.Key = Key;
                cipher.IV = IV;
                cipher.Mode = CipherMode.CBC;
                cipher.Padding = PaddingMode.PKCS7;

                // Create a decrytor to perform the stream transform.
                ICryptoTransform encryptor = cipher.CreateEncryptor(cipher.Key, cipher.IV);

                // Create the streams used for encryption. 
                using (MemoryStream outputStream = new MemoryStream())
                {
                    using (CryptoStream encryptStream = new CryptoStream(outputStream, encryptor, CryptoStreamMode.Write))
                    {
                        encryptStream.Write(input, 0, input.Length);
                        encryptStream.FlushFinalBlock();
                        outputStream.Seek(0, 0);
                        return outputStream.ToArray();
                    }
                }
            }

        }

        public static byte[] DecryptBytes(byte[] cipherText, byte[] Key, byte[] IV)
        {
            // Check arguments. 
            if (cipherText == null || cipherText.Length <= 0)
                throw new ArgumentNullException("cipherText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("Key");

            // Create an RijndaelManaged object 
            // with the specified key and IV. 
            using (var cipher = new RijndaelManaged())
            {
                cipher.Key = Key;
                cipher.IV = IV;
                cipher.Mode = CipherMode.CBC;
                cipher.Padding = PaddingMode.PKCS7;

                // Create a decrytor to perform the stream transform.
                ICryptoTransform decryptor = cipher.CreateDecryptor(cipher.Key, cipher.IV);

                // Create the streams used for decryption. 
                using (var inputStream = new MemoryStream(cipherText))
                {
                    using (var outputStream = new MemoryStream())
                    {
                        using (CryptoStream decryptedStream = new CryptoStream(inputStream, decryptor, CryptoStreamMode.Read))
                        {
                            var buffer = new byte[1024];
                            decryptedStream.Flush();
                            var read = decryptedStream.Read(buffer, 0, buffer.Length);
                            while (read > 0)
                            {
                                outputStream.Write(buffer, 0, read);
                                decryptedStream.Flush();
                                read = decryptedStream.Read(buffer, 0, buffer.Length);
                            }
                            outputStream.Seek(0, 0);
                            return outputStream.ToArray();
                        }
                    }
                }
            }
        }
    }
}

Node .js

var crypto = require('crypto');

module.exports = {
  encrypt: encryptValue,
  decrypt: decryptValue
}

function encryptValue(input, passphrase) {
  var cipher = crypto.createCipher('aes-256-cbc', passphrase);
  var encrypted = cipher.update(input, 'utf8', 'base64') + cipher.final('base64');
  return encrypted;
}

function decryptValue(inputBase64, passphrase) {
  var decipher = crypto.createDecipher('aes-256-cbc', passphrase);
  var plain = decipher.update(inputBase64, 'base64', 'utf8') + decipher.final('utf8');
  return plain;
}

我的 .Net 代码引用 HashUtility这不是严格需要的,而且我没有可用的 scrypt 的完整 node.js 实现......它主要用于测试。

关于Node.JS RC2-CBC 加密和解密密码与 C# 不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13283397/

相关文章:

javascript - forEach 内部 promise 的结果

java - 将短字符串加密/保护为长字符串

mysql - 如何在 SequelizeJS 中进行连接?

node.js - 如何聚合 AWS SQS ApproximateNumberOfMessages

javascript - React Native 版本不匹配。无法在Android Studio中生成构建,但通过VS代码react-native run-android可以正常运行

javascript - Puppeteer:按类查找 iframe