Suraj Putta
Suraj Putta

Reputation: 9

AES GCM Java BouncyCastle decryption fails second time

Using the below lines of code for Encrypting and Decrypting using BouncyCastle for decrypting data received from a 3rd party source based on C. First encryption and decryption works fine(basis the initial key and iv shared by the 3rd party which they have asked to use through out the session), second encryption and decryption fails.. mostly because I am using the same IV again if you notice. Looking for what might be the logic for the new IV creation and how am i supposed to send it to the 3rd party (if i do not send it, how can they decrypt without knowing the created 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. Have tried to replace the last four digits of the iv and increase it incrementally
  2. Tried C JNI library implementaion
  3. Other libraries like kalium, JCE.. didn't work

Methodology provided by third party in the doc
For symmetric encryption/decryption methodology –
Encryption:
Initialization →

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();
}

Encryption →

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;
}

Decryption:

Initialization→

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();
}

Decryption→

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;
}

Note –

Upvotes: 0

Views: 147

Answers (1)

user-8534
user-8534

Reputation: 25

Take a look at the parts of the encryption and decryption:

  • You need the IV data (12 bytes for GCM)
  • You need the AAD (seams to be 16 bytes here)
  • You need the input data (plaintext or ciphertext)

In encrypt you add the aad

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

in decrypt you do not use these data

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

Please update your code, that no global variables are used.

May [16 byte AAD || 12 byte IV || ciphertext] be a good output for encrypt for you? At decrypt read aad, then iv, then perform decryption.

Use inputstream and outputstream for simple read and write.

Upvotes: 1

Related Questions