繁体   English   中英

NodeJs 使用 pbkdf2Sync 加密并在 Java 中解密

[英]NodeJs encrypt using pbkdf2Sync and decrypt in java

我使用以下方法在 NodeJs 中加密了一些数据。 它在 Nodejs 服务器上可以很好地进行加密和解密。

加密输入 = "SIYdcYSyiWY5XUqYMrfv31sPF8DSojs1ikghMs4R"

在加密的NodeJS输出= “IRhqmwhlFUxS1Zg + Qyr2ykSkAA1cQ5gVts7RIZoULCbYMS / DVsdfTyanGAAu4HkuAZv4ynk + VBPZ6vaTH5xTONfuVRlUavF9X // 12v5et5em1ItPYdlOWkYo5IkodpAQvm5Yrm4F5xaRxRU3 + TAZzOQm / 3YQIlz74X + 3V3 / AV / K4qFebSLUMZJM9glPWo4O + ISDf76ztiN2ynLyvsivSU / qUuQEtPVEK”

encryptAES = ((text) => {
    // random initialization vector
    const iv = crypto.randomBytes(16);

    const salt = crypto.randomBytes(64);

    var masterKey = crypto.randomBytes(32);

    const key = crypto.pbkdf2Sync(masterKey, salt, 2145, 32, 'sha512');

    // AES 256 GCM Mode
    const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);

    const encrypted = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()]);

    // extract the auth tag
    const tag = cipher.getAuthTag();

    // generate output
    return Buffer.concat([salt, iv, tag, masterKey, encrypted]).toString('base64');
});

我尝试在 Java 客户端上解密它,但由于某种原因它失败了。 我很确定我没有使用正确的解密方法。 下面是我走了多远


    public String decrypt(String base64EncryptedData) throws Exception {

        byte[] decryptedData = Base64.getDecoder().decode(base64EncryptedData);

        byte[] salt =  Arrays.copyOfRange(decryptedData, 0, 64); 
        byte[] iv = Arrays.copyOfRange(decryptedData, 64, 80); 
        byte[] tag = Arrays.copyOfRange(decryptedData, 80, 96); 
        String masterKey = new String(Arrays.copyOfRange(decryptedData, 96, 128), "UTF-8"); 
        byte[] text = Arrays.copyOfRange(decryptedData, 128, decryptedData.length); ;
        GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(tag.length * 8, iv);

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
        KeySpec spec = new PBEKeySpec(masterKey.toCharArray(), salt, 2145, 32*8);
        SecretKey tmp = factory.generateSecret(spec);
        key = new SecretKeySpec(tmp.getEncoded(), "AES");
        dcipher = Cipher.getInstance("AES/GCM/NoPadding");
        dcipher.init(Cipher.DECRYPT_MODE, key, gcmParameterSpec);

        byte[] utf8 = dcipher.doFinal(text);
        return new String(utf8, "UTF8");
    }


在 Java 中我得到异常

javax.crypto.AEADBadTagException: Tag mismatch!

代码中有几个问题:

  • 最严重的是密码是和消息一起发送的。 这允许任何人解密密文。 密码必须保密,不得与消息一起发送,只有发送方和接收方知道。
  • 使用PBKDF2WithHmacSHA512在 Java 代码中派生的密钥tmpPBKDF2WithHmacSHA512的一个实例, PBKDF2KeyImpl密码存储在char[]其字符将采用 UTF8 编码(请参阅PBKDF2KeyImpl类的文档)。 然而,在 NodeJS 代码中,密码是通过使用crypto.randomBytes伪随机填充缓冲区来crypto.randomBytes 随机二进制数据通常不能在不破坏数据的情况下使用 UTF8 编码转换为字符串,这里. 为了避免这个问题,必须使用 UTF8 可编码数据或 BouncyCastle 的PKCS5S2ParametersGenerator ,它需要一个byte[] (在PBEParametersGenerator#init ),这也取决于应用 KDF 的上下文(例如从密码或来自主密钥,这里)。
  • 在 Java 中,密文和身份验证标记不是单独处理的,而是作为单个byte[] ,标记附加到密文的末尾。 在当前的 Java 代码中,身份验证标记是分开的,但不在任何地方使用(除了在GCMparameterSpec构造函数中作为其长度的参考)。
  • 另请注意有关 PBKDF2 参数的建议,尤其是有关迭代计数、 RFC8018 、第 4.1 和 4.2 节以及此处的建议

暂无
暂无

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

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