[java-support] branch master updated: Convert GCM usage in DataSealer from BC to JCE API.
Scott Cantor
cantor.2 at osu.edu
Thu Jan 17 17:55:42 EST 2019
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch master
in repository java-support.
View the commit online:
http://git.shibboleth.net/view/?p=java-support.git;a=commit;h=afd3363643b6920cc285a3f6db4d706ae2dd75c3
The following commit(s) were added to refs/heads/master by this push:
new afd3363 Convert GCM usage in DataSealer from BC to JCE API.
afd3363 is described below
commit afd3363643b6920cc285a3f6db4d706ae2dd75c3
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Jan 17 17:55:36 2019 -0500
Convert GCM usage in DataSealer from BC to JCE API.
---
.../java/support/security/DataSealer.java | 85 +++++++++++++---------
.../java/support/security/DataSealerTest.java | 3 +-
2 files changed, 51 insertions(+), 37 deletions(-)
diff --git a/src/main/java/net/shibboleth/utilities/java/support/security/DataSealer.java b/src/main/java/net/shibboleth/utilities/java/support/security/DataSealer.java
index f90ebdd..b9543c2 100644
--- a/src/main/java/net/shibboleth/utilities/java/support/security/DataSealer.java
+++ b/src/main/java/net/shibboleth/utilities/java/support/security/DataSealer.java
@@ -24,6 +24,7 @@ import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
import java.security.KeyException;
import java.security.SecureRandom;
import java.util.zip.GZIPInputStream;
@@ -31,7 +32,9 @@ import java.util.zip.GZIPOutputStream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import javax.crypto.Cipher;
import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
@@ -46,12 +49,6 @@ import org.apache.commons.codec.BinaryDecoder;
import org.apache.commons.codec.BinaryEncoder;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
-import org.bouncycastle.crypto.InvalidCipherTextException;
-import org.bouncycastle.crypto.engines.AESEngine;
-import org.bouncycastle.crypto.modes.GCMBlockCipher;
-import org.bouncycastle.crypto.params.AEADParameters;
-import org.bouncycastle.crypto.params.KeyParameter;
-import org.bouncycastle.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -77,10 +74,16 @@ public class DataSealer extends AbstractInitializableComponent {
@NonnullAfterInit private SecureRandom random;
/** Encodes encrypted bytes to string. */
- @Nonnull private BinaryEncoder encoder = new Base64(0, new byte[] { '\n' });
+ @Nonnull private BinaryEncoder encoder;
/** Decodes encrypted string to bytes. */
- @Nonnull private BinaryDecoder decoder = (Base64) encoder;
+ @Nonnull private BinaryDecoder decoder;
+
+ /** Constructor. */
+ public DataSealer() {
+ encoder = new Base64(0, new byte[] { '\n' });
+ decoder = (Base64) encoder;
+ }
/**
* Set whether the key source is expected to be locked at startup, and unlocked
@@ -127,6 +130,8 @@ public class DataSealer extends AbstractInitializableComponent {
* @param e Byte-to-string encoder.
*/
public void setEncoder(@Nonnull final BinaryEncoder e) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
encoder = Constraint.isNotNull(e, "Encoder cannot be null");
}
@@ -136,6 +141,8 @@ public class DataSealer extends AbstractInitializableComponent {
* @param d String-to-byte decoder.
*/
public void setDecoder(@Nonnull final BinaryDecoder d) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
decoder = Constraint.isNotNull(d, "Decoder cannot be null");
}
@@ -207,31 +214,28 @@ public class DataSealer extends AbstractInitializableComponent {
}
final SecretKey key = keyStrategy.getKey(keyAlias);
- final GCMBlockCipher cipher = new GCMBlockCipher(new AESEngine());
+ final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
// Load the IV.
- final int ivSize = cipher.getUnderlyingCipher().getBlockSize();
+ final int ivSize = cipher.getBlockSize();
final byte[] iv = new byte[ivSize];
inputDataStream.readFully(iv);
-
- final AEADParameters aeadParams =
- new AEADParameters(new KeyParameter(key.getEncoded()), 128, iv, keyAlias.getBytes());
- cipher.init(false, aeadParams);
-
+
+ final GCMParameterSpec params = new GCMParameterSpec(128, iv);
+ cipher.init(Cipher.DECRYPT_MODE, key, params);
+ cipher.updateAAD(keyAlias.getBytes());
+
// Data can't be any bigger than the original minus IV.
final byte[] data = new byte[in.length - ivSize];
final int dataSize = inputDataStream.read(data);
final byte[] plaintext = new byte[cipher.getOutputSize(dataSize)];
- final int outputLen = cipher.processBytes(data, 0, dataSize, plaintext, 0);
+ final int outputLen = cipher.update(data, 0, dataSize, plaintext, 0);
cipher.doFinal(plaintext, outputLen);
// Pass the plaintext into the subroutine for processing.
return extractAndCheckDecryptedData(plaintext);
- } catch (final IllegalStateException | InvalidCipherTextException| IOException | DecoderException e) {
- log.error("Exception unwrapping data", e);
- throw new DataSealerException("Exception unwrapping data", e);
} catch (final KeyNotFoundException e) {
if (keyUsed != null) {
log.info("Data was wrapped with a key ({}) no longer available", keyUsed.toString());
@@ -242,6 +246,9 @@ public class DataSealer extends AbstractInitializableComponent {
} catch (final KeyException e) {
log.error(e.getMessage());
throw new DataSealerException("Exception loading key", e);
+ } catch (final GeneralSecurityException | IOException | DecoderException e) {
+ log.error("Exception unwrapping data", e);
+ throw new DataSealerException("Exception unwrapping data", e);
}
}
@@ -312,16 +319,16 @@ public class DataSealer extends AbstractInitializableComponent {
}
try {
- final GCMBlockCipher cipher = new GCMBlockCipher(new AESEngine());
- final byte[] iv = new byte[cipher.getUnderlyingCipher().getBlockSize()];
+ final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+
+ final byte[] iv = new byte[cipher.getBlockSize()];
random.nextBytes(iv);
+ final GCMParameterSpec params = new GCMParameterSpec(128, iv);
final Pair<String,SecretKey> defaultKey = keyStrategy.getDefaultKey();
- final AEADParameters aeadParams =
- new AEADParameters(new KeyParameter(defaultKey.getSecond().getEncoded()), 128, iv,
- defaultKey.getFirst().getBytes());
- cipher.init(true, aeadParams);
+ cipher.init(Cipher.ENCRYPT_MODE, defaultKey.getSecond(), params);
+ cipher.updateAAD(defaultKey.getFirst().getBytes());
final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
final GZIPOutputStream compressedStream = new GZIPOutputStream(byteStream);
@@ -346,7 +353,7 @@ public class DataSealer extends AbstractInitializableComponent {
final byte[] plaintext = byteStream.toByteArray();
final byte[] encryptedData = new byte[cipher.getOutputSize(plaintext.length)];
- int outputLen = cipher.processBytes(plaintext, 0, plaintext.length, encryptedData, 0);
+ int outputLen = cipher.update(plaintext, 0, plaintext.length, encryptedData, 0);
outputLen += cipher.doFinal(encryptedData, outputLen);
final ByteArrayOutputStream finalByteStream = new ByteArrayOutputStream();
@@ -381,25 +388,31 @@ public class DataSealer extends AbstractInitializableComponent {
final String decrypted;
try {
- final GCMBlockCipher cipher = new GCMBlockCipher(new AESEngine());
- final byte[] iv = new byte[cipher.getUnderlyingCipher().getBlockSize()];
+ final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+
+ final byte[] iv = new byte[cipher.getBlockSize()];
random.nextBytes(iv);
- final AEADParameters aeadParams = new AEADParameters(
- new KeyParameter(key.getEncoded()), 128, iv, "aad".getBytes(StandardCharsets.UTF_8));
+ final GCMParameterSpec params = new GCMParameterSpec(128, iv);
+
+ cipher.init(Cipher.ENCRYPT_MODE, key, params);
+ cipher.updateAAD("aad".getBytes(StandardCharsets.UTF_8));
- cipher.init(true, aeadParams);
byte[] plaintext = "test".getBytes(StandardCharsets.UTF_8);
+
final byte[] encryptedData = new byte[cipher.getOutputSize(plaintext.length)];
- int outputLen = cipher.processBytes(plaintext, 0, plaintext.length, encryptedData, 0);
+ int outputLen = cipher.update(plaintext, 0, plaintext.length, encryptedData, 0);
cipher.doFinal(encryptedData, outputLen);
- cipher.init(false, aeadParams);
+ cipher.init(Cipher.DECRYPT_MODE, key, params);
+ cipher.updateAAD("aad".getBytes(StandardCharsets.UTF_8));
+
plaintext = new byte[cipher.getOutputSize(encryptedData.length)];
- outputLen = cipher.processBytes(encryptedData, 0, encryptedData.length, plaintext, 0);
+ outputLen = cipher.update(encryptedData, 0, encryptedData.length, plaintext, 0);
cipher.doFinal(plaintext, outputLen);
- decrypted = Strings.fromUTF8ByteArray(plaintext);
- } catch (final IllegalStateException | InvalidCipherTextException e) {
+ decrypted = new String(plaintext, StandardCharsets.UTF_8);
+
+ } catch (final IllegalStateException | GeneralSecurityException e) {
log.error("Round trip encryption/decryption test unsuccessful", e);
throw new DataSealerException("Round trip encryption/decryption test unsuccessful", e);
}
diff --git a/src/test/java/net/shibboleth/utilities/java/support/security/DataSealerTest.java b/src/test/java/net/shibboleth/utilities/java/support/security/DataSealerTest.java
index 12ec22d..22af5d3 100644
--- a/src/test/java/net/shibboleth/utilities/java/support/security/DataSealerTest.java
+++ b/src/test/java/net/shibboleth/utilities/java/support/security/DataSealerTest.java
@@ -22,9 +22,10 @@ import net.shibboleth.utilities.java.support.component.ComponentInitializationEx
import net.shibboleth.utilities.java.support.resource.Resource;
import net.shibboleth.utilities.java.support.resource.TestResourceConverter;
+import java.util.Arrays;
+
import javax.annotation.Nonnull;
-import org.bouncycastle.util.Arrays;
import org.springframework.core.io.ClassPathResource;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list