AES GCM Java BouncyCastle 解密第二次失败

问题描述 投票:0回答:1

使用以下代码行使用 BouncyCastle 进行加密和解密,以解密从基于 C 的第 3 方源接收的数据。第一次加密和解密工作正常(基于他们要求使用的第 3 方共享的初始密钥和 iv)在整个会话期间),第二次加密和解密失败..主要是因为我再次使用相同的IV,如果你注意到的话。寻找新 IV 创建的逻辑是什么,以及我应该如何将其发送给第 3 方(如果我不发送它,他们如何在不知道创建的 IV 的情况下解密)

public byte[] encrypt(byte[] plainBytes) {
        byte[] encryptedBytes = new byte[0];
        try {
            GCMBlockCipher cipher = new GCMBlockCipher(new AESFastEngine());
            AEADParameters parameters =
                    new AEADParameters(new KeyParameter(key), MacBitSize, iv);

            cipher.init(true, parameters);

            encryptedBytes = new byte[cipher.getOutputSize(plainBytes.length)];
            int retLen = cipher.processBytes
                    (plainBytes, 0, plainBytes.length, encryptedBytes, 0);
            cipher.doFinal(encryptedBytes, retLen);
        } catch (IllegalArgumentException |
                 IllegalStateException | DataLengthException |
                 InvalidCipherTextException ex) {
            System.out.println(ex.getMessage());
        }
        System.arraycopy(aad, 0, encryptedBytes, plainBytes.length, 16);
        byte[] final_encr = new byte[plainBytes.length];
        System.arraycopy(encryptedBytes, 0, final_encr, 0, plainBytes.length);
        return final_encr;
    }

    public byte[] decrypt(byte[] encryptedBytes) {
        byte[] plainBytes = new byte[0];
        try {
            GCMBlockCipher cipher = new GCMBlockCipher(new AESFastEngine());
            AEADParameters parameters =
                    new AEADParameters(new KeyParameter(key), MacBitSize, iv);

            cipher.init(false, parameters);
            cipher.processAADBytes(aad, 0, aad.length);
            plainBytes = new byte[encryptedBytes.length];
            int retLen = cipher.processBytes
                    (encryptedBytes, 0, encryptedBytes.length, plainBytes, 0);
            retLen += cipher.processBytes(aad, 0, aad.length, plainBytes, retLen);
            retLen += cipher.doFinal(plainBytes, retLen);
        } catch (IllegalArgumentException | IllegalStateException |
                 DataLengthException | InvalidCipherTextException ex) {
            System.out.println(ex.getMessage());
        }
        return plainBytes;
    }
  1. 已尝试替换 iv 的最后四位数字并逐步增加
  2. 尝试过C JNI库实现
  3. 其他库如 kalium、JCE.. 不起作用

文档中第三方提供的方法
对于对称加密/解密方法 –
加密:
初始化→

void encrypt_EVP_aes_256_cbc_init(EVP_CIPHER_CTX ** ctx, unsigned char * key,
    unsigned char * iv) {
    if (!( * ctx = EVP_CIPHER_CTX_new()))
        handleErrors();

    if (1 != EVP_EncryptInit_ex( * ctx, EVP_aes_256_gcm(), NULL, key, iv))
        handleErrors();
}

加密→

void encrypt(EVP_CIPHER_CTX * ctx, unsigned char * plaintext, int plaintext_len,
    unsigned char * ciphertext, int * ciphertext_len) {
    int len;

    if (1 != EVP_EncryptUpdate(ctx, ciphertext, & len, plaintext, plaintext_len))
        handleErrors();
    * ciphertext_len = len;
}

解密:

初始化→

void decrypt_EVP_aes_256_cbc_init(EVP_CIPHER_CTX ** ctx, unsigned char * key,
    unsigned char * iv) {
    if (!( * ctx = EVP_CIPHER_CTX_new()))
        handleErrors();

    if (1 != EVP_DecryptInit_ex( * ctx, EVP_aes_256_gcm(), NULL, key, iv))
        handleErrors();
}

解密→

int decrypt(EVP_CIPHER_CTX * ctx, unsigned char * ciphertext, int ciphertext_len,
    unsigned char * plaintext, int * plaintext_len) {
    int len;

    if (1 != EVP_DecryptUpdate(ctx, plaintext, & len, ciphertext, ciphertext_len))
        handleErrors();
    * plaintext_len = len;
}

注意 –

  • 以粗体突出显示的是 OpenSSL 库函数。
  • 明文是实际的消息缓冲区。
  • 密文是加密的消息缓冲区。
java encryption aes bouncycastle aes-gcm
1个回答
0
投票

看一下加密和解密的部分:

  • 您需要 IV 数据(GCM 为 12 字节)
  • 你需要AAD(这里接缝是16字节)
  • 您需要输入数据(明文或密文)

在加密中添加aad

System.arraycopy(aad, 0, encryptedBytes, plainBytes.length, 16);

在解密时您不使用这些数据

cipher.processAADBytes(aad, 0, aad.length);

请更新您的代码,不使用全局变量。

可能

[16 byte AAD || 12 byte IV || ciphertext]
是一个很好的加密输出吗?解密时读取aad,然后读取iv,然后执行解密。

使用inputstream和outputstream进行简单的读写。

© www.soinside.com 2019 - 2024. All rights reserved.