I am trying to perform encryption/decryption using AES/EAX/NoPadding. Since EAX doesn't appear to be available without BouncyCastle, BC has been added as a provider.
When I try to encrypt "Hello World!", it appears to have encrypted successfully.
@NotNull
@Override
public byte[] encrypt(@NotNull Key key, @NotNull byte[] plain, @Nullable byte[] authentication) throws CryptoException {
try {
final AesEaxKey aesEaxKey = (AesEaxKey) key;
final Cipher cipher = Cipher.getInstance(getCipherAlgorithm(), BouncyCastleProvider.PROVIDER_NAME);
final byte[] cipherText = new byte[getIvSize(aesEaxKey) + plain.length + getTagSize()];
final byte[] iv = randomIv(aesEaxKey);
System.arraycopy(iv, 0, cipherText, 0, getIvSize(aesEaxKey));
cipher.init(Cipher.ENCRYPT_MODE, aesEaxKey, getParameterSpec(iv));
if (authentication != null && authentication.length != 0) {
cipher.updateAAD(authentication);
}
cipher.doFinal(plain, 0, plain.length, cipherText, getIvSize(aesEaxKey));
return cipherText;
} catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidAlgorithmParameterException | NoSuchProviderException |
InvalidKeyException | BadPaddingException | IllegalBlockSizeException | ShortBufferException e) {
throw new CryptoException(e.getMessage(), e);
}
}
When I try to decrypt the ciphertext, it throws "Mac check in EAX failed".
@NotNull
@Override
public byte[] decrypt(@NotNull Key key, @NotNull byte[] cipherText, @Nullable byte[] authentication) throws CryptoException {
try {
final AesEaxKey aesEaxKey = (AesEaxKey) key;
final Cipher cipher = Cipher.getInstance(getCipherAlgorithm(), BouncyCastleProvider.PROVIDER_NAME);
cipher.init(Cipher.DECRYPT_MODE, aesEaxKey, getParameterSpec(cipherText, 0, getIvSize(aesEaxKey)));
if (authentication != null && authentication.length != 0) {
cipher.updateAAD(authentication);
}
return cipher.doFinal(cipherText, getIvSize(aesEaxKey), cipherText.length - getIvSize(aesEaxKey));
} catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException | NoSuchProviderException |
InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
throw new CryptoException(e.getMessage(), e);
}
}
Details:
I have an implementation of AES/GCM/NoPadding that uses this same exact code which works perfectly.
What am I doing wrong?
AEAD modes such as EAX require a more complicated AlgorithmParameterSpec because both the nonce (aka IV) and the tag length in bits must be specified. Java since 1.7 has provided a GCMParameterSpec for GCM ciphers. The same data is needed for EAX mode, and apparently the Bouncycastle provider will use a GCMParameterSpec for EAX mode as well.
Note that, for the GCMParameterSpec, the tag length is specified in bits, while for the purposes of sizing arrays the tag length needs to be specified in bytes.