【问题标题】:Encrypt payload using a key and iv by AES/GCM/NoPadding algorithm in node js and decrypt in java在节点 js 中使用密钥和 iv 通过 AES/GCM/NoPadding 算法加密有效负载并在 java 中解密
【发布时间】:2019-12-27 22:26:43
【问题描述】:

我已使用 node.js 加密文件并在 JAVA 中解密。解密是在 JAVA 中使用“AES/GCM/Nopadding”算法完成的,它是第三方应用程序,因此我看不到 JAVA 代码。 我正在使用“aes-128-gcm”算法加密 node.js 中的有效负载。 为此,我正在尝试模仿一个有效的 java 加密代码

我已经尝试过加密和节点锻造。 我正在获取输出,但在提交有效负载时收到错误“加密错误 - 有效负载未正确加密”。

请帮我找出我在这段代码中做错了什么。

java 中的工作代码

public void encrypt(@NonNull final byte[] payload, @NonNull final byte[] key) throws GeneralSecurityException
{
    SecretKeySpec codingKey = new SecretKeySpec(key, AES);
    Cipher cipher = AEC_GCM_THREAD_CIPHER.get();
    byte[] iv = new byte[cipher.getBlockSize()];
    RANDOM.nextBytes(iv);

    cipher.init(Cipher.ENCRYPT_MODE, codingKey, new IvParameterSpec(iv));
    final byte[] encryptedPayload = cipher.doFinal(payload);
    byte[] encryptMerchantKey = encryptMerchantKey(key);

    String payloadFinal = encodeToUrlString(encryptedPayload);    // final payload
    String ivFinal =  encodeToUrlString(iv);                  // final iv
    String keyFinal =  encodeToUrlString(encryptMerchantKey);  // final key

    System.out.println("Payload");
    System.out.println(payloadFinal);
    System.out.println("iv");
    System.out.println(ivFinal);
    System.out.println("key");
    System.out.println(keyFinal);
}

我在节点 js 中尝试过的代码

function encrypt(payload) {

    let key = forge.random.getBytesSync(16);
    let iv = forge.random.getBytesSync(16);

    let cipher = forge.cipher.createCipher("AES-GCM", key);
    cipher.start({ iv: iv});
    cipher.update(forge.util.createBuffer(payload));
    cipher.finish();

    let encrypted = forge.util.encode64(cipher.output.getBytes());
    let tag = forge.util.encode64(cipher.mode.tag.getBytes());
    let iv64 = forge.util.encode64(iv);

    let encryptedPayload = encrypted+tag;

    //RSA Encryption
    encryptedkey = RSAencrypt(forge.util.encode64(key));

     return {
     "payload" : base64url.fromBase64(encryptedPayload) ,
     "iv" : base64url.fromBase64(iv64).length,
     "key" : base64url.fromBase64(encryptedkey)
     };
}

Rsa 描述工作正常,能够解密密钥。 aes加密的一些问题。如代码所示,我将身份验证标签和加密数据一起添加但没有用。

【问题讨论】:

  • toeknToUrlString 是做什么的?为什么您转换为 base 64 只是为了在您的 NodeJS 代码中再次对其进行解码?请注意,GCM 的 nonce (IV) 默认大小为 12 字节,而不是 16,因此与块大小不同(但 16 字节的 nonce 应该完全兼容)。请要求接受方的规范,不要让自己猜测它们!
  • 您还应该发布输出,不要让我们自己生成。您的 Java 显然添加了输出语句,那么它在哪里,为什么您的 NodeJS 没有相同类型的调试语句?
  • “错误加密 - 有效负载未正确加密”,提交有效负载时。
  • 那不是函数的输出,那是您提交它的一方的结果(而且由于我们甚至不知道您如何提交数据,我们甚至无法判断该错误是否是在您向我们展示的函数中生成)。
  • 因为您甚至没有表现出(学习)如何调试自己的代码的丝毫倾向,例如比较函数的输出,我想我们在这里帮不了你。这不是一个完整且可验证的最小示例,因为它不完整并且缺少输入/输出以及作为输入和输出的要求。

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


【解决方案1】:

