使用node.js中的crypto进行aes-128-cbc加密/解密不会产生与Java代码相似的结果 [英] aes-128-cbc encrytion/decryption using crypto in node.js not giving same result as similar to java code

查看:92
本文介绍了使用node.js中的crypto进行aes-128-cbc加密/解密不会产生与Java代码相似的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用第三方API,在该API中,我必须以aes-128加密形式发送数据。为了帮助您进行加密/解密,他们给了我Java代码。我试图在Node.js中复制它,但是我无法应用与普通Java代码相同的加密,因此遇到了错误。

I am working with third party API in which I have to send data in aes-128 encrypted form. For help in encryption/decryption they have given me java code. I have tried to replicate it in Node.js but i am unable to apply same encrytion as pergive java code hence I am facing error.

java中的工作代码是-

The working code in java is -

public class AesCryptUtil {
    Cipher ecipher;
    /**
     * Input a string that will be md5 hashed to create the key.
     * 
     * @return void, cipher initialized
     */
    public AesCryptUtil() {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            kgen.init(128);
            this.setupCrypto(kgen.generateKey());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public AesCryptUtil(String key) {
        SecretKeySpec skey = new SecretKeySpec(getMD5(key), "AES");
        this.setupCrypto(skey);
    }

    private void setupCrypto(SecretKey key) {
        // Create an 8-byte initialization vector
        byte[] iv = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };

        AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
        try {
            ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

            // CBC requires an initialization vector
            ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // Buffer used to transport the bytes from one stream to another
    byte[] buf = new byte[1024];

    public void encrypt(InputStream in, OutputStream out) {
        try {
            // Bytes written to out will be encrypted
            out = new CipherOutputStream(out, ecipher);

            // Read in the cleartext bytes and write to out to encrypt
            int numRead = 0;
            while ((numRead = in.read(buf)) >= 0) {
                out.write(buf, 0, numRead);
            }
            out.close();
        } catch (java.io.IOException e) {
            e.printStackTrace();
        }
    }
/**
     * Input is a string to encrypt.
     * 
     * @return a Hex string of the byte array
     */
    public String encrypt(String plaintext) {
        try {
            byte[] ciphertext = ecipher.doFinal(plaintext.getBytes("UTF-8"));
            return this.byteToHex(ciphertext);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }


    /**
     * Input encrypted String represented in HEX
     **/

    private static byte[] getMD5(String input) {
        try {
            byte[] bytesOfMessage = input.getBytes("UTF-8");
            MessageDigest md = MessageDigest.getInstance("MD5");
            return md.digest(bytesOfMessage);
        } catch (Exception e) {
            return null;
        }
    }

    static final String HEXES = "0123456789ABCDEF";

    public static String byteToHex(byte[] raw) {
        if (raw == null) {
            return null;
        }
        String result = "";
        for (int i = 0; i < raw.length; i++) {
            result += Integer.toString((raw[i] & 0xff) + 0x100, 16).substring(1);
        return result;
    }

    public static byte[] hexToByte(String hexString) {
        int len = hexString.length();
        byte[] ba = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            ba[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i + 1), 16));
        }
        return ba;
    }

    public static void main(String args[]) {
        String result = null;
        String err = null;
        String key = "DEEA29E294D8B2241FB41EF254AAB86F";
        String data = "<?xml version=" + "1.0" + " encoding=" + "UTF-8" + "?><xmltagopen></xmltagclose>";
        String action = "enc";

        if (key == null)
            err = "error: no key";
        else if (key.length() < 32)
            err = "error: key length less than 32 bytes";
        else if (data == null || action == null)
            err = "error: no data";
        else if (action == null)
            err = "error: no action";
        else if (!action.equals("enc") && !action.equals("dec"))
            err = "error: invalid action";

        if (err == null) {
            try {
                AesCryptUtil encrypter = new AesCryptUtil(key);

                if (action.equals("enc"))
                    result = encrypter.encrypt(data);
                else
                    result = encrypter.decrypt(data);
            } catch (Exception e) {
                err = "error : Exception in performing the requested operation : " + e;
            }
        }
        if (result != null)
            System.out.println(result);
        else
            System.out.println(err);
    }

}

我试图在node.js,但是它不起作用,并且我从api中收到错误消息,提示加密不正确-

I have tried to do similar in node.js but it's not working and I am getting error message from api that encryption is not correct-

const xml = '<?xml version="1.0" encoding="UTF-8"?><xmltagopen</xmltagclose>';
    let key = 'DEEA29E294D8B2241FB41EF254AAB86F';
    let encodeKey = crypto.createHash('md5').update(key, 'utf8').digest("hex");
    console.log(encodeKey);
    let ivBuffer = new Buffer.from([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]);
    let iv = ivBuffer.toString('hex');

    let cipher = crypto.createCipher('aes-128-cbc', encodeKey, iv);
    let encText = cipher.update(xml, 'utf8', 'hex');
    encText += cipher.final('hex');
    console.log(encText);


推荐答案

已弃用的中所述,nodejs.org/api/crypto.html#crypto_crypto_createcipher_algorithm_password_options rel = nofollow noreferrer> crypto.createCipher 函数从提供的密码中得出加密密钥:


crypto.createCipher()<的实现使用OpenSSL函数 EVP_BytesToKey 导出密钥,并将摘要算法设置为 MD5,一次迭代,并且不加盐。缺少盐会使字典受到攻击,因为相同的密码始终会创建相同的密钥。低迭代次数和非加密安全的哈希算法可以非常快速地测试密码。

The implementation of crypto.createCipher() derives keys using the OpenSSL function EVP_BytesToKey with the digest algorithm set to MD5, one iteration, and no salt. The lack of salt allows dictionary attacks as the same password always creates the same key. The low iteration count and non-cryptographically secure hash algorithm allow passwords to be tested very rapidly.

使用 crypto.createCipheriv 代替。

例如这样:

var crypto  = require( 'crypto' );
var encryptionKey = Buffer.from('DEEA29E294D8B2241FB41EF254AAB86F', 'hex');
var iv = Buffer.from([0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]);
// better: var iv = crypto.randomBytes(16);
var cipher  = crypto.createCipheriv( 'aes-128-cbc', encryptionKey, iv );
var buf1 = cipher.update( Buffer.from(data) );
var buf2 = cipher.final();
var encrypted = Buffer.concat([buf1, buf2]);

这篇关于使用node.js中的crypto进行aes-128-cbc加密/解密不会产生与Java代码相似的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