Decrypt data failed in some cases with AESNativeGCM.
On linux (run in cloud foundry) data are retrieved from AWS S3.
This can not be reproduce on Mac, as native is not supported.
Provided test reproduce what is happening.
This issue has been mitigated by forcing java implementation by adding:
Security.setProperty("org.bouncycastle.native.cpu_variant", "java");
org.bouncycastle.crypto.internal.OutputLengthException: output len too short
at org.bouncycastle.crypto.fips.AESNativeGCM.processBytes(Native Method)
at org.bouncycastle.crypto.fips.AESNativeGCM.processBytes(Unknown Source)
at org.bouncycastle.crypto.internal.io.CipherOutputStreamImpl$DirectAEADOutputStream.write(Unknown Source)
at org.bouncycastle.crypto.UpdateOutputStream.update(Unknown Source)
at org.bouncycastle.jcajce.provider.BaseCipher.engineUpdate(Unknown Source)
at java.base/javax.crypto.Cipher.update(Cipher.java:1929)
at org.bouncycastle.jcajce.io.CipherInputStream.nextChunk(Unknown Source)
at org.bouncycastle.jcajce.io.CipherInputStream.read(Unknown Source)
at java.base/java.io.InputStream.transferTo(InputStream.java:796)
- bc-fips: 2.1.2
- java: 21.0.11
- spring boot: 3.5.14
package test;
import static javax.crypto.Cipher.DECRYPT_MODE;
import static javax.crypto.Cipher.ENCRYPT_MODE;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.Provider;
import java.security.SecureRandom;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import org.bouncycastle.jcajce.io.CipherInputStream;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
import org.junit.jupiter.api.Test;
public class BcFipsTest {
static class ForceInputStream extends FilterInputStream {
private int it = 0;
public ForceInputStream(InputStream in) {
super(in);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
// Reproduce the way data are retrieved from S3
it++;
if (it == 16) {
len = 487;
} else if (it == 17) {
len = 94;
}
return super.read(b, off, len);
}
}
public static final Provider BC_PROVIDER = new BouncyCastleFipsProvider();
@Test
void forceChunk() throws Exception {
// Failed with AESNativeGCM but not GCMBlockCipher
fipsTest(16000, true);
}
@Test
void defaultChunk() throws Exception {
fipsTest(16000, false);
}
void fipsTest(
int size,
boolean force) throws Exception {
byte[] salt = generateRandom(12);
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
SecretKey key = keyGenerator.generateKey();
byte[] data = generateRandom(size);
byte[] encryptedData = encrypt(salt, key, data);
Cipher cipher = getCipher(salt, key, DECRYPT_MODE);
try (
InputStream bis = new ByteArrayInputStream(encryptedData);
InputStream fis = force ? new ForceInputStream(bis) : bis;
InputStream is = new CipherInputStream(fis, cipher)) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
is.transferTo(os);
byte[] decryptedData = os.toByteArray();
assertTrue(Arrays.equals(data, decryptedData));
}
}
private static byte[] encrypt(byte[] salt, SecretKey key, byte[] data) throws Exception {
Cipher cipher = getCipher(salt, key, ENCRYPT_MODE);
return cipher.doFinal(data);
}
private static Cipher getCipher(byte[] salt, SecretKey key, int opmode) throws Exception {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", BC_PROVIDER);
cipher.init(
opmode,
key,
new GCMParameterSpec(128, salt));
return cipher;
}
public static byte[] generateRandom(int length) throws Exception {
byte[] randomBytes = new byte[length];
SecureRandom random = SecureRandom.getInstanceStrong();
random.nextBytes(randomBytes);
return randomBytes;
}
}
Decrypt data failed in some cases with AESNativeGCM.
On linux (run in cloud foundry) data are retrieved from AWS S3.
This can not be reproduce on Mac, as native is not supported.
Provided test reproduce what is happening.
This issue has been mitigated by forcing java implementation by adding: