use of org.bouncycastle.crypto.modes.GCMBlockCipher in project nem2-sdk-java by nemtech.
the class AESGCM method createAESGCMCipher.
/**
* Creates a new AES/GCM/NoPadding cipher.
*
* @param secretKey The AES key. Must not be {@code null}.
* @param forEncryption If {@code true} creates an encryption cipher, else creates a decryption
* cipher.
* @param iv The initialisation vector (IV). Must not be {@code null}.
* @return The AES/GCM/NoPadding cipher.
*/
private static GCMBlockCipher createAESGCMCipher(final byte[] secretKey, final boolean forEncryption, final byte[] iv) {
// Initialise AES cipher
BlockCipher cipher = createCipher(secretKey, forEncryption);
// Create GCM cipher with AES
GCMBlockCipher gcm = new GCMBlockCipher(cipher);
final KeyParameter keyParam = new KeyParameter(secretKey);
final CipherParameters params = new ParametersWithIV(keyParam, iv);
gcm.init(forEncryption, params);
return gcm;
}
use of org.bouncycastle.crypto.modes.GCMBlockCipher in project nem2-sdk-java by nemtech.
the class AESGCM method encrypt.
/**
* Encrypts the specified plain text using AES/GCM/NoPadding.
*
* @param secretKey The AES key. Must not be {@code null}.
* @param plainText The plain text. Must not be {@code null}.
* @param iv The initialisation vector (IV). Must not be {@code null}.
* @return The authenticated cipher text.
* @throws CryptoException If encryption failed.
*/
public static AuthenticatedCipherText encrypt(final byte[] secretKey, final byte[] iv, final byte[] plainText) throws RuntimeException {
// Initialise AES/GCM cipher for encryption
GCMBlockCipher cipher = createAESGCMCipher(secretKey, true, iv);
// Prepare output buffer
int outputLength = cipher.getOutputSize(plainText.length);
byte[] output = new byte[outputLength];
// Produce cipher text
int outputOffset = cipher.processBytes(plainText, 0, plainText.length, output, 0);
// Produce authentication tag
try {
outputOffset += cipher.doFinal(output, outputOffset);
} catch (InvalidCipherTextException e) {
throw new CryptoException("Could Not Generate GCM Authentication: " + ExceptionUtils.getMessage(e), e);
}
// Split output into cipher text and authentication tag
int authTagLength = AUTH_TAG_BIT_LENGTH / 8;
byte[] cipherText = new byte[outputOffset - authTagLength];
byte[] authTag = new byte[authTagLength];
System.arraycopy(output, 0, cipherText, 0, cipherText.length);
System.arraycopy(output, outputOffset - authTagLength, authTag, 0, authTag.length);
return new AuthenticatedCipherText(cipherText, authTag, iv);
}
use of org.bouncycastle.crypto.modes.GCMBlockCipher in project nem2-sdk-java by nemtech.
the class AESGCM method decrypt.
/**
* Decrypts the specified cipher text using AES/GCM/NoPadding.
*
* @param secretKey The AES key. Must not be {@code null}.
* @param iv The initialisation vector (IV). Must not be {@code null}.
* @param cipherText The cipher text. Must not be {@code null}.
* @param authTag The authentication tag. Must not be {@code null}.
* @return The decrypted plain text.
* @throws CryptoException If decryption failed.
*/
public static byte[] decrypt(final byte[] secretKey, final byte[] iv, final byte[] cipherText, final byte[] authTag) throws RuntimeException {
// Initialise AES/GCM cipher for decryption
GCMBlockCipher cipher = createAESGCMCipher(secretKey, false, iv);
// Join cipher text and authentication tag to produce cipher input
byte[] input = new byte[cipherText.length + authTag.length];
System.arraycopy(cipherText, 0, input, 0, cipherText.length);
System.arraycopy(authTag, 0, input, cipherText.length, authTag.length);
int outputLength = cipher.getOutputSize(input.length);
byte[] output = new byte[outputLength];
// Decrypt
int outputOffset = cipher.processBytes(input, 0, input.length, output, 0);
// Validate authentication tag
try {
outputOffset += cipher.doFinal(output, outputOffset);
} catch (InvalidCipherTextException e) {
throw new CryptoException("Could decrypt value: " + ExceptionUtils.getMessage(e), e);
}
return output;
}
use of org.bouncycastle.crypto.modes.GCMBlockCipher in project syncany by syncany.
the class AesGcmWithBcInputStreamTest method testE_BouncyCastleCipherInputStreamWithAesGcmLongPlaintext.
@Test
public void testE_BouncyCastleCipherInputStreamWithAesGcmLongPlaintext() throws InvalidKeyException, InvalidAlgorithmParameterException, IOException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException {
// Encrypt (not interesting in this example)
byte[] randomKey = createRandomArray(16);
byte[] randomIv = createRandomArray(16);
// <<<< 4080 bytes fails, 4079 bytes works!
byte[] originalPlaintext = createRandomArray(4080);
byte[] originalCiphertext = encryptWithAesGcm(originalPlaintext, randomKey, randomIv);
// Decrypt with BouncyCastle implementation of CipherInputStream
AEADBlockCipher cipher = new GCMBlockCipher(new AESEngine());
cipher.init(false, new AEADParameters(new KeyParameter(randomKey), 128, randomIv));
try {
readFromStream(new org.bouncycastle.crypto.io.CipherInputStream(new ByteArrayInputStream(originalCiphertext), cipher));
// ^^^^^^^^^^^^^^^ INTERESTING PART ^^^^^^^^^^^^^^^^
//
// In this example, the BouncyCastle implementation of the CipherInputStream throws an ArrayIndexOutOfBoundsException.
// The only difference to the example above is that the plaintext is now 4080 bytes long! For 4079 bytes plaintexts,
// everything works just fine.
System.out.println("Test E: org.bouncycastle.crypto.io.CipherInputStream: OK, throws no exception");
} catch (IOException e) {
fail("Test E: org.bouncycastle.crypto.io.CipherInputStream: NOT OK throws: " + e.getMessage());
}
}
use of org.bouncycastle.crypto.modes.GCMBlockCipher in project syncany by syncany.
the class AesGcmWithBcInputStreamTest method testD_BouncyCastleCipherInputStreamWithAesGcm.
@Test
public void testD_BouncyCastleCipherInputStreamWithAesGcm() throws InvalidKeyException, InvalidAlgorithmParameterException, IOException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException {
// Encrypt (not interesting in this example)
byte[] randomKey = createRandomArray(16);
byte[] randomIv = createRandomArray(16);
byte[] originalPlaintext = "Confirm 100$ pay".getBytes("ASCII");
byte[] originalCiphertext = encryptWithAesGcm(originalPlaintext, randomKey, randomIv);
// Attack / alter ciphertext (an attacker would do this!)
byte[] alteredCiphertext = Arrays.clone(originalCiphertext);
// <<< Change 100$ to 900$
alteredCiphertext[8] = (byte) (alteredCiphertext[8] ^ 0x08);
// Decrypt with BouncyCastle implementation of CipherInputStream
AEADBlockCipher cipher = new GCMBlockCipher(new AESEngine());
cipher.init(false, new AEADParameters(new KeyParameter(randomKey), 128, randomIv));
try {
readFromStream(new org.bouncycastle.crypto.io.CipherInputStream(new ByteArrayInputStream(alteredCiphertext), cipher));
// ^^^^^^^^^^^^^^^ INTERESTING PART ^^^^^^^^^^^^^^^^
//
// The BouncyCastle implementation of the CipherInputStream detects MAC verification errors and
// throws a InvalidCipherTextIOException if an error occurs. Nice! A more or less minor issue
// however is that it is incompatible with the standard JCE Cipher class from the javax.crypto
// package. The new interface AEADBlockCipher must be used. The code below is not executed.
fail("Test D: org.bouncycastle.crypto.io.CipherInputStream: NOT OK, tampering not detected");
} catch (InvalidCipherTextIOException e) {
System.out.println("Test D: org.bouncycastle.crypto.io.CipherInputStream: OK, tampering detected");
}
}
Aggregations