Skip to content

Commit 9d248fb

Browse files
Using ByteByffer instead of ByteArrayInput/OutputStreams
1 parent c6bd363 commit 9d248fb

File tree

5 files changed

+32
-42
lines changed

5 files changed

+32
-42
lines changed

src/main/java/com/amazonaws/encryptionsdk/internal/AesGcmJceKeyCipher.java

Lines changed: 21 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,10 @@
1616
import javax.crypto.Cipher;
1717
import javax.crypto.SecretKey;
1818
import javax.crypto.spec.GCMParameterSpec;
19-
import java.io.ByteArrayInputStream;
20-
import java.io.ByteArrayOutputStream;
21-
import java.io.DataInputStream;
22-
import java.io.DataOutputStream;
23-
import java.io.IOException;
19+
import java.nio.ByteBuffer;
2420
import java.security.GeneralSecurityException;
2521
import java.security.InvalidKeyException;
2622
import java.security.Key;
27-
import java.security.SecureRandom;
2823
import java.util.Map;
2924

3025
/**
@@ -34,54 +29,46 @@ class AesGcmJceKeyCipher extends JceKeyCipher {
3429
private static final int NONCE_LENGTH = 12;
3530
private static final int TAG_LENGTH = 128;
3631
private static final String TRANSFORMATION = "AES/GCM/NoPadding";
37-
private final SecureRandom rnd = new SecureRandom();
3832

3933
AesGcmJceKeyCipher(SecretKey key) {
4034
super(key, key);
4135
}
4236

4337
private static byte[] specToBytes(final GCMParameterSpec spec) {
4438
final byte[] nonce = spec.getIV();
45-
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
46-
try (final DataOutputStream dos = new DataOutputStream(baos)) {
47-
dos.writeInt(spec.getTLen());
48-
dos.writeInt(nonce.length);
49-
dos.write(nonce);
50-
dos.close();
51-
baos.close();
52-
} catch (final IOException ex) {
53-
throw new AssertionError("Impossible exception", ex);
54-
}
55-
return baos.toByteArray();
39+
final byte[] result = new byte[Integer.BYTES + Integer.BYTES + nonce.length];
40+
final ByteBuffer buffer = ByteBuffer.wrap(result);
41+
buffer.putInt(spec.getTLen());
42+
buffer.putInt(nonce.length);
43+
buffer.put(nonce);
44+
return result;
5645
}
5746

5847
private static GCMParameterSpec bytesToSpec(final byte[] data, final int offset) throws InvalidKeyException {
59-
final ByteArrayInputStream bais = new ByteArrayInputStream(data, offset, data.length - offset);
60-
try (final DataInputStream dis = new DataInputStream(bais)) {
61-
final int tagLen = dis.readInt();
62-
final int nonceLen = dis.readInt();
48+
final ByteBuffer buffer = ByteBuffer.wrap(data, offset, data.length - offset);
6349

64-
if (tagLen != TAG_LENGTH) {
65-
throw new InvalidKeyException(String.format("Authentication tag length must be %s", TAG_LENGTH));
66-
}
50+
final int tagLen = buffer.getInt();
51+
final int nonceLen = buffer.getInt();
6752

68-
if (nonceLen != NONCE_LENGTH) {
69-
throw new InvalidKeyException(String.format("Initialization vector (IV) length must be %s", NONCE_LENGTH));
70-
}
53+
if (tagLen != TAG_LENGTH) {
54+
throw new InvalidKeyException(String.format("Authentication tag length must be %s", TAG_LENGTH));
55+
}
7156

72-
final byte[] nonce = new byte[nonceLen];
73-
dis.readFully(nonce);
74-
return new GCMParameterSpec(tagLen, nonce);
75-
} catch (final IOException ex) {
76-
throw new AssertionError("Impossible exception", ex);
57+
if (nonceLen != NONCE_LENGTH || buffer.remaining() != NONCE_LENGTH) {
58+
throw new InvalidKeyException(String.format("Initialization vector (IV) length must be %s", NONCE_LENGTH));
7759
}
60+
61+
final byte[] nonce = new byte[nonceLen];
62+
buffer.get(nonce);
63+
64+
return new GCMParameterSpec(tagLen, nonce);
7865
}
7966

8067
@Override
8168
WrappingData buildWrappingCipher(final Key key, final Map<String, String> encryptionContext)
8269
throws GeneralSecurityException {
8370
final byte[] nonce = new byte[NONCE_LENGTH];
84-
rnd.nextBytes(nonce);
71+
Utils.getSecureRandom().nextBytes(nonce);
8572
final GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH, nonce);
8673
final Cipher cipher = Cipher.getInstance(TRANSFORMATION);
8774
cipher.init(Cipher.ENCRYPT_MODE, key, spec);

src/main/java/com/amazonaws/encryptionsdk/internal/JceKeyCipher.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,14 @@ public EncryptedDataKey encryptKey(final byte[] key, final String keyName, final
9090
final Cipher cipher = wData.cipher;
9191
final byte[] encryptedKey = cipher.doFinal(key);
9292

93-
final byte[] provInfo = new byte[keyNameBytes.length + wData.extraInfo.length];
94-
System.arraycopy(keyNameBytes, 0, provInfo, 0, keyNameBytes.length);
95-
System.arraycopy(wData.extraInfo, 0, provInfo, keyNameBytes.length, wData.extraInfo.length);
93+
final byte[] provInfo;
94+
if (wData.extraInfo.length == 0) {
95+
provInfo = keyNameBytes;
96+
} else {
97+
provInfo = new byte[keyNameBytes.length + wData.extraInfo.length];
98+
System.arraycopy(keyNameBytes, 0, provInfo, 0, keyNameBytes.length);
99+
System.arraycopy(wData.extraInfo, 0, provInfo, keyNameBytes.length, wData.extraInfo.length);
100+
}
96101

97102
return new KeyBlob(keyNamespace, provInfo, encryptedKey);
98103
} catch (final GeneralSecurityException gsex) {

src/main/java/com/amazonaws/encryptionsdk/internal/RsaJceKeyCipher.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,7 @@ Cipher buildUnwrappingCipher(Key key, byte[] extraInfo, int offset, Map<String,
101101
if (extraInfo.length != offset) {
102102
throw new IllegalArgumentException("Extra info must be empty for RSA keys");
103103
}
104-
// We require BouncyCastle to avoid some bugs in the default Java implementation
105-
// of OAEP.
104+
106105
final Cipher cipher = Cipher.getInstance(transformation_);
107106
cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec_);
108107
return cipher;

src/main/java/com/amazonaws/encryptionsdk/internal/Utils.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ public static byte[] bigIntegerToByteArray(final BigInteger bigInteger, final in
314314

315315
/**
316316
* Returns true if the prefix of the given length for the input arrays are equal.
317+
* This method will return as soon as the first difference is found, and is thus not constant-time.
317318
*
318319
* @param a The first array.
319320
* @param b The second array.

src/main/java/com/amazonaws/encryptionsdk/jce/JceMasterKey.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import java.security.Key;
2929
import java.security.PrivateKey;
3030
import java.security.PublicKey;
31-
import java.security.SecureRandom;
3231
import java.util.ArrayList;
3332
import java.util.Collection;
3433
import java.util.List;
@@ -40,7 +39,6 @@
4039
* {@link #getInstance(PublicKey, PrivateKey, String, String, String)}.
4140
*/
4241
public class JceMasterKey extends MasterKey<JceMasterKey> {
43-
private final SecureRandom rnd = new SecureRandom();
4442
private final String providerName_;
4543
private final String keyId_;
4644
private final byte[] keyIdBytes_;
@@ -110,7 +108,7 @@ public String getKeyId() {
110108
public DataKey<JceMasterKey> generateDataKey(final CryptoAlgorithm algorithm,
111109
final Map<String, String> encryptionContext) {
112110
final byte[] rawKey = new byte[algorithm.getDataKeyLength()];
113-
rnd.nextBytes(rawKey);
111+
Utils.getSecureRandom().nextBytes(rawKey);
114112
EncryptedDataKey encryptedDataKey = jceKeyCipher_.encryptKey(rawKey, keyId_, providerName_, encryptionContext);
115113
return new DataKey<>(new SecretKeySpec(rawKey, algorithm.getDataKeyAlgo()),
116114
encryptedDataKey.getEncryptedDataKey(), encryptedDataKey.getProviderInformation(), this);

0 commit comments

Comments
 (0)