Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Klientkryptering med Google Tink, Google Cloud JMS integrasjon med lagring i Google Cloud Storage

Kryptering med Google Tink, nøkler fra Cloud KMS. Lagring i Cloud Storage

Avhengigheter

Maven - pom.xml

...
<properties>
	<google-cloud.version>25.0.0</google-cloud.version>
	<google-tink.version>1.6.1</google-tink.version>
</properties>

<dependencyManagement>
	<dependency>
		<groupId>com.google.cloud</groupId>
		<artifactId>libraries-bom</artifactId>
		<version>${google-cloud.version}</version>
		<type>pom</type>
		<scope>import</scope>
	</dependency>
	<dependency>
		<groupId>com.google.crypto.tink</groupId>
		<artifactId>tink</artifactId>
		<version>${google-tink.version}</version>
	</dependency>
	<dependency>
		<groupId>com.google.crypto.tink</groupId>
		<artifactId>tink-gcpkms</artifactId>
		<version>${google-tink.version}</version>
	</dependency>
</dependencyManagement>

<dependencies>
	<dependency>
		<groupId>com.google.cloud</groupId>
		<artifactId>google-cloud-storage</artifactId>
	</dependency>
	<dependency>
		<groupId>com.google.crypto.tink</groupId>
		<artifactId>tink</artifactId>
	</dependency>
	<dependency>
		<groupId>com.google.crypto.tink</groupId>
		<artifactId>tink-gcpkms</artifactId>
	</dependency>
</dependencies>
...

Ressurser

Hvis man er avhengig av data kryptert med eldre versjoner av en nøkkel så må data rekrypteres med ny versjon av nøkkel.

package storage;
/**
* Ekstern lagring i bucket
*
* @author Joakim Bjørnstad
*/
public interface BucketStorage {
/**
* Krypterer og laster opp objekt til Cloud Storage.
*
* @param objectName Navn på objektet. GUID eller annen unik ID.
* @param payload Objekt i klartekst. JSON string, base64 representert binærfil osv.
* @param associatedData Data som knyttes til objektet for å unngå manipulering. F.eks journalpostId, bestillingsId.
*/
void upload(String objectName, String payload, String associatedData);
/**
* Laster ned og dekrypterer objekt fra Cloud Storage
*
* @param objectName Navn på objektet som finnes i bucket. GUID eller annen unik ID som er kjent.
* @param associatedData Data som knyttes til objektet for å unngå manipulering. Må ha lik verdi som da det ble kryptert.
* F.eks journalpostId, bestillingsId.
* @return Objekt i klartekst
*/
String downloadObject(String objectName, String associatedData);
}
package storage;
import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageException;
import com.google.crypto.tink.Aead;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
/**
* Google Cloud Storage implementasjon av {@link BucketStorage}
*
* @author Joakim Bjørnstad
*/
public class GoogleCloudBucketStorage implements BucketStorage {
private final String bucket;
private final Storage storage;
private final Aead aead;
public GoogleCloudBucketStorage(String bucket,
Storage storage,
Aead aead) {
this.bucket = bucket;
this.storage = storage;
this.aead = aead;
}
@Override
public void upload(String objectName, String payload, String associatedData) {
try {
byte[] encryptedValue = aead.encrypt(payload.getBytes(), associatedData.getBytes());
BlobId blobId = BlobId.of(bucket, objectName);
BlobInfo blobInfo = BlobInfo.newBuilder(blobId).build();
storage.createFrom(blobInfo, new ByteArrayInputStream(encryptedValue));
} catch (IOException | GeneralSecurityException | StorageException e) {
throw new ObjectUploadFailedException("Klarte ikke laste opp objectName=" + objectName + " til bucket=" + bucket);
}
}
@Override
public String downloadObject(String objectName, String associatedData) {
try {
byte[] cipherText = storage.readAllBytes(bucket, objectName);
byte[] plainText = aead.decrypt(cipherText, associatedData.getBytes());
return new String(plainText);
} catch (GeneralSecurityException | StorageException e) {
throw new ObjectDownloadFailedException("Klarte ikke laste ned objectName=" + objectName + " fra bucket=" + bucket);
}
}
}
package storage;
import com.google.api.client.http.apache.v2.ApacheHttpTransport;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;
import com.google.crypto.tink.Aead;
import com.google.crypto.tink.KeyTemplate;
import com.google.crypto.tink.KeyTemplates;
import com.google.crypto.tink.KeysetHandle;
import com.google.crypto.tink.aead.AeadConfig;
import com.google.crypto.tink.aead.KmsEnvelopeAeadKeyManager;
import com.google.crypto.tink.integration.gcpkms.GcpKmsClient;
import java.util.Optional;
import static java.util.concurrent.TimeUnit.SECONDS;
/**
* Oppsett av Google Tink, KMS integrasjon og Cloud Storage Java klientbibliotek
*
* @author Joakim Bjørnstad
*/
public class GoogleCloudStorageConfiguration {
public BucketStorage storage() throws Exception {
final String kekUri = "gcp-kms://projects/{dinprosjektId}/locations/europe-north1/keyRings/{dinNøkkelring}/cryptoKeys/{dinNøkkelId}";
// Setter opp Tink Authenticated Encryption with Associated Data (AEAD)
AeadConfig.register();
// Setter opp Google Cloud KMS integrasjon.
// ServiceAccount kommer fra en json fil på path GOOGLE_APPLICATION_CREDENTIALS i env
GcpKmsClient.register(Optional.of(kekUri), Optional.empty());
// AES128_GCM er anbefalt for de fleste formål av Google. Enkelt å endre.
KeyTemplate keyTemplate = KmsEnvelopeAeadKeyManager.createKeyTemplate(kekUri, KeyTemplates.get("AES128_GCM"));
KeysetHandle handle = KeysetHandle.generateNew(keyTemplate);
// Tink primitiver er trådsikre
Aead aead = handle.getPrimitive(Aead.class);
// Setter opp lesing fra Bucket. ServiceAccount hentes fra GOOGLE_APPLICATION_CREDENTIALS i env
Storage storage = StorageOptions.newBuilder()
.setProjectId("dinprosjektId")
.setTransportOptions(StorageOptions.getDefaultHttpTransportOptions().toBuilder()
.setConnectTimeout((int) SECONDS.toMillis(5))
.setReadTimeout((int) SECONDS.toMillis(20))
// Litt mer avansert http transport. Bedre connection pooling enn standard
.setHttpTransportFactory(ApacheHttpTransport::new)
.build())
.build().getService();
return new GoogleCloudBucketStorage(storage, "dinBucket", aead);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment