Skip to content

Commit 7344d35

Browse files
Merge pull request #71 from slyubomirsky/keyblob-parse-exception
Keyblob should parse field lengths as unsigned shorts
2 parents d8e8760 + 7b4b616 commit 7344d35

File tree

2 files changed

+73
-25
lines changed

2 files changed

+73
-25
lines changed

src/main/java/com/amazonaws/encryptionsdk/model/KeyBlob.java

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.amazonaws.encryptionsdk.EncryptedDataKey;
2121
import com.amazonaws.encryptionsdk.exception.AwsCryptoException;
2222
import com.amazonaws.encryptionsdk.exception.ParseException;
23+
import com.amazonaws.encryptionsdk.internal.Constants;
2324
import com.amazonaws.encryptionsdk.internal.PrimitivesParser;
2425

2526
/**
@@ -41,11 +42,11 @@
4142
* </ol>
4243
*/
4344
public final class KeyBlob implements EncryptedDataKey {
44-
private short keyProviderIdLen_ = -1;
45+
private int keyProviderIdLen_ = -1;
4546
private byte[] keyProviderId_;
46-
private short keyProviderInfoLen_ = -1;
47+
private int keyProviderInfoLen_ = -1;
4748
private byte[] keyProviderInfo_;
48-
private short encryptedKeyLen_ = -1;
49+
private int encryptedKeyLen_ = -1;
4950
private byte[] encryptedKey_;
5051

5152
private boolean isComplete_ = false;
@@ -77,6 +78,7 @@ public KeyBlob(final EncryptedDataKey edk) {
7778
setKeyProviderId(edk.getProviderId());
7879
setKeyProviderInfo(edk.getProviderInformation());
7980
}
81+
8082
/**
8183
* Parse the key provider identifier length in the provided bytes. It looks
8284
* for 2 bytes representing a short primitive type in the provided bytes
@@ -98,7 +100,7 @@ public KeyBlob(final EncryptedDataKey edk) {
98100
* length.
99101
*/
100102
private int parseKeyProviderIdLen(final byte[] b, final int off) throws ParseException {
101-
keyProviderIdLen_ = PrimitivesParser.parseShort(b, off);
103+
keyProviderIdLen_ = PrimitivesParser.parseUnsignedShort(b, off);
102104
return Short.SIZE / Byte.SIZE;
103105
}
104106

@@ -152,7 +154,7 @@ private int parseKeyProviderId(final byte[] b, final int off) throws ParseExcept
152154
* length.
153155
*/
154156
private int parseKeyProviderInfoLen(final byte[] b, final int off) throws ParseException {
155-
keyProviderInfoLen_ = PrimitivesParser.parseShort(b, off);
157+
keyProviderInfoLen_ = PrimitivesParser.parseUnsignedShort(b, off);
156158
return Short.SIZE / Byte.SIZE;
157159
}
158160

@@ -205,7 +207,7 @@ private int parseKeyProviderInfo(final byte[] b, final int off) throws ParseExce
205207
* if there are not sufficient bytes to parse the key length.
206208
*/
207209
private int parseKeyLen(final byte[] b, final int off) throws ParseException {
208-
encryptedKeyLen_ = PrimitivesParser.parseShort(b, off);
210+
encryptedKeyLen_ = PrimitivesParser.parseUnsignedShort(b, off);
209211
return Short.SIZE / Byte.SIZE;
210212
}
211213

@@ -302,13 +304,13 @@ public byte[] toByteArray() {
302304
final int outLen = 3 * (Short.SIZE / Byte.SIZE) + keyProviderIdLen_ + keyProviderInfoLen_ + encryptedKeyLen_;
303305
final ByteBuffer out = ByteBuffer.allocate(outLen);
304306

305-
out.putShort(keyProviderIdLen_);
307+
out.putShort((short) keyProviderIdLen_);
306308
out.put(keyProviderId_, 0, keyProviderIdLen_);
307309

308-
out.putShort(keyProviderInfoLen_);
310+
out.putShort((short) keyProviderInfoLen_);
309311
out.put(keyProviderInfo_, 0, keyProviderInfoLen_);
310312

311-
out.putShort(encryptedKeyLen_);
313+
out.putShort((short) encryptedKeyLen_);
312314
out.put(encryptedKey_, 0, encryptedKeyLen_);
313315

314316
return out.array();
@@ -332,7 +334,7 @@ public boolean isComplete() {
332334
* @return
333335
* the length of the key provider identifier.
334336
*/
335-
public short getKeyProviderIdLen() {
337+
public int getKeyProviderIdLen() {
336338
return keyProviderIdLen_;
337339
}
338340

@@ -353,7 +355,7 @@ public String getProviderId() {
353355
* @return
354356
* the length of the key provider info.
355357
*/
356-
public short getKeyProviderInfoLen() {
358+
public int getKeyProviderInfoLen() {
357359
return keyProviderInfoLen_;
358360
}
359361

@@ -374,7 +376,7 @@ public byte[] getProviderInformation() {
374376
* @return
375377
* the length of the encrypted data key.
376378
*/
377-
public short getEncryptedDataKeyLen() {
379+
public int getEncryptedDataKeyLen() {
378380
return encryptedKeyLen_;
379381
}
380382

@@ -397,12 +399,12 @@ public byte[] getEncryptedDataKey() {
397399
*/
398400
public void setKeyProviderId(final String keyProviderId) {
399401
final byte[] keyProviderIdBytes = keyProviderId.getBytes(StandardCharsets.UTF_8);
400-
if (keyProviderIdBytes.length > Short.MAX_VALUE) {
402+
if (keyProviderIdBytes.length > Constants.UNSIGNED_SHORT_MAX_VAL) {
401403
throw new AwsCryptoException(
402-
"Key provider identifier length exceeds the max value of a short primitive.");
404+
"Key provider identifier length exceeds the max value of an unsigned short primitive.");
403405
}
404406
keyProviderId_ = keyProviderIdBytes;
405-
keyProviderIdLen_ = (short) keyProviderId_.length;
407+
keyProviderIdLen_ = keyProviderId_.length;
406408
}
407409

408410
/**
@@ -413,12 +415,12 @@ public void setKeyProviderId(final String keyProviderId) {
413415
* identifier.
414416
*/
415417
public void setKeyProviderInfo(final byte[] keyProviderInfo) {
416-
if (keyProviderInfo.length > Short.MAX_VALUE) {
418+
if (keyProviderInfo.length > Constants.UNSIGNED_SHORT_MAX_VAL) {
417419
throw new AwsCryptoException(
418-
"Key provider identifier information length exceeds the max value of a short primitive.");
420+
"Key provider identifier information length exceeds the max value of an unsigned short primitive.");
419421
}
420422
keyProviderInfo_ = keyProviderInfo.clone();
421-
keyProviderInfoLen_ = (short) keyProviderInfo.length;
423+
keyProviderInfoLen_ = keyProviderInfo.length;
422424
}
423425

424426
/**
@@ -428,10 +430,10 @@ public void setKeyProviderInfo(final byte[] keyProviderInfo) {
428430
* the bytes containing the encrypted data key.
429431
*/
430432
public void setEncryptedDataKey(final byte[] encryptedDataKey) {
431-
if (encryptedDataKey.length > Short.MAX_VALUE) {
432-
throw new AwsCryptoException("Key length exceeds the max value of a short primitive.");
433+
if (encryptedDataKey.length > Constants.UNSIGNED_SHORT_MAX_VAL) {
434+
throw new AwsCryptoException("Key length exceeds the max value of an unsigned short primitive.");
433435
}
434436
encryptedKey_ = encryptedDataKey.clone();
435-
encryptedKeyLen_ = (short) encryptedKey_.length;
437+
encryptedKeyLen_ = encryptedKey_.length;
436438
}
437-
}
439+
}

src/test/java/com/amazonaws/encryptionsdk/model/KeyBlobTest.java

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import static org.junit.Assert.assertEquals;
1818

1919
import java.nio.charset.StandardCharsets;
20+
import java.util.Arrays;
2021
import java.util.HashMap;
2122
import java.util.Map;
2223

@@ -26,6 +27,7 @@
2627
import com.amazonaws.encryptionsdk.CryptoAlgorithm;
2728
import com.amazonaws.encryptionsdk.DataKey;
2829
import com.amazonaws.encryptionsdk.exception.AwsCryptoException;
30+
import com.amazonaws.encryptionsdk.internal.Constants;
2931
import com.amazonaws.encryptionsdk.internal.RandomBytesGenerator;
3032
import com.amazonaws.encryptionsdk.internal.StaticMasterKey;
3133

@@ -76,7 +78,7 @@ public void overlyLargeKeyProviderIdLen() {
7678

7779
final DataKey<StaticMasterKey> mockDataKey = masterKeyProvider_.generateDataKey(ALGORITHM, encryptionContext);
7880

79-
final int providerId_Len = Short.MAX_VALUE + 1;
81+
final int providerId_Len = Constants.UNSIGNED_SHORT_MAX_VAL + 1;
8082
final byte[] providerId_Bytes = RandomBytesGenerator.generate(providerId_Len);
8183
final String providerId_ = new String(providerId_Bytes, StandardCharsets.UTF_8);
8284

@@ -93,15 +95,15 @@ public void overlyLargeKeyProviderInfoLen() {
9395

9496
final DataKey<StaticMasterKey> mockDataKey = masterKeyProvider_.generateDataKey(ALGORITHM, encryptionContext);
9597

96-
final int providerInfo_Len = Short.MAX_VALUE + 1;
98+
final int providerInfo_Len = Constants.UNSIGNED_SHORT_MAX_VAL + 1;
9799
final byte[] providerInfo_ = RandomBytesGenerator.generate(providerInfo_Len);
98100

99101
new KeyBlob(providerId_, providerInfo_, mockDataKey.getEncryptedDataKey());
100102
}
101103

102104
@Test(expected = AwsCryptoException.class)
103105
public void overlyLargeKey() {
104-
final int keyLen = Short.MAX_VALUE + 1;
106+
final int keyLen = Constants.UNSIGNED_SHORT_MAX_VAL + 1;
105107
final byte[] encryptedKeyBytes = RandomBytesGenerator.generate(keyLen);
106108

107109
new KeyBlob(providerId_, providerInfo_.getBytes(StandardCharsets.UTF_8), encryptedKeyBytes);
@@ -170,4 +172,48 @@ public void checkKeyLen() {
170172

171173
assertEquals(mockDataKey_.getEncryptedDataKey().length, reconstructedKeyBlob.getEncryptedDataKeyLen());
172174
}
175+
176+
private KeyBlob generateRandomKeyBlob(int idLen, int infoLen, int keyLen) {
177+
final byte[] idBytes = new byte[idLen];
178+
Arrays.fill(idBytes, (byte) 'A');
179+
180+
final byte[] infoBytes = RandomBytesGenerator.generate(infoLen);
181+
final byte[] keyBytes = RandomBytesGenerator.generate(keyLen);
182+
183+
return new KeyBlob(new String(idBytes, StandardCharsets.UTF_8), infoBytes, keyBytes);
184+
}
185+
186+
private void assertKeyBlobsEqual(KeyBlob b1, KeyBlob b2) {
187+
assertArrayEquals(b1.getProviderId().getBytes(StandardCharsets.UTF_8),
188+
b2.getProviderId().getBytes(StandardCharsets.UTF_8));
189+
assertArrayEquals(b1.getProviderInformation(), b2.getProviderInformation());
190+
assertArrayEquals(b1.getEncryptedDataKey(), b2.getEncryptedDataKey());
191+
}
192+
193+
@Test
194+
public void checkKeyProviderIdLenUnsigned() {
195+
// provider id length is too large for a signed short but fits in unsigned
196+
final KeyBlob blob = generateRandomKeyBlob(Constants.UNSIGNED_SHORT_MAX_VAL, Short.MAX_VALUE, Short.MAX_VALUE);
197+
final byte[] arr = blob.toByteArray();
198+
199+
assertKeyBlobsEqual(deserialize(arr), blob);
200+
}
201+
202+
@Test
203+
public void checkKeyProviderInfoLenUnsigned() {
204+
// provider info length is too large for a signed short but fits in unsigned
205+
final KeyBlob blob = generateRandomKeyBlob(Short.MAX_VALUE, Constants.UNSIGNED_SHORT_MAX_VAL, Short.MAX_VALUE);
206+
final byte[] arr = blob.toByteArray();
207+
208+
assertKeyBlobsEqual(deserialize(arr), blob);
209+
}
210+
211+
@Test
212+
public void checkKeyLenUnsigned() {
213+
// key length is too large for a signed short but fits in unsigned
214+
final KeyBlob blob = generateRandomKeyBlob(Short.MAX_VALUE, Short.MAX_VALUE, Constants.UNSIGNED_SHORT_MAX_VAL);
215+
final byte[] arr = blob.toByteArray();
216+
217+
assertKeyBlobsEqual(deserialize(arr), blob);
218+
}
173219
}

0 commit comments

Comments
 (0)