Skip to content

Commit

Permalink
KMS samples.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jerjou Cheng committed Feb 1, 2017
1 parent 5440235 commit 5f358a5
Show file tree
Hide file tree
Showing 7 changed files with 1,057 additions and 0 deletions.
25 changes: 25 additions & 0 deletions kms/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Cloud Key Management Service

Google [Cloud Key Management Service](https://cloud.google.com/kms/) is a
cloud-hosted key management service that lets you manage encryption for your
cloud services the same way you do on-premise. You can generate, use, rotate and
destroy AES256 encryption keys. These sample Java applications demonstrate
how to access the KMS API using the Google Java API Client Libraries.

## Quickstart

Install [Maven](http://maven.apache.org/).

Build your project with:

mvn clean compile assembly:single

You can run the quickstart with:

java -cp target/kms-samples-1.0.0-jar-with-dependencies.jar \
com.example.Quickstart [your-project-id]

and can see the available snippet commands with:

java -cp target/kms-samples-1.0.0-jar-with-dependencies.jar \
com.example.Snippets
79 changes: 79 additions & 0 deletions kms/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.google.cloud.kms.samples</groupId>
<artifactId>kms-samples</artifactId>
<packaging>jar</packaging>

<parent>
<artifactId>doc-samples</artifactId>
<groupId>com.google.cloud</groupId>
<version>1.0.0</version>
<relativePath>..</relativePath>
</parent>

<dependencies>
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-cloudkms</artifactId>
<version>v1beta1-rev51-1.18.0-rc</version>
</dependency>
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>1.22.0</version>
</dependency>
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client-jackson2</artifactId>
<version>1.22.0</version>
</dependency>
<dependency>
<groupId>args4j</groupId>
<artifactId>args4j</artifactId>
<version>2.33</version>
</dependency>

<!-- test dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.truth</groupId>
<artifactId>truth</artifactId>
<version>0.31</version>
<scope>test</scope>
</dependency>
</dependencies>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<build>
<sourceDirectory>src/main/java</sourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>5</source>
<target>5</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>

</project>
119 changes: 119 additions & 0 deletions kms/src/main/java/com/example/CryptFile.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* Copyright (c) 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/

package com.example;

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.cloudkms.v1beta1.CloudKMS;
import com.google.api.services.cloudkms.v1beta1.CloudKMSScopes;
import com.google.api.services.cloudkms.v1beta1.model.DecryptRequest;
import com.google.api.services.cloudkms.v1beta1.model.DecryptResponse;
import com.google.api.services.cloudkms.v1beta1.model.EncryptRequest;
import com.google.api.services.cloudkms.v1beta1.model.EncryptResponse;

import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;

import java.io.IOException;

public class CryptFile {

/**
* Creates an authorized CloudKMS client service using Application Default Credentials.
*
* @return an authorized CloudKMS client
* @throws IOException if there's an error getting the default credentials.
*/
public static CloudKMS createAuthorizedClient() throws IOException {
// Create the credential
HttpTransport transport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
// Authorize the client using Application Default Credentials
// @see https://g.co/dv/identity/protocols/application-default-credentials
GoogleCredential credential = GoogleCredential.getApplicationDefault(transport, jsonFactory);

// Depending on the environment that provides the default credentials (e.g. Compute Engine, App
// Engine), the credentials may require us to specify the scopes we need explicitly.
// Check for this case, and inject the scope if required.
if (credential.createScopedRequired()) {
credential = credential.createScoped(CloudKMSScopes.all());
}

return new CloudKMS.Builder(transport, jsonFactory, credential)
.setApplicationName("CloudKMS CryptFile")
.build();
}

/**
* Encrypts the given bytes, using the specified crypto key.
*/
public static byte[] encrypt(String projectId, String ringId, String keyId, byte[] plaintext)
throws IOException {
String location = "global";
// The resource name of the cryptoKey
String cryptoKeyName = String.format(
"projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s",
projectId, location, ringId, keyId);
// Create the Cloud KMS client.
CloudKMS kms = createAuthorizedClient();

EncryptRequest request = new EncryptRequest().encodePlaintext(plaintext);
EncryptResponse response = kms.projects().locations().keyRings().cryptoKeys()
.encrypt(cryptoKeyName, request)
.execute();

return response.decodeCiphertext();
}

/**
* Decrypts the given encrypted bytes, using the specified crypto key.
*/
public static byte[] decrypt(String projectId, String ringId, String keyId, byte[] encrypted)
throws IOException {
String location = "global";
// Create the Cloud KMS client.
CloudKMS kms = createAuthorizedClient();

// The resource name of the cryptoKey
String cryptoKeyName = String.format(
"projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s",
projectId, location, ringId, keyId);

DecryptRequest request = new DecryptRequest().encodeCiphertext(encrypted);
DecryptResponse response = kms.projects().locations().keyRings().cryptoKeys()
.decrypt(cryptoKeyName, request)
.execute();

return response.decodePlaintext();
}

public static void main(String[] args) throws IOException {
CryptFileCommands commands = new CryptFileCommands();
CmdLineParser parser = new CmdLineParser(commands);

try {
parser.parseArgument(args);
} catch (CmdLineException e) {
System.out.println(e);
System.out.println();
e.getParser().printUsage(System.out);
System.exit(1);
}
commands.command.run();
}
}
91 changes: 91 additions & 0 deletions kms/src/main/java/com/example/CryptFileCommands.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/

package com.example;

import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
import org.kohsuke.args4j.spi.SubCommand;
import org.kohsuke.args4j.spi.SubCommandHandler;
import org.kohsuke.args4j.spi.SubCommands;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
* Defines the different sub-commands and their parameters, for command-line invocation.
*/
class CryptFileCommands {
/**
* An interface for a command-line sub-command.
*/
interface Command {
public void run() throws IOException;
}

// Most of the commands take some subset of the same arguments, so specify groups of arguments
// as classes for greater code reuse.
static class Args {
@Option(name = "--project-id", aliases = "-p", required = true, usage = "Your GCP project ID")
String projectId;
@Argument(metaVar = "ringId", required = true, index = 0, usage = "The ring id")
String ringId;
@Argument(metaVar = "keyId", required = true, index = 1, usage = "The key id")
String keyId;
@Argument(metaVar = "inFile", required = true, index = 1, usage = "The source file")
String inFile;
@Argument(metaVar = "outFile", required = true, index = 1, usage = "The destination file")
String outFile;
}

public static class EncryptCommand extends Args implements Command {
public void run() throws IOException {
byte[] encrypted = CryptFile.encrypt(
projectId, ringId, keyId,
Files.readAllBytes(Paths.get(inFile)));

FileOutputStream stream = new FileOutputStream(outFile);
try {
stream.write(encrypted);
} finally {
stream.close();
}
}
}

public static class DecryptCommand extends Args implements Command {
public void run() throws IOException {
byte[] decrypted = CryptFile.decrypt(
projectId, ringId, keyId,
Files.readAllBytes(Paths.get(inFile)));

FileOutputStream stream = new FileOutputStream(outFile);
try {
stream.write(decrypted);
} finally {
stream.close();
}
}
}

@Argument(metaVar = "command", required = true, handler = SubCommandHandler.class,
usage = "The subcommand to run")
@SubCommands({
@SubCommand(name = "encrypt", impl = EncryptCommand.class),
@SubCommand(name = "decrypt", impl = DecryptCommand.class)
})
Command command;
}
Loading

0 comments on commit 5f358a5

Please sign in to comment.