【问题标题】:NodeJs encrypt using pbkdf2Sync and decrypt in javaNodeJs 使用 pbkdf2Sync 加密并在 java 中解密
【发布时间】:2020-07-01 18:31:36
【问题描述】:

我使用下面的方法加密了 NodeJs 中的一些数据。它可以在 Nodejs 服务器上正常加密和解密。

加密输入 = "SIYdcYSyiWY5XUqYMrfv31sPF8DSojs1ikghMs4R"

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

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!

【问题讨论】:

  • 客户给出的错误是什么? PBEKeySpec 中的 512 不正确。在多平台问题中,最好提供输入和输出。
  • @kelalaka 我用加密字符串更新了它

标签: java node.js encryption aes aes-gcm


【解决方案1】:

代码有几个问题:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-08
    相关资源
    最近更新 更多