简体   繁体   English

Nodejs加密的字符串与Java不匹配:AES-256-CBC

[英]Nodejs Encrypted string not matching java : AES-256-CBC

Hi I have written nodejs encryption and java encryption by using same algorithm on both the side. 嗨,我在两侧都使用相同的算法编写了nodejs加密和java加密。 But Java and NodeJS are returning different encrypted string. 但是Java和NodeJS返回的加密字符串不同。 Please help me here. 请在这里帮助我。

//Here is my Java Code //这是我的Java代码

import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;

    import javax.crypto.Cipher;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    import java.util.Base64;

    public enum AESUtil {
        ;
        private static final String ENCRYPTION_KEY = "RwcmlVpg";
        private static final String ENCRYPTION_IV = "4e5Wa71fYoT7MFEX";

        public static String encrypt(String src) {
            try {
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                cipher.init(Cipher.ENCRYPT_MODE, makeKey(), makeIv());
                Base64.Encoder encoder = Base64.getEncoder();
                return encoder.encodeToString(cipher.doFinal(src.getBytes()));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        public static String decrypt(String src) {
            String decrypted = "";
            try {
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                cipher.init(Cipher.DECRYPT_MODE, makeKey(), makeIv());
                Base64.Decoder decoder = Base64.getDecoder();
                decrypted = new String(cipher.doFinal(decoder.decode(src)));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return decrypted;
        }

        static AlgorithmParameterSpec makeIv() {
            try {
                return new IvParameterSpec(ENCRYPTION_IV.getBytes("UTF-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            return null;
        }

        static Key makeKey() {
            try {
                MessageDigest md = MessageDigest.getInstance("SHA-256");
                byte[] key = md.digest(ENCRYPTION_KEY.getBytes("UTF-8"));
                return new SecretKeySpec(key, "AES");
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

            return null;
        }
    }

//Below is the code to test above code //下面是测试上面代码的代码

    public class AESMain {

        /**
         * @param args
         */
        public static void main(String[] args) {
            String src = "Hello,CryptWorld";
            String encrypted = AESUtil.encrypt(src);
            String decrypted = AESUtil.decrypt(encrypted);
            System.out.println("src: " + src);
            System.out.println("encrypted: " + encrypted);
            System.out.println("decrypted: " + decrypted);
        }

    }

Response from the above code is 上面代码的响应是

src: Hello,CryptWorld
encrypted: rh7ro9NH1XZeLX95paLETDgYxRbnDoOIrxarO0Sy73s=
decrypted: Hello,CryptWorld

//Node JS Code //节点JS代码

var Encrypt, crypto;

crypto = require("crypto");


Encrypt = module.exports = (function() {
  var b64dec, b64enc, cipher, decrypt, encrypt, iv, key;
  key = crypto.createHash("sha256").update("RwcmlVpg").digest();
  iv = '4e5Wa71fYoT7MFEX';
  cipher = function(mode, data) {
    var encipher, encoded;
    encipher = crypto[mode]("aes-256-cbc", key, iv);
    encoded = encipher.update(data);
    encoded += encipher.final();
    return encoded;
  };
  encrypt = function(data) {
    return b64enc(cipher("createCipheriv", data));
  };
  decrypt = function(data) {
    return cipher("createDecipheriv", b64dec(data));
  };
  b64enc = function(data) {
    var b;
    b = new Buffer(data, "binary");
    return b.toString("base64");
  };
  b64dec = function(data) {
    var b;
    b = new Buffer(data, "base64");
    return b.toString("binary");
  };
  return {
    encrypt: encrypt,
    decrypt: decrypt
  };
})();
var expected = Encrypt.encrypt("Hello,CryptWorld");
console.log("expected " + expected);

The Response from Node JS is 来自Node JS的响应是

expected /R79/f1H/XZeLX95/f39TDgY/Rb9Dv39/Rb9O0T9/Xs=

The node js version is v6.10.1 and JDK version 1.8.0_77. 节点js版本为v6.10.1和JDK版本1.8.0_77。

I really don't know what I am missing. 我真的不知道我在想什么。

My first hint would be to make sure that you exactly the same: 我的第一个提示是确保您完全相同

  1. character encoding 字符编码
  2. line endings 行尾

in both of your programs, for the text being encrypted and for the keys. 在您的两个程序中,都针对加密的文本和密钥。 Try printing the text buffers and keys as hex and compare those before you even do any encryption. 尝试将文本缓冲区和密钥打印为十六进制,并在进行任何加密之前进行比较。 If they differ then there's your problem. 如果它们不同,那就是您的问题。 If they're the same then it may be a problem with the encryption itself. 如果它们相同,则可能是加密本身存在问题。

Note that Node uses UTF-8 by default while Java uses UCS-2 internally as far as I know. 请注意,据我所知,Node默认情况下使用UTF-8,而Java内部使用UCS-2。 I see you're making some attempts to convert the encoding but double check the results in both envirements for bot the keys and the clear text just before the encryption step. 我看到您正在尝试转换编码,但在加密步骤之前,请仔细检查两种环境下bot密钥和明文的结果。

Also make sure that you're not encrypting base64 representation of the string instead of the string itself, or that if you use base64 for the key then you do it consistently. 还要确保您不对字符串的base64表示而不是字符串本身进行加密,或者确保如果对密钥使用base64,则必须始终进行加密。

Also, print both keys before the encryption. 另外,在加密之前打印两个密钥。 You're building them programmatically so make sure you know what they are at the end. 您是通过编程方式构建它们的,因此请确保您最终知道它们是什么。

If you make sure that you have the same keys, the same messages, the same encoding, line endings and representation (hex, base64 etc.) then use some online tool for AES encryption like: 如果确保您具有相同的密钥,相同的消息,相同的编码,行尾和表示形式(十六进制,base64等),请使用一些在线工具进行AES加密,例如:

and compare which of your program does the job correctly. 并比较您的程序哪个可以正确完成工作。

I'm not a javascript or node.js expert, but I think the problem is that the cipher.update() and cipher.final() are returning instances of Buffer , not string. 我不是javascript或node.js专家,但我认为问题在于cipher.update()cipher.final()返回的是Buffer实例,而不是字符串。 Therefore you must use Buffer.concat(...) to concatenate them, ie 因此,您必须使用Buffer.concat(...)来连接它们,即

cipher = function (mode, data) {
    var encipher, encoded;
    encipher = crypto[mode]("aes-256-cbc", key, iv);
    cipher1 = encipher.update(data);
    cipher2 = encipher.final();
    return  Buffer.concat([cipher1, cipher2]);
};

Additionally, you should never use this String.getBytes() method nor this String(byte[]) constructor in any code that strives to achieve portability or interoperability. 此外,在任何旨在实现可移植性或互操作性的代码中,切勿使用此String.getBytes()方法或此String(byte[])构造函数。 Instead, always specify the charset explicitly. 相反,请始终明确指定字符集。 I would recommend UTF_8 exclusively, eg so use String.getBytes(StandardCharsets.UTF_8) and new String(byte[], StandardCharsets.UTF_8) . 我会特别推荐UTF_8,例如,使用String.getBytes(StandardCharsets.UTF_8)new String(byte[], StandardCharsets.UTF_8)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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