Skip to content

Commit 24d202f

Browse files
* use byte[] instead of String in KMS asymmetric * added import comments
1 parent 5dbf7be commit 24d202f

File tree

2 files changed

+81
-45
lines changed

2 files changed

+81
-45
lines changed

kms/src/main/java/com/example/Asymmetric.java

+54-26
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import com.google.api.services.cloudkms.v1.model.ListKeyRingsResponse;
3333
import java.io.IOException;
3434
import java.io.StringReader;
35-
import java.nio.charset.StandardCharsets;
3635
import java.security.InvalidKeyException;
3736
import java.security.KeyFactory;
3837
import java.security.MessageDigest;
@@ -43,7 +42,6 @@
4342
import java.security.Signature;
4443
import java.security.SignatureException;
4544
import java.security.spec.InvalidKeySpecException;
46-
import java.security.spec.PKCS8EncodedKeySpec;
4745
import java.security.spec.X509EncodedKeySpec;
4846
import java.util.Base64;
4947
import javax.crypto.BadPaddingException;
@@ -57,7 +55,18 @@
5755
public class Asymmetric {
5856

5957
// [START kms_get_asymmetric_public]
60-
/** Retrieves the public key from a saved asymmetric key pair on Cloud KMS */
58+
/**
59+
* Retrieves the public key from a saved asymmetric key pair on Cloud KMS
60+
*
61+
* Requires:
62+
* java.io.StringReader
63+
* java.security.KeyFactory
64+
* java.security.PublicKey
65+
* java.security.Security
66+
* java.security.spec.X509EncodedKeySpec
67+
* org.bouncycastle.jce.provider.BouncyCastleProvider
68+
* org.bouncycastle.util.io.pem.PemReader
69+
*/
6170
public static PublicKey getAsymmetricPublicKey(CloudKMS client, String keyPath)
6271
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException,
6372
NoSuchProviderException {
@@ -86,26 +95,32 @@ public static PublicKey getAsymmetricPublicKey(CloudKMS client, String keyPath)
8695
* Decrypt a given ciphertext using an 'RSA_DECRYPT_OAEP_2048_SHA256' private key
8796
* stored on Cloud KMS
8897
*/
89-
public static String decryptRSA(String ciphertext, CloudKMS client, String keyPath)
98+
public static byte[] decryptRSA(byte[] ciphertext, CloudKMS client, String keyPath)
9099
throws IOException {
91-
AsymmetricDecryptRequest request = new AsymmetricDecryptRequest().setCiphertext(ciphertext);
100+
AsymmetricDecryptRequest request = new AsymmetricDecryptRequest().encodeCiphertext(ciphertext);
92101
AsymmetricDecryptResponse response = client.projects()
93102
.locations()
94103
.keyRings()
95104
.cryptoKeys()
96105
.cryptoKeyVersions()
97106
.asymmetricDecrypt(keyPath, request)
98107
.execute();
99-
return new String(response.decodePlaintext());
108+
return response.decodePlaintext();
100109
}
101110
// [END kms_decrypt_rsa]
102111

103112
// [START kms_encrypt_rsa]
104113
/**
105-
* Encrypt message locally using an 'RSA_DECRYPT_OAEP_2048_SHA256' public key
106-
* retrieved from Cloud KMS
114+
* Encrypt data locally using an 'RSA_DECRYPT_OAEP_2048_SHA256' public key
115+
* retrieved from Cloud KMS
116+
*
117+
* Requires:
118+
* java.security.PublicKey
119+
* java.security.Security
120+
* javax.crypto.Cipher
121+
* org.bouncycastle.jce.provider.BouncyCastleProvider
107122
*/
108-
public static String encryptRSA(String message, CloudKMS client, String keyPath)
123+
public static byte[] encryptRSA(byte[] plaintext, CloudKMS client, String keyPath)
109124
throws IOException, IllegalBlockSizeException, NoSuchPaddingException,
110125
InvalidKeySpecException, NoSuchProviderException, BadPaddingException,
111126
NoSuchAlgorithmException, InvalidKeyException {
@@ -114,20 +129,23 @@ public static String encryptRSA(String message, CloudKMS client, String keyPath)
114129

115130
Cipher cipher = Cipher.getInstance("RSA/NONE/OAEPWITHSHA256ANDMGF1PADDING", "BC");
116131
cipher.init(Cipher.ENCRYPT_MODE, rsaKey);
117-
byte[] ciphertext = cipher.doFinal(message.getBytes(StandardCharsets.UTF_8));
118-
return Base64.getEncoder().encodeToString(ciphertext);
132+
return cipher.doFinal(plaintext);
119133
}
120134
// [END kms_encrypt_rsa]
121135

122136
// [START kms_sign_asymmetric]
123-
/** Create a signature for a message using a private key stored on Cloud KMS */
124-
public static String signAsymmetric(String message, CloudKMS client, String keyPath)
137+
/** Create a signature for a message using a private key stored on Cloud KMS
138+
*
139+
* Requires:
140+
* java.security.MessageDigest
141+
* java.util.Base64
142+
*/
143+
public static byte[] signAsymmetric(byte[] message, CloudKMS client, String keyPath)
125144
throws IOException, NoSuchAlgorithmException {
126-
byte[] msgBytes = message.getBytes(StandardCharsets.UTF_8);
127145
Digest digest = new Digest();
128146
// Note: some key algorithms will require a different hash function
129147
// For example, EC_SIGN_P384_SHA384 requires SHA-384
130-
digest.encodeSha256(MessageDigest.getInstance("SHA-256").digest(msgBytes));
148+
digest.encodeSha256(MessageDigest.getInstance("SHA-256").digest(message));
131149

132150
AsymmetricSignRequest signRequest = new AsymmetricSignRequest();
133151
signRequest.setDigest(digest);
@@ -139,16 +157,22 @@ public static String signAsymmetric(String message, CloudKMS client, String keyP
139157
.cryptoKeyVersions()
140158
.asymmetricSign(keyPath, signRequest)
141159
.execute();
142-
return response.getSignature();
160+
return Base64.getMimeDecoder().decode(response.getSignature());
143161
}
144162
// [END kms_sign_asymmetric]
145163

146164
// [START kms_verify_signature_rsa]
147165
/**
148166
* Verify the validity of an 'RSA_SIGN_PSS_2048_SHA256' signature for the
149-
* specified plaintext message
167+
* specified message
168+
*
169+
* Requires:
170+
* java.security.PublicKey
171+
* java.security.Security
172+
* java.security.Signature
173+
* org.bouncycastle.jce.provider.BouncyCastleProvider
150174
*/
151-
public static boolean verifySignatureRSA(String signature, String message, CloudKMS client,
175+
public static boolean verifySignatureRSA(byte[] signature, byte[] message, CloudKMS client,
152176
String keyPath) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException,
153177
SignatureException, NoSuchProviderException, InvalidKeyException {
154178
Security.addProvider(new BouncyCastleProvider());
@@ -157,18 +181,23 @@ public static boolean verifySignatureRSA(String signature, String message, Cloud
157181
Signature rsaVerify = Signature.getInstance("SHA256withRSA/PSS");
158182

159183
rsaVerify.initVerify(rsaKey);
160-
rsaVerify.update(message.getBytes(StandardCharsets.UTF_8));
161-
byte[] sigBytes = Base64.getMimeDecoder().decode(signature);
162-
return rsaVerify.verify(sigBytes);
184+
rsaVerify.update(message);
185+
return rsaVerify.verify(signature);
163186
}
164187
// [END kms_verify_signature_rsa]
165188

166189
// [START kms_verify_signature_ec]
167190
/**
168191
* Verify the validity of an 'EC_SIGN_P256_SHA256' signature for the
169-
* specified plaintext message
192+
* specified message
193+
*
194+
* Requires:
195+
* java.security.PublicKey
196+
* java.security.Security
197+
* java.security.Signature
198+
* org.bouncycastle.jce.provider.BouncyCastleProvider
170199
*/
171-
public static boolean verifySignatureEC(String signature, String message, CloudKMS client,
200+
public static boolean verifySignatureEC(byte[] signature, byte[] message, CloudKMS client,
172201
String keyPath) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException,
173202
SignatureException, NoSuchProviderException, InvalidKeyException {
174203
Security.addProvider(new BouncyCastleProvider());
@@ -177,9 +206,8 @@ public static boolean verifySignatureEC(String signature, String message, CloudK
177206
Signature ecVerify = Signature.getInstance("SHA256withECDSA", "BC");
178207

179208
ecVerify.initVerify(ecKey);
180-
ecVerify.update(message.getBytes(StandardCharsets.UTF_8));
181-
byte[] sigBytes = Base64.getMimeDecoder().decode(signature);
182-
return ecVerify.verify(sigBytes);
209+
ecVerify.update(message);
210+
return ecVerify.verify(signature);
183211
}
184212
// [END kms_verify_signature_ec]
185213

kms/src/test/java/com/example/AsymmetricIT.java

+27-19
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,13 @@
3131
import java.io.ByteArrayOutputStream;
3232
import java.io.IOException;
3333
import java.io.PrintStream;
34+
import java.nio.charset.StandardCharsets;
3435
import java.security.NoSuchAlgorithmException;
3536
import java.security.NoSuchProviderException;
3637
import java.security.PublicKey;
3738
import java.security.spec.InvalidKeySpecException;
39+
import java.util.Arrays;
40+
import java.util.Base64;
3841
import java.util.UUID;
3942
import java.util.regex.Matcher;
4043
import java.util.regex.Pattern;
@@ -56,6 +59,7 @@ public class AsymmetricIT {
5659
private static final String parent = "projects/" + projectId + "/locations/global";
5760
private static final String keyRing = "kms-asymmetric-sample";
5861
private static final String message = "test message 123";
62+
private static final byte[] message_bytes = message.getBytes(StandardCharsets.UTF_8);
5963

6064
private static final String rsaDecryptId = "rsa-decrypt";
6165
private static final String rsaSignId = "rsa-sign";
@@ -136,35 +140,39 @@ public void testGetPublicKey() throws Exception {
136140

137141
@Test
138142
public void testRSAEncryptDecrypt() throws Exception {
139-
String ciphertext = Asymmetric.encryptRSA(message, client, rsaDecrypt);
140-
assertEquals("incorrect RSA ciphertext length.", 344, ciphertext.length());
141-
assertEquals("incorrect ciphertext final character.", '=', ciphertext.charAt(343));
143+
byte[] ciphertext = Asymmetric.encryptRSA(message_bytes, client, rsaDecrypt);
144+
assertEquals("incorrect RSA ciphertext length.", 256, ciphertext.length);
142145

143-
String plaintext = Asymmetric.decryptRSA(ciphertext, client, rsaDecrypt);
146+
byte[] plainbytes = Asymmetric.decryptRSA(ciphertext, client, rsaDecrypt);
147+
assertTrue("decryption failed.", Arrays.equals(message_bytes, plainbytes));
148+
String plaintext = new String(plainbytes);
144149
assertEquals("decryption failed.", message, plaintext);
145150
}
146151

147152
@Test
148153
public void testRSASignVerify() throws Exception {
149-
String sig = Asymmetric.signAsymmetric(message, client, rsaSign);
150-
assertEquals("invalid ciphertext length", 344, sig.length());
151-
assertEquals("incorrect ciphertext final character.", '=', sig.charAt(343));
152-
153-
boolean success = Asymmetric.verifySignatureRSA(sig, message, client, rsaSign);
154-
assertTrue("RSA verification failed.", success);
155-
boolean shouldFail = Asymmetric.verifySignatureRSA(sig, message + ".", client, rsaSign);
156-
assertFalse("RSA verification failed.", shouldFail);
154+
byte[] sig = Asymmetric.signAsymmetric(message_bytes, client, rsaSign);
155+
assertEquals("invalid ciphertext length", 256, sig.length);
156+
157+
boolean success = Asymmetric.verifySignatureRSA(sig, message_bytes, client, rsaSign);
158+
assertTrue("RSA verification failed. Valid message not accepted", success);
159+
String changed = message + ".";
160+
byte[] changedBytes = changed.getBytes(StandardCharsets.UTF_8);
161+
boolean shouldFail = Asymmetric.verifySignatureRSA(sig, changedBytes, client, rsaSign);
162+
assertFalse("RSA verification failed. Invalid message accepted", shouldFail);
157163
}
158164

159165
@Test
160166
public void testECSignVerify() throws Exception {
161-
String sig = Asymmetric.signAsymmetric(message, client, ecSign);
162-
assertTrue("invalid ciphertext length", sig.length() > 50 && sig.length() < 300);
163-
164-
boolean success = Asymmetric.verifySignatureEC(sig, message, client, ecSign);
165-
assertTrue("RSA verification failed.", success);
166-
boolean shouldFail = Asymmetric.verifySignatureEC(sig, message + ".", client, ecSign);
167-
assertFalse("RSA verification failed.", shouldFail);
167+
byte[] sig = Asymmetric.signAsymmetric(message_bytes, client, ecSign);
168+
assertTrue("invalid ciphertext length", sig.length > 50 && sig.length < 300);
169+
170+
boolean success = Asymmetric.verifySignatureEC(sig, message_bytes, client, ecSign);
171+
assertTrue("EC verification failed. Valid message not accepted", success);
172+
String changed = message + ".";
173+
byte[] changedBytes = changed.getBytes(StandardCharsets.UTF_8);
174+
boolean shouldFail = Asymmetric.verifySignatureEC(sig, changedBytes, client, ecSign);
175+
assertFalse("EC verification failed. Invalid message accepted", shouldFail);
168176
}
169177

170178
}

0 commit comments

Comments
 (0)