Skip to content

Commit b0b6aa0

Browse files
committed
Better test coverage for user-supplied encryption keys
1 parent a262306 commit b0b6aa0

File tree

3 files changed

+142
-51
lines changed

3 files changed

+142
-51
lines changed

google-cloud-storage/src/test/java/com/google/cloud/storage/BlobTest.java

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,21 @@
4040
import com.google.cloud.storage.Storage.CopyRequest;
4141
import com.google.common.collect.ImmutableList;
4242
import com.google.common.collect.ImmutableMap;
43+
import com.google.common.io.BaseEncoding;
4344

4445
import org.easymock.Capture;
4546
import org.junit.After;
4647
import org.junit.Before;
4748
import org.junit.Test;
4849

4950
import java.net.URL;
51+
import java.security.Key;
5052
import java.util.List;
5153
import java.util.Map;
5254
import java.util.concurrent.TimeUnit;
5355

56+
import javax.crypto.spec.SecretKeySpec;
57+
5458
public class BlobTest {
5559

5660
private static final Acl ACL = Acl.of(User.ofAllAuthenticatedUsers(), Role.OWNER);
@@ -108,6 +112,9 @@ public class BlobTest {
108112
.size(0L)
109113
.isDirectory(true)
110114
.build();
115+
private static final String BASE64_KEY = "JVzfVl8NLD9FjedFuStegjRfES5ll5zc59CIXw572OA=";
116+
private static final Key KEY =
117+
new SecretKeySpec(BaseEncoding.base64().decode(BASE64_KEY), "AES256");
111118

112119
private Storage storage;
113120
private Blob blob;
@@ -168,15 +175,17 @@ public void testContent() throws Exception {
168175
}
169176

170177
@Test
171-
public void testContentWithOptions() throws Exception {
178+
public void testContentWithDecryptionKey() throws Exception {
172179
initializeExpectedBlob(2);
173180
byte[] content = {1, 2};
174181
expect(storage.options()).andReturn(mockOptions);
175-
expect(storage.readAllBytes(BLOB_INFO.blobId(), Storage.BlobSourceOption.decryptionKey("key")))
176-
.andReturn(content);
182+
expect(storage.readAllBytes(BLOB_INFO.blobId(),
183+
Storage.BlobSourceOption.decryptionKey(BASE64_KEY)))
184+
.andReturn(content).times(2);
177185
replay(storage);
178186
initializeBlob();
179-
assertArrayEquals(content, blob.content(BlobSourceOption.decryptionKey("key")));
187+
assertArrayEquals(content, blob.content(BlobSourceOption.decryptionKey(BASE64_KEY)));
188+
assertArrayEquals(content, blob.content(BlobSourceOption.decryptionKey(KEY)));
180189
}
181190

182191
@Test
@@ -310,15 +319,16 @@ public void testReader() throws Exception {
310319
}
311320

312321
@Test
313-
public void testReaderWithOptions() throws Exception {
322+
public void testReaderWithDecryptionKey() throws Exception {
314323
initializeExpectedBlob(2);
315324
ReadChannel channel = createMock(ReadChannel.class);
316325
expect(storage.options()).andReturn(mockOptions);
317-
expect(storage.reader(BLOB_INFO.blobId(), Storage.BlobSourceOption.decryptionKey("key")))
318-
.andReturn(channel);
326+
expect(storage.reader(BLOB_INFO.blobId(), Storage.BlobSourceOption.decryptionKey(BASE64_KEY)))
327+
.andReturn(channel).times(2);
319328
replay(storage);
320329
initializeBlob();
321-
assertSame(channel, blob.reader(BlobSourceOption.decryptionKey("key")));
330+
assertSame(channel, blob.reader(BlobSourceOption.decryptionKey(BASE64_KEY)));
331+
assertSame(channel, blob.reader(BlobSourceOption.decryptionKey(KEY)));
322332
}
323333

324334
@Test
@@ -333,15 +343,16 @@ public void testWriter() throws Exception {
333343
}
334344

335345
@Test
336-
public void testWriterWithOptions() throws Exception {
346+
public void testWriterWithEncryptionKey() throws Exception {
337347
initializeExpectedBlob(2);
338348
BlobWriteChannel channel = createMock(BlobWriteChannel.class);
339349
expect(storage.options()).andReturn(mockOptions);
340-
expect(storage.writer(eq(expectedBlob), eq(BlobWriteOption.encryptionKey("key"))))
341-
.andReturn(channel);
350+
expect(storage.writer(eq(expectedBlob), eq(BlobWriteOption.encryptionKey(BASE64_KEY))))
351+
.andReturn(channel).times(2);
342352
replay(storage);
343353
initializeBlob();
344-
assertSame(channel, blob.writer(BlobWriteOption.encryptionKey("key")));
354+
assertSame(channel, blob.writer(BlobWriteOption.encryptionKey(BASE64_KEY)));
355+
assertSame(channel, blob.writer(BlobWriteOption.encryptionKey(KEY)));
345356
}
346357

347358
@Test

google-cloud-storage/src/test/java/com/google/cloud/storage/BucketTest.java

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import com.google.common.base.Function;
3939
import com.google.common.collect.ImmutableList;
4040
import com.google.common.collect.Lists;
41+
import com.google.common.io.BaseEncoding;
4142

4243
import org.junit.After;
4344
import org.junit.Before;
@@ -47,10 +48,13 @@
4748

4849
import java.io.ByteArrayInputStream;
4950
import java.io.InputStream;
51+
import java.security.Key;
5052
import java.util.Collections;
5153
import java.util.Iterator;
5254
import java.util.List;
5355

56+
import javax.crypto.spec.SecretKeySpec;
57+
5458
public class BucketTest {
5559

5660
private static final Acl ACL = Acl.of(User.ofAllAuthenticatedUsers(), Role.OWNER);
@@ -91,6 +95,9 @@ public class BucketTest {
9195
.build();
9296
private static final BucketInfo BUCKET_INFO = BucketInfo.builder("b").metageneration(42L).build();
9397
private static final String CONTENT_TYPE = "text/plain";
98+
private static final String BASE64_KEY = "JVzfVl8NLD9FjedFuStegjRfES5ll5zc59CIXw572OA=";
99+
private static final Key KEY =
100+
new SecretKeySpec(BaseEncoding.base64().decode(BASE64_KEY), "AES256");
94101

95102
private Storage storage;
96103
private Storage serviceMockReturnsOptions = createMock(Storage.class);
@@ -320,14 +327,30 @@ public void testCreateWithOptions() throws Exception {
320327
expect(storage.create(info, content, Storage.BlobTargetOption.generationMatch(),
321328
Storage.BlobTargetOption.metagenerationMatch(),
322329
Storage.BlobTargetOption.predefinedAcl(acl),
323-
Storage.BlobTargetOption.encryptionKey("key"))).andReturn(expectedBlob);
330+
Storage.BlobTargetOption.encryptionKey(BASE64_KEY))).andReturn(expectedBlob);
324331
replay(storage);
325332
initializeBucket();
326333
Blob blob = bucket.create("n", content, CONTENT_TYPE,
327334
Bucket.BlobTargetOption.generationMatch(42L),
328335
Bucket.BlobTargetOption.metagenerationMatch(24L),
329336
Bucket.BlobTargetOption.predefinedAcl(acl),
330-
Bucket.BlobTargetOption.encryptionKey("key"));
337+
Bucket.BlobTargetOption.encryptionKey(BASE64_KEY));
338+
assertEquals(expectedBlob, blob);
339+
}
340+
341+
@Test
342+
public void testCreateWithEncryptionKey() throws Exception {
343+
initializeExpectedBucket(5);
344+
BlobInfo info = BlobInfo.builder(BlobId.of("b", "n")).contentType(CONTENT_TYPE).build();
345+
Blob expectedBlob = new Blob(serviceMockReturnsOptions, new BlobInfo.BuilderImpl(info));
346+
byte[] content = {0xD, 0xE, 0xA, 0xD};
347+
expect(storage.options()).andReturn(mockOptions);
348+
expect(storage.create(info, content, Storage.BlobTargetOption.encryptionKey(KEY)))
349+
.andReturn(expectedBlob);
350+
replay(storage);
351+
initializeBucket();
352+
Blob blob =
353+
bucket.create("n", content, CONTENT_TYPE, Bucket.BlobTargetOption.encryptionKey(KEY));
331354
assertEquals(expectedBlob, blob);
332355
}
333356

@@ -421,15 +444,32 @@ public void testCreateFromStreamWithOptions() throws Exception {
421444
expect(storage.create(info, streamContent, Storage.BlobWriteOption.generationMatch(),
422445
Storage.BlobWriteOption.metagenerationMatch(), Storage.BlobWriteOption.predefinedAcl(acl),
423446
Storage.BlobWriteOption.crc32cMatch(), Storage.BlobWriteOption.md5Match(),
424-
Storage.BlobWriteOption.encryptionKey("key")))
447+
Storage.BlobWriteOption.encryptionKey(BASE64_KEY)))
425448
.andReturn(expectedBlob);
426449
replay(storage);
427450
initializeBucket();
428451
Blob blob = bucket.create("n", streamContent, CONTENT_TYPE,
429452
Bucket.BlobWriteOption.generationMatch(42L),
430453
Bucket.BlobWriteOption.metagenerationMatch(24L), Bucket.BlobWriteOption.predefinedAcl(acl),
431454
Bucket.BlobWriteOption.crc32cMatch("crc"), Bucket.BlobWriteOption.md5Match("md5"),
432-
Bucket.BlobWriteOption.encryptionKey("key"));
455+
Bucket.BlobWriteOption.encryptionKey(BASE64_KEY));
456+
assertEquals(expectedBlob, blob);
457+
}
458+
459+
@Test
460+
public void testCreateFromStreamWithEncryptionKey() throws Exception {
461+
initializeExpectedBucket(5);
462+
BlobInfo info = BlobInfo.builder(BlobId.of("b", "n")).contentType(CONTENT_TYPE).build();
463+
Blob expectedBlob = new Blob(serviceMockReturnsOptions, new BlobInfo.BuilderImpl(info));
464+
byte[] content = {0xD, 0xE, 0xA, 0xD};
465+
InputStream streamContent = new ByteArrayInputStream(content);
466+
expect(storage.options()).andReturn(mockOptions);
467+
expect(storage.create(info, streamContent, Storage.BlobWriteOption.encryptionKey(KEY)))
468+
.andReturn(expectedBlob);
469+
replay(storage);
470+
initializeBucket();
471+
Blob blob =
472+
bucket.create("n", streamContent, CONTENT_TYPE, Bucket.BlobWriteOption.encryptionKey(KEY));
433473
assertEquals(expectedBlob, blob);
434474
}
435475

google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java

Lines changed: 75 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,33 @@ public void testCreateBlobWithOptions() throws IOException {
402402
assertEquals(-1, byteStream.read(streamBytes));
403403
}
404404

405+
@Test
406+
public void testCreateBlobWithEncryptionKey() throws IOException {
407+
Capture<ByteArrayInputStream> capturedStream = Capture.newInstance();
408+
EasyMock.expect(storageRpcMock.create(
409+
EasyMock.eq(BLOB_INFO1.toBuilder().md5(CONTENT_MD5).crc32c(CONTENT_CRC32C).build().toPb()),
410+
EasyMock.capture(capturedStream),
411+
EasyMock.eq(ENCRYPTION_KEY_OPTIONS)))
412+
.andReturn(BLOB_INFO1.toPb())
413+
.times(2);
414+
EasyMock.replay(storageRpcMock);
415+
initializeService();
416+
Blob blob = storage.create(BLOB_INFO1, BLOB_CONTENT, BlobTargetOption.encryptionKey(KEY));
417+
assertEquals(expectedBlob1, blob);
418+
ByteArrayInputStream byteStream = capturedStream.getValue();
419+
byte[] streamBytes = new byte[BLOB_CONTENT.length];
420+
assertEquals(BLOB_CONTENT.length, byteStream.read(streamBytes));
421+
assertArrayEquals(BLOB_CONTENT, streamBytes);
422+
assertEquals(-1, byteStream.read(streamBytes));
423+
blob = storage.create(BLOB_INFO1, BLOB_CONTENT, BlobTargetOption.encryptionKey(BASE64_KEY));
424+
assertEquals(expectedBlob1, blob);
425+
byteStream = capturedStream.getValue();
426+
streamBytes = new byte[BLOB_CONTENT.length];
427+
assertEquals(BLOB_CONTENT.length, byteStream.read(streamBytes));
428+
assertArrayEquals(BLOB_CONTENT, streamBytes);
429+
assertEquals(-1, byteStream.read(streamBytes));
430+
}
431+
405432
@Test
406433
public void testCreateBlobFromStream() {
407434
ByteArrayInputStream fileStream = new ByteArrayInputStream(BLOB_CONTENT);
@@ -416,6 +443,24 @@ public void testCreateBlobFromStream() {
416443
assertEquals(expectedBlob1, blob);
417444
}
418445

446+
@Test
447+
public void testCreateBlobFromStreamWithEncryptionKey() throws IOException {
448+
ByteArrayInputStream fileStream = new ByteArrayInputStream(BLOB_CONTENT);
449+
BlobInfo.Builder infoBuilder = BLOB_INFO1.toBuilder();
450+
BlobInfo infoWithHashes = infoBuilder.md5(CONTENT_MD5).crc32c(CONTENT_CRC32C).build();
451+
BlobInfo infoWithoutHashes = infoBuilder.md5(null).crc32c(null).build();
452+
EasyMock.expect(
453+
storageRpcMock.create(infoWithoutHashes.toPb(), fileStream, ENCRYPTION_KEY_OPTIONS))
454+
.andReturn(BLOB_INFO1.toPb()).times(2);
455+
EasyMock.replay(storageRpcMock);
456+
initializeService();
457+
Blob blob =
458+
storage.create(infoWithHashes, fileStream, BlobWriteOption.encryptionKey(BASE64_KEY));
459+
assertEquals(expectedBlob1, blob);
460+
blob = storage.create(infoWithHashes, fileStream, BlobWriteOption.encryptionKey(BASE64_KEY));
461+
assertEquals(expectedBlob1, blob);
462+
}
463+
419464
@Test
420465
public void testGetBucket() {
421466
EasyMock.expect(storageRpcMock.get(BucketInfo.of(BUCKET_NAME1).toPb(), EMPTY_RPC_OPTIONS))
@@ -933,13 +978,22 @@ public void testCopyWithEncryptionKey() {
933978
ENCRYPTION_KEY_OPTIONS, true, request.target().toPb(), ENCRYPTION_KEY_OPTIONS, null);
934979
StorageRpc.RewriteResponse rpcResponse = new StorageRpc.RewriteResponse(rpcRequest, null, 42L,
935980
false, "token", 21L);
936-
EasyMock.expect(storageRpcMock.openRewrite(rpcRequest)).andReturn(rpcResponse);
981+
EasyMock.expect(storageRpcMock.openRewrite(rpcRequest)).andReturn(rpcResponse).times(2);
937982
EasyMock.replay(storageRpcMock);
938983
initializeService();
939984
CopyWriter writer = storage.copy(request);
940985
assertEquals(42L, writer.blobSize());
941986
assertEquals(21L, writer.totalBytesCopied());
942987
assertTrue(!writer.isDone());
988+
request = Storage.CopyRequest.builder()
989+
.source(BLOB_INFO2.blobId())
990+
.sourceOptions(BlobSourceOption.decryptionKey(BASE64_KEY))
991+
.target(BLOB_INFO1, BlobTargetOption.encryptionKey(KEY))
992+
.build();
993+
writer = storage.copy(request);
994+
assertEquals(42L, writer.blobSize());
995+
assertEquals(21L, writer.totalBytesCopied());
996+
assertTrue(!writer.isDone());
943997
}
944998

945999
@Test
@@ -1012,35 +1066,41 @@ public void testReadAllBytesWithOptions() {
10121066
public void testReadAllBytesWithDecriptionKey() {
10131067
EasyMock.expect(
10141068
storageRpcMock.load(BlobId.of(BUCKET_NAME1, BLOB_NAME1).toPb(), ENCRYPTION_KEY_OPTIONS))
1015-
.andReturn(BLOB_CONTENT);
1069+
.andReturn(BLOB_CONTENT).times(2);
10161070
EasyMock.replay(storageRpcMock);
10171071
initializeService();
10181072
byte[] readBytes = storage.readAllBytes(BUCKET_NAME1, BLOB_NAME1,
10191073
BlobSourceOption.decryptionKey(KEY));
10201074
assertArrayEquals(BLOB_CONTENT, readBytes);
1075+
readBytes = storage.readAllBytes(BUCKET_NAME1, BLOB_NAME1,
1076+
BlobSourceOption.decryptionKey(BASE64_KEY));
1077+
assertArrayEquals(BLOB_CONTENT, readBytes);
10211078
}
10221079

10231080
@Test
1024-
public void testReadAllBytesWithBase64DecriptionKey() {
1081+
public void testReadAllBytesFromBlobIdWithOptions() {
10251082
EasyMock.expect(
1026-
storageRpcMock.load(BlobId.of(BUCKET_NAME1, BLOB_NAME1).toPb(), ENCRYPTION_KEY_OPTIONS))
1083+
storageRpcMock.load(BLOB_INFO1.blobId().toPb(), BLOB_SOURCE_OPTIONS))
10271084
.andReturn(BLOB_CONTENT);
10281085
EasyMock.replay(storageRpcMock);
10291086
initializeService();
1030-
byte[] readBytes = storage.readAllBytes(BUCKET_NAME1, BLOB_NAME1,
1031-
BlobSourceOption.decryptionKey(BASE64_KEY));
1087+
byte[] readBytes = storage.readAllBytes(BLOB_INFO1.blobId(),
1088+
BLOB_SOURCE_GENERATION_FROM_BLOB_ID, BLOB_SOURCE_METAGENERATION);
10321089
assertArrayEquals(BLOB_CONTENT, readBytes);
10331090
}
10341091

10351092
@Test
1036-
public void testReadAllBytesWithOptionsFromBlobId() {
1093+
public void testReadAllBytesFromBlobIdWithDecriptionKey() {
10371094
EasyMock.expect(
1038-
storageRpcMock.load(BLOB_INFO1.blobId().toPb(), BLOB_SOURCE_OPTIONS))
1039-
.andReturn(BLOB_CONTENT);
1095+
storageRpcMock.load(BLOB_INFO1.blobId().toPb(), ENCRYPTION_KEY_OPTIONS))
1096+
.andReturn(BLOB_CONTENT).times(2);
10401097
EasyMock.replay(storageRpcMock);
10411098
initializeService();
1042-
byte[] readBytes = storage.readAllBytes(BLOB_INFO1.blobId(),
1043-
BLOB_SOURCE_GENERATION_FROM_BLOB_ID, BLOB_SOURCE_METAGENERATION);
1099+
byte[] readBytes =
1100+
storage.readAllBytes(BLOB_INFO1.blobId(), BlobSourceOption.decryptionKey(KEY));
1101+
assertArrayEquals(BLOB_CONTENT, readBytes);
1102+
readBytes =
1103+
storage.readAllBytes(BLOB_INFO1.blobId(), BlobSourceOption.decryptionKey(BASE64_KEY));
10441104
assertArrayEquals(BLOB_CONTENT, readBytes);
10451105
}
10461106

@@ -1086,26 +1146,15 @@ public void testReaderWithDecryptionKey() throws IOException {
10861146
byte[] result = new byte[DEFAULT_CHUNK_SIZE];
10871147
EasyMock.expect(
10881148
storageRpcMock.read(BLOB_INFO2.toPb(), ENCRYPTION_KEY_OPTIONS, 0, DEFAULT_CHUNK_SIZE))
1089-
.andReturn(StorageRpc.Tuple.of("etag", result));
1149+
.andReturn(StorageRpc.Tuple.of("etag", result)).times(2);
10901150
EasyMock.replay(storageRpcMock);
10911151
initializeService();
10921152
ReadChannel channel =
10931153
storage.reader(BUCKET_NAME1, BLOB_NAME2, BlobSourceOption.decryptionKey(KEY));
10941154
assertNotNull(channel);
10951155
assertTrue(channel.isOpen());
10961156
channel.read(ByteBuffer.allocate(42));
1097-
}
1098-
1099-
@Test
1100-
public void testReaderWithBase64DecryptionKey() throws IOException {
1101-
byte[] result = new byte[DEFAULT_CHUNK_SIZE];
1102-
EasyMock.expect(
1103-
storageRpcMock.read(BLOB_INFO2.toPb(), ENCRYPTION_KEY_OPTIONS, 0, DEFAULT_CHUNK_SIZE))
1104-
.andReturn(StorageRpc.Tuple.of("etag", result));
1105-
EasyMock.replay(storageRpcMock);
1106-
initializeService();
1107-
ReadChannel channel =
1108-
storage.reader(BUCKET_NAME1, BLOB_NAME2, BlobSourceOption.decryptionKey(BASE64_KEY));
1157+
channel = storage.reader(BUCKET_NAME1, BLOB_NAME2, BlobSourceOption.decryptionKey(BASE64_KEY));
11091158
assertNotNull(channel);
11101159
assertTrue(channel.isOpen());
11111160
channel.read(ByteBuffer.allocate(42));
@@ -1157,22 +1206,13 @@ public void testWriterWithOptions() {
11571206
public void testWriterWithEncryptionKey() {
11581207
BlobInfo info = BLOB_INFO1.toBuilder().md5(null).crc32c(null).build();
11591208
EasyMock.expect(storageRpcMock.open(info.toPb(), ENCRYPTION_KEY_OPTIONS))
1160-
.andReturn("upload-id");
1209+
.andReturn("upload-id").times(2);
11611210
EasyMock.replay(storageRpcMock);
11621211
initializeService();
11631212
WriteChannel channel = storage.writer(info, BlobWriteOption.encryptionKey(KEY));
11641213
assertNotNull(channel);
11651214
assertTrue(channel.isOpen());
1166-
}
1167-
1168-
@Test
1169-
public void testWriterWithBase64EncryptionKey() {
1170-
BlobInfo info = BLOB_INFO1.toBuilder().md5(null).crc32c(null).build();
1171-
EasyMock.expect(storageRpcMock.open(info.toPb(), ENCRYPTION_KEY_OPTIONS))
1172-
.andReturn("upload-id");
1173-
EasyMock.replay(storageRpcMock);
1174-
initializeService();
1175-
WriteChannel channel = storage.writer(info, BlobWriteOption.encryptionKey(BASE64_KEY));
1215+
channel = storage.writer(info, BlobWriteOption.encryptionKey(BASE64_KEY));
11761216
assertNotNull(channel);
11771217
assertTrue(channel.isOpen());
11781218
}

0 commit comments

Comments
 (0)