在Node.js中加密字符串并在Java中解密

时间:2018-07-05 15:26:41

标签: node.js encryption node-crypto

我正在用NODEJS加密文本,并尝试用Java解密,但出现错误。 我的nodejs代码:

var crypto = require('crypto')
  , key = 'mykey@91'
  , plaintext = 'SS18617710213463'
  , cipher = crypto.createCipher('aes-128-ecb', key)
  , decipher = crypto.createDecipher('aes-128-ecb', key);



var encryptedPassword = cipher.update(plaintext, 'utf8', 'base64');

encryptedPassword += cipher.final('base64')

var decryptedPassword = decipher.update(encryptedPassword, 'base64', 'utf8');
decryptedPassword += decipher.final('utf8');

console.log('original  :', plaintext); 
console.log('encrypted :', encryptedPassword);
console.log('decrypted :', decryptedPassword);

但是当我尝试解密它时,它总是抛出错误。

public static String decrypt(String encryptedText) {
    try {
         final String key = "mykey@91";
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] cipherText = Base64.getDecoder().decode(encryptedText.getBytes("UTF8"));
        String decryptedString = new String(cipher.doFinal(cipherText),"UTF8");
        return decryptedString;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

我得到的错误如下:

  

java.security.InvalidKeyException:无效的AES密钥长度:8个字节

1 个答案:

答案 0 :(得分:2)

得到Invalid AES key length: 8 bytes invalid AES的原因与键和文本的长度有关。您需要确保其长度(以位为单位)为2的幂。如果要使用字符串作为加密密钥,请检查其长度(以字节为单位),然后乘以8以找到以位为单位的长度。同样,大多数String实现都需要每个字符2个字节(Java 64位)。这里的详细信息:How to solve InvalidKeyException

在这种情况下,仅使用填充键或更长的键,上述错误就会消失,例如:

static String PLAIN_TEXT = "SS18617710213463"; 
static String ENCRYPTION_KEY = "mykey@91mykey@91";

但是,还有另一件事要考虑。 Java实现必须匹配node.js提供的确切算法。这并不像听起来那么容易(至少根据我的经验)。对于您的情况,我建议您在node.js端使用node-forge,这样更容易匹配Java实现:

var forge = require('node-forge');

var plaintext = 'SS18617710213463';  
var key = 'mykey@91mykey@91';
var iv = 'AODVNUASDNVVAOVF';

console.log('Plain Text: ' + plaintext); 

var cipher = forge.cipher.createCipher('AES-CBC', key);
cipher.start({iv: iv});
cipher.update(forge.util.createBuffer(plaintext));
cipher.finish();
var encrypted = cipher.output;

var encodedB64 = forge.util.encode64(encrypted.data);
console.log("Encoded: " + encodedB64);

var decodedB64 = forge.util.decode64(encodedB64);
encrypted.data = decodedB64;

var decipher = forge.cipher.createDecipher('AES-CBC', key);
decipher.start({iv: iv});
decipher.update(encrypted);
var result = decipher.finish(); 

console.log("Decoded: " + decipher.output.data);

运行上面的代码,输出应为:

Plain Text: SS18617710213463
Encoded: HCzZD7uc13fqfM6odWcXf/mdR4aNJfkMDhEbnU+asjE=
Decoded: SS18617710213463

兼容的Java代码将以以下方式运行:

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

public class Main {

    static String PLAIN_TEXT = "SS18617710213463"; 
    static String ENCRYPTION_KEY = "mykey@91mykey@91";
    static String INITIALIZATIO_VECTOR = "AODVNUASDNVVAOVF";

    public static void main(String [] args) {
        try {

            System.out.println("Plain text: " + PLAIN_TEXT);

            byte[] encryptedMsg = encrypt(PLAIN_TEXT, ENCRYPTION_KEY);
            String base64Encrypted = Base64.getEncoder().encodeToString(encryptedMsg);
            System.out.println("Encrypted: "+  base64Encrypted);

            byte[] base64Decrypted = Base64.getDecoder().decode(base64Encrypted);
            String decryptedMsg = decrypt(base64Decrypted, ENCRYPTION_KEY);
            System.out.println("Decrypted: " + decryptedMsg);
        } catch (Exception e) { 
            e.printStackTrace();
        } 
    }

    public static byte[] encrypt(String plainText, String encryptionKey) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/pkcs5padding", "SunJCE");
        SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
        cipher.init(Cipher.ENCRYPT_MODE, key,new IvParameterSpec(INITIALIZATIO_VECTOR.getBytes("UTF-8")));
        return cipher.doFinal(plainText.getBytes("UTF-8"));
      }

      public static String decrypt(byte[] cipherText, String encryptionKey) throws Exception{
        Cipher cipher = Cipher.getInstance("AES/CBC/pkcs5padding", "SunJCE");
        SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
        cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(INITIALIZATIO_VECTOR.getBytes("UTF-8")));
        return new String(cipher.doFinal(cipherText),"UTF-8");
      }
}

哪个会产生:

Plain text: SS18617710213463
Encrypted: HCzZD7uc13fqfM6odWcXf/mdR4aNJfkMDhEbnU+asjE=
Decrypted: SS18617710213463