Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@
import com.google.cloud.storage.spi.StorageRpc;
import com.google.cloud.storage.spi.StorageRpc.Tuple;
import com.google.common.base.Function;
import com.google.common.io.BaseEncoding;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.URL;
import java.security.Key;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -81,6 +83,10 @@ private BlobSourceOption(StorageRpc.Option rpcOption) {
super(rpcOption, null);
}

private BlobSourceOption(StorageRpc.Option rpcOption, Object value) {
super(rpcOption, value);
}

private Storage.BlobSourceOption toSourceOptions(BlobInfo blobInfo) {
switch (rpcOption()) {
case IF_GENERATION_MATCH:
Expand All @@ -91,6 +97,8 @@ private Storage.BlobSourceOption toSourceOptions(BlobInfo blobInfo) {
return Storage.BlobSourceOption.metagenerationMatch(blobInfo.metageneration());
case IF_METAGENERATION_NOT_MATCH:
return Storage.BlobSourceOption.metagenerationNotMatch(blobInfo.metageneration());
case CUSTOMER_SUPPLIED_KEY:
return Storage.BlobSourceOption.decryptionKey((String) value());
default:
throw new AssertionError("Unexpected enum value");
}
Expand Down Expand Up @@ -143,6 +151,25 @@ public static BlobSourceOption metagenerationNotMatch() {
return new BlobSourceOption(StorageRpc.Option.IF_METAGENERATION_NOT_MATCH);
}

/**
* Returns an option to set a customer-supplied AES256 key for server-side encryption of the
* blob.
*/
public static BlobSourceOption decryptionKey(Key key) {
String base64Key = BaseEncoding.base64().encode(key.getEncoded());
return new BlobSourceOption(StorageRpc.Option.CUSTOMER_SUPPLIED_KEY, base64Key);
}

/**
* Returns an option to set a customer-supplied AES256 key for server-side encryption of the
* blob.
*
* @param key the AES256 encoded in base64
*/
public static BlobSourceOption decryptionKey(String key) {
return new BlobSourceOption(StorageRpc.Option.CUSTOMER_SUPPLIED_KEY, key);
}

static Storage.BlobSourceOption[] toSourceOptions(BlobInfo blobInfo,
BlobSourceOption... options) {
Storage.BlobSourceOption[] convertedOptions = new Storage.BlobSourceOption[options.length];
Expand Down Expand Up @@ -308,6 +335,12 @@ Builder isDirectory(boolean isDirectory) {
return this;
}

@Override
Builder customerEncryption(CustomerEncryption customerEncryption) {
infoBuilder.customerEncryption(customerEncryption);
return this;
}

@Override
public Blob build() {
return new Blob(storage, infoBuilder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public StorageObject apply(BlobInfo blobInfo) {
private final String contentLanguage;
private final Integer componentCount;
private final boolean isDirectory;
private final CustomerEncryption customerEncryption;

/**
* This class is meant for internal use only. Users are discouraged from using this class.
Expand All @@ -92,6 +93,69 @@ public Set<Entry<K, V>> entrySet() {
}
}

/**
* Objects of this class hold information on the customer-supplied encryption key, if the blob is
* encrypted using such a key.
*/
public static class CustomerEncryption implements Serializable {

private static final long serialVersionUID = -2133042982786959351L;

private final String encryptionAlgorithm;
private final String keySha256;

CustomerEncryption(String encryptionAlgorithm, String keySha256) {
this.encryptionAlgorithm = encryptionAlgorithm;
this.keySha256 = keySha256;
}

/**
* Returns the algorithm used to encrypt the blob.
*/
public String encryptionAlgorithm() {
return encryptionAlgorithm;
}

/**
* Returns the SHA256 hash of the encryption key.
*/
public String keySha256() {
return keySha256;
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("encryptionAlgorithm", encryptionAlgorithm())
.add("keySha256", keySha256())
.toString();
}

@Override
public final int hashCode() {
return Objects.hash(encryptionAlgorithm, keySha256);
}

@Override
public final boolean equals(Object obj) {
return obj == this
|| obj != null
&& obj.getClass().equals(CustomerEncryption.class)
&& Objects.equals(toPb(), ((CustomerEncryption) obj).toPb());
}

StorageObject.CustomerEncryption toPb() {
return new StorageObject.CustomerEncryption()
.setEncryptionAlgorithm(encryptionAlgorithm)
.setKeySha256(keySha256);
}

static CustomerEncryption fromPb(StorageObject.CustomerEncryption customerEncryptionPb) {
return new CustomerEncryption(customerEncryptionPb.getEncryptionAlgorithm(),
customerEncryptionPb.getKeySha256());
}
}

/**
* Builder for {@code BlobInfo}.
*/
Expand Down Expand Up @@ -193,6 +257,8 @@ public abstract static class Builder {

abstract Builder isDirectory(boolean isDirectory);

abstract Builder customerEncryption(CustomerEncryption customerEncryption);

/**
* Creates a {@code BlobInfo} object.
*/
Expand Down Expand Up @@ -223,6 +289,7 @@ static final class BuilderImpl extends Builder {
private Long updateTime;
private Long createTime;
private Boolean isDirectory;
private CustomerEncryption customerEncryption;

BuilderImpl(BlobId blobId) {
this.blobId = blobId;
Expand All @@ -237,6 +304,7 @@ static final class BuilderImpl extends Builder {
contentDisposition = blobInfo.contentDisposition;
contentLanguage = blobInfo.contentLanguage;
componentCount = blobInfo.componentCount;
customerEncryption = blobInfo.customerEncryption;
acl = blobInfo.acl;
owner = blobInfo.owner;
size = blobInfo.size;
Expand Down Expand Up @@ -386,6 +454,12 @@ Builder isDirectory(boolean isDirectory) {
return this;
}

@Override
Builder customerEncryption(CustomerEncryption customerEncryption) {
this.customerEncryption = customerEncryption;
return this;
}

@Override
public BlobInfo build() {
checkNotNull(blobId);
Expand All @@ -402,6 +476,7 @@ public BlobInfo build() {
contentDisposition = builder.contentDisposition;
contentLanguage = builder.contentLanguage;
componentCount = builder.componentCount;
customerEncryption = builder.customerEncryption;
acl = builder.acl;
owner = builder.owner;
size = builder.size;
Expand Down Expand Up @@ -631,6 +706,14 @@ public boolean isDirectory() {
return isDirectory;
}

/**
* Returns information on the customer-supplied encryption key, if the blob is encrypted using
* such a key.
*/
public CustomerEncryption customerEncryption() {
return customerEncryption;
}

/**
* Returns a builder for the current blob.
*/
Expand Down Expand Up @@ -696,6 +779,9 @@ public ObjectAccessControl apply(Acl acl) {
firstNonNull(entry.getValue(), Data.<String>nullOf(String.class)));
}
}
if (customerEncryption != null) {
storageObject.setCustomerEncryption(customerEncryption.toPb());
}
storageObject.setMetadata(pbMetadata);
storageObject.setCacheControl(cacheControl);
storageObject.setContentEncoding(contentEncoding);
Expand Down Expand Up @@ -815,6 +901,9 @@ public Acl apply(ObjectAccessControl objectAccessControl) {
if (storageObject.containsKey("isDirectory")) {
builder.isDirectory(Boolean.TRUE);
}
if (storageObject.getCustomerEncryption() != null) {
builder.customerEncryption(CustomerEncryption.fromPb(storageObject.getCustomerEncryption()));
}
return builder.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.io.BaseEncoding;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.security.Key;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
Expand Down Expand Up @@ -166,6 +168,9 @@ private StorageRpc.Tuple<BlobInfo, Storage.BlobTargetOption> toTargetOption(Blob
case IF_METAGENERATION_NOT_MATCH:
return StorageRpc.Tuple.of(blobInfo.toBuilder().metageneration((Long) value()).build(),
Storage.BlobTargetOption.metagenerationNotMatch());
case CUSTOMER_SUPPLIED_KEY:
return StorageRpc.Tuple.of(blobInfo,
Storage.BlobTargetOption.encryptionKey((String) value()));
default:
throw new AssertionError("Unexpected enum value");
}
Expand Down Expand Up @@ -223,6 +228,25 @@ public static BlobTargetOption metagenerationNotMatch(long metageneration) {
return new BlobTargetOption(StorageRpc.Option.IF_METAGENERATION_NOT_MATCH, metageneration);
}

/**
* Returns an option to set a customer-supplied AES256 key for server-side encryption of the
* blob.
*/
public static BlobTargetOption encryptionKey(Key key) {
String base64Key = BaseEncoding.base64().encode(key.getEncoded());
return new BlobTargetOption(StorageRpc.Option.CUSTOMER_SUPPLIED_KEY, base64Key);
}

/**
* Returns an option to set a customer-supplied AES256 key for server-side encryption of the
* blob.
*
* @param key the AES256 encoded in base64
*/
public static BlobTargetOption encryptionKey(String key) {
return new BlobTargetOption(StorageRpc.Option.CUSTOMER_SUPPLIED_KEY, key);
}

static StorageRpc.Tuple<BlobInfo, Storage.BlobTargetOption[]> toTargetOptions(
BlobInfo info, BlobTargetOption... options) {
Set<StorageRpc.Option> optionSet =
Expand Down Expand Up @@ -289,6 +313,9 @@ private StorageRpc.Tuple<BlobInfo, Storage.BlobWriteOption> toWriteOption(BlobIn
case IF_CRC32C_MATCH:
return StorageRpc.Tuple.of(blobInfo.toBuilder().crc32c((String) value).build(),
Storage.BlobWriteOption.crc32cMatch());
case CUSTOMER_SUPPLIED_KEY:
return StorageRpc.Tuple.of(blobInfo,
Storage.BlobWriteOption.encryptionKey((String) value));
default:
throw new AssertionError("Unexpected enum value");
}
Expand Down Expand Up @@ -387,6 +414,25 @@ public static BlobWriteOption crc32cMatch(String crc32c) {
return new BlobWriteOption(Storage.BlobWriteOption.Option.IF_CRC32C_MATCH, crc32c);
}

/**
* Returns an option to set a customer-supplied AES256 key for server-side encryption of the
* blob.
*/
public static BlobWriteOption encryptionKey(Key key) {
String base64Key = BaseEncoding.base64().encode(key.getEncoded());
return new BlobWriteOption(Storage.BlobWriteOption.Option.CUSTOMER_SUPPLIED_KEY, base64Key);
}

/**
* Returns an option to set a customer-supplied AES256 key for server-side encryption of the
* blob.
*
* @param key the AES256 encoded in base64
*/
public static BlobWriteOption encryptionKey(String key) {
return new BlobWriteOption(Storage.BlobWriteOption.Option.CUSTOMER_SUPPLIED_KEY, key);
}

static StorageRpc.Tuple<BlobInfo, Storage.BlobWriteOption[]> toWriteOptions(
BlobInfo info, BlobWriteOption... options) {
Set<Storage.BlobWriteOption.Option> optionSet =
Expand Down
Loading