Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
355 views
in Technique[技术] by (71.8m points)

node.js - Encrypt in node and decrypt in java

I have an encrypt-code in Java. I'm trying to port the encrypt part to node. Basically, node will do the encryption using the crypto module, and then Java will do the decryption.

Here's how I do encryption in Java:

protected static String encrypt(String plaintext) {
    final byte[] KEY = {
            0x6d, 0x79, 0x56, 0x65, 0x72, 0x79, 0x54, 0x6f, 0x70,
            0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b
    };

    try {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        final SecretKeySpec secretKey = new SecretKeySpec(KEY, "AES");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        final String encryptedString = Base64.encodeToString(
            cipher.doFinal(plaintext.getBytes()), Base64.DEFAULT);

        return encryptedString;
    } catch (Exception e) {
        return null;
    }
}

Here's how I do encryption in node:

var crypto = require('crypto'),
    key = new Buffer('6d7956657279546f705365637265744b', 'hex'),
    cipher = crypto.createCipher('aes-128-ecb', key),
    chunks = [];

cipher.setAutoPadding(true);
chunks.push(cipher.update(
    new Buffer(JSON.stringify({someKey: "someValue"}), 'utf8'),
    null, 'base64'));
chunks.push(cipher.final('base64'));

var encryptedString = chunks.join('');

In Java, I get the string T4RlJo5ENV8h1uvmOHzz1KjyXzBoBuqVLSTHsPppljA=. This gets decrypted correctly. However, in node, I get al084hEpTK7gOYGQRSGxF+WWKvNYhT4SC7MukrzHieM= which is obviously different and thus it won't get decrypted correctly.

I tried to look for people who has the same problem as me, and this github issue is the closest I can find. As suggested in that issue, I tried running openssl like so:

$ echo -e '{"someKey": "someValue"}' | openssl enc -a -e -aes-128-ecb -K "6d7956657279546f705365637265744b"
T4RlJo5ENV8h1uvmOHzz1MY2bhoFRHZ+ClxsV24l2BU=

The result I got was close enough to the one produced by java, but still different:

T4RlJo5ENV8h1uvmOHzz1MY2bhoFRHZ+ClxsV24l2BU=  // openssl
T4RlJo5ENV8h1uvmOHzz1KjyXzBoBuqVLSTHsPppljA=  // java
al084hEpTK7gOYGQRSGxF+WWKvNYhT4SC7MukrzHieM=  // node

Which brings me to the question, how do I make node output the same encrypted string as my java code? I can only change my code in node, but not in java.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Thought I post the a full CBC example from both the node and java sides(256 instead of 128): If you get the java.security.InvalidKeyException you have to install the Java Cryptography Extension (JCE) unlimited strength jurisdiction policy files:

Java 6 link Java 7 link Java 8 link

Java encrypt and Decrypt.

    import java.security.MessageDigest;
    import javax.crypto.spec.SecretKeySpec;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.Cipher;
    import java.util.Base64;
    import javax.xml.bind.DatatypeConverter;

    public class AESExample {
        private static byte[] iv = "0000000000000000".getBytes();
        private static String decrypt(String encrypted, String seed)
                throws Exception {
            byte[] keyb = seed.getBytes("utf-8");
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] thedigest = md.digest(keyb);
            SecretKeySpec skey = new SecretKeySpec(thedigest, "AES");
            Cipher dcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            dcipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(seed.getBytes("UTF-8"), "AES"), new IvParameterSpec(iv));
            byte[] clearbyte = dcipher.doFinal(DatatypeConverter
                    .parseHexBinary(encrypted));
            return new String(clearbyte);
        }
        public static String encrypt(String content, String key) throws Exception {
            byte[] input = content.getBytes("utf-8");
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] thedigest = md.digest(key.getBytes("utf-8"));
            SecretKeySpec skc = new SecretKeySpec(thedigest, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes("UTF-8"), "AES"), new IvParameterSpec(iv));
            byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
            int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
            ctLength += cipher.doFinal(cipherText, ctLength);
            return DatatypeConverter.printHexBinary(cipherText);
        }

public static String encrypt128(String content, String key) throws Exception {
        byte[] input = content.getBytes("utf-8");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(DatatypeConverter.parseHexBinary(key), "AES"), new IvParameterSpec(iv));
         byte[] encrypted = cipher.doFinal(content.getBytes("UTF-8"));
        return DatatypeConverter.printHexBinary(encrypted);
    }

        public static void main(String[] args) throws Exception {
            String data = "Here is my string";
            String key = "1234567891123456";
            String cipher = AESExample.encrypt(data, key);
            String decipher = AESExample.decrypt(cipher, key);
            System.out.println(cipher);
            System.out.println(decipher);
            System.out.println(AESExample.encrypt(data, "1234567891123456"));
            System.out.println(AESExample.encrypt128(data, "d7900701209d3fbac4e214dfeb5f230f"));
        }
    }

Node both directions below:

    var crypto = require('crypto');
        var iv = new Buffer('0000000000000000');
        // reference to converting between buffers http://nodejs.org/api/buffer.html#buffer_new_buffer_str_encoding
        // reference node crypto api http://nodejs.org/api/crypto.html#crypto_crypto_createcipheriv_algorithm_key_iv
        // reference to ECB vs CBC cipher methods http://crypto.stackexchange.com/questions/225/should-i-use-ecb-or-cbc-encryption-mode-for-my-block-cipher

        var encrypt = function(data, key) {
          var decodeKey = crypto.createHash('sha256').update(key, 'utf-8').digest();
          var cipher = crypto.createCipheriv('aes-256-cbc', decodeKey, iv);
          return cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
        };

        var decrypt = function(data, key) {
          var encodeKey = crypto.createHash('sha256').update(key, 'utf-8').digest();
          var cipher = crypto.createDecipheriv('aes-256-cbc', encodeKey, iv);
          return cipher.update(data, 'hex', 'utf8') + cipher.final('utf8');
        };

       var decrypt128 = function(data, key) {

          var encodeKey = crypto.createHash('sha256').update(key, 'utf-8').digest();
         var cipher = crypto.createDecipheriv('aes-128-cbc', new Buffer(key, 'hex'),
    new Buffer(
      iv));
  return cipher.update(data, 'hex', 'utf8') + cipher.final('utf8');
};
        var data = 'Here is my string'
        var key = '1234567891123456';
        var cipher = encrypt(data, key);
        var decipher = decrypt(cipher, key);
        console.log(cipher);
        console.log(decipher);
        // the string below was generated from the "main" in the java side
        console.log(decrypt(
          "79D78BEFC06827B118A2ABC6BD9D544E83F92930144432F22A6909EF18E0FDD1", key));
        console.log(decrypt128(
  "3EB7CF373E108ACA93E85D170C000938A6B3DCCED53A4BFC0F5A18B7DDC02499",
  "d7900701209d3fbac4e214dfeb5f230f"));

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...