【问题标题】:Encrypt a string in nodejs and decrypt in java在nodejs中加密字符串并在java中解密
【发布时间】:2018-07-05 15:26:41
【问题描述】:

我在 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 个字节

【问题讨论】:

  • 来自documentation:“crypto.createCipher() 的实现使用 OpenSSL 函数 EVP_BytesToKey 派生密钥,摘要算法设置为 MD5,一次迭代,无盐。缺少盐允许字典攻击因为相同的密码总是创建相同的密钥。低迭代次数和非加密安全哈希算法允许非常快速地测试密码。"

标签: node.js encryption node-crypto


【解决方案1】:

您收到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

【讨论】:

  • 我需要另一种方式——在节点中解密一些是 enc 的东西。在爪哇。花了一整天没有成功,直到 node-forge 和你的评论
猜你喜欢
  • 1970-01-01
  • 2012-07-29
  • 1970-01-01
  • 1970-01-01
  • 2019-02-07
  • 1970-01-01
  • 2020-07-01
  • 2013-11-24
  • 2016-12-25
相关资源
最近更新 更多