问题在于 forge 缓冲区需要转换为节点缓冲区 这段代码现在可以工作了。谢谢@Maarten Bodewes 的建议。

function encrypt(payload) {

    //initialize forge random buffer
    var key = forge.random.getBytesSync(16);
    var iv = forge.random.getBytesSync(16);

    let cipher = forge.cipher.createCipher("AES-GCM", key);
    cipher.start({iv : iv});
    cipher.update(forge.util.createBuffer(payload));
    cipher.finish();

    let encrypted = cipher.output.data;
    let tag = cipher.mode.tag.data;
    let encryptedLoad = encrypted+tag;

    // node buffer and forge buffer differ, so the forge buffer must be converted to node Buffer            
    iv = Buffer.from(iv, "binary");
    encryptedLoad = Buffer.from(encryptedLoad, "binary");

    //Calling RSA Encryption
    encryptedKey = RSAencrypt(key);

    return {
     "payload" : base64url(encryptedLoad) ,
     "iv" : base64url(iv),
     "key" : base64url.fromBase64(encryptedKey)
     };
}

【讨论】:

  • 你能分享一下java部分来解码吗?
【解决方案2】:

我有完整的 Angular 和 Java 加密和解密示例,您可以照原样使用这个示例并根据您的需要进行更改。
使用命令“npm install node-forge”安装 node-forge。

encrypt(msg, pass) {
    const key = CryptoJS.lib.WordArray.random(8).toString();
    const iv =  CryptoJS.lib.WordArray.random(8).toString();

    // encrypt some bytes using GCM mode
    const cipher = forge.cipher.createCipher('AES-GCM', key);
    cipher.start({
        iv: iv, 
         additionalData: 'nvn', // optional
         tagLength: 128 // optional, defaults to 128 bits
    }); 
    cipher.update(forge.util.createBuffer(msg));
    cipher.finish();
    const encrypted = cipher.output;
    const encodedB64 = forge.util.encode64(encrypted.data);
    const tag = cipher.mode.tag; 
    const tagB64 = forge.util.encode64(tag.data);
    // outputs encrypted hex

    const trasmitmsg = key+iv+tagB64+encodedB64;
    return trasmitmsg
}

我使用 CryptoJS 生成随机字符串,因为 node-forge 的随机给出不可转移的字符串。

解密这个trasmitmsg的java代码是

public String getDecrypt(String transmsg) throws Exception {
    String keyString = transmsg.substring(0, 16);
    String ivString = transmsg.substring(16, 32);
    String additionalString = transmsg.substring(32, 56);
    String cipherString = transmsg.substring(56);

    byte[] keyBytes = keyString.getBytes();
    SecretKey key = new SecretKeySpec(keyBytes, "AES");
    byte[] ivBytes = ivString.getBytes();

    byte[] one = Base64.getDecoder().decode(cipherString);
    byte[] two = Base64.getDecoder().decode(additionalString);
    byte[] cipherText = ArrayUtils.addAll(one, two);
    return decrypt(cipherText, key, ivBytes);
}

public static String decrypt(byte[] cipherText, SecretKey key, byte[] IV) throws Exception {
    // Get Cipher Instance
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

    // Create SecretKeySpec
    SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "AES");

    // Create GCMParameterSpec
    GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH , IV);

    // Initialize Cipher for DECRYPT_MODE
    cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);

    cipher.updateAAD("nvn".getBytes());
    byte[] decryptedText = cipher.doFinal(cipherText);

    return new String(decryptedText);
}

干杯!!!

【讨论】:

  • 你没有使用 pass 参数来加密 oO - 你碰巧在 js 中也有解密吗?
  • @jonathanHeindl 你明白了吗?他在发送数据时没有使用 pass 或“key”。有人可以确认吗?
  • 在我的情况下,通行证是进入密钥的内容,我必须做一些散列才能获得真正的密钥: var key = forge.pkcs5.pbkdf2(secret, salt, 65536, 32, 'sha256' );
猜你喜欢
  • 2019-05-30
  • 2021-09-30
  • 1970-01-01
  • 2016-11-14
  • 2018-03-07
  • 1970-01-01
  • 2021-09-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多