xref: /aosp_15_r20/external/tink/java_src/src/test/java/com/google/crypto/tink/integration/gcpkms/FakeCloudKmsTest.java (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ////////////////////////////////////////////////////////////////////////////////
16 package com.google.crypto.tink.integration.gcpkms;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 import static java.nio.charset.StandardCharsets.UTF_8;
20 import static java.util.Arrays.asList;
21 import static org.junit.Assert.assertThrows;
22 
23 import com.google.api.services.cloudkms.v1.CloudKMS;
24 import com.google.api.services.cloudkms.v1.model.DecryptRequest;
25 import com.google.api.services.cloudkms.v1.model.DecryptResponse;
26 import com.google.api.services.cloudkms.v1.model.EncryptRequest;
27 import com.google.api.services.cloudkms.v1.model.EncryptResponse;
28 import com.google.crypto.tink.aead.AeadConfig;
29 import java.io.IOException;
30 import org.junit.BeforeClass;
31 import org.junit.Test;
32 import org.junit.runner.RunWith;
33 import org.junit.runners.JUnit4;
34 
35 @RunWith(JUnit4.class)
36 public final class FakeCloudKmsTest {
37 
38   private static final String KEY_ID =
39       "projects/tink-test/locations/global/keyRings/unit-test/cryptoKeys/aead-key";
40   private static final String KEY_ID_2 =
41       "projects/tink-test/locations/global/keyRings/unit-test/cryptoKeys/aead-key-2";
42 
43   @BeforeClass
setUpClass()44   public static void setUpClass() throws Exception {
45     AeadConfig.register();
46   }
47 
48   @Test
testEncryptDecryptWithValidKeyId_success()49   public void testEncryptDecryptWithValidKeyId_success() throws Exception {
50     CloudKMS kms = new FakeCloudKms(asList(KEY_ID));
51 
52     byte[] plaintext = "plaintext".getBytes(UTF_8);
53     byte[] associatedData = "associatedData".getBytes(UTF_8);
54 
55     EncryptRequest encRequest =
56         new EncryptRequest()
57             .encodePlaintext(plaintext)
58             .encodeAdditionalAuthenticatedData(associatedData);
59 
60     EncryptResponse encResponse =
61         kms.projects().locations().keyRings().cryptoKeys().encrypt(KEY_ID, encRequest).execute();
62 
63     DecryptRequest decRequest =
64         new DecryptRequest()
65             .encodeCiphertext(encResponse.decodeCiphertext())
66             .encodeAdditionalAuthenticatedData(associatedData);
67 
68     DecryptResponse decResponse =
69         kms.projects().locations().keyRings().cryptoKeys().decrypt(KEY_ID, decRequest).execute();
70 
71     assertThat(decResponse.decodePlaintext()).isEqualTo(plaintext);
72   }
73 
74   @Test
encryptEmptyData_decryptReturnsNull()75   public void encryptEmptyData_decryptReturnsNull() throws Exception {
76     CloudKMS kms = new FakeCloudKms(asList(KEY_ID));
77 
78     byte[] plaintext = "".getBytes(UTF_8);
79     byte[] associatedData = "associatedData".getBytes(UTF_8);
80 
81     EncryptRequest encRequest =
82         new EncryptRequest()
83             .encodePlaintext(plaintext)
84             .encodeAdditionalAuthenticatedData(associatedData);
85 
86     EncryptResponse encResponse =
87         kms.projects().locations().keyRings().cryptoKeys().encrypt(KEY_ID, encRequest).execute();
88 
89     DecryptRequest decRequest =
90         new DecryptRequest()
91             .encodeCiphertext(encResponse.decodeCiphertext())
92             .encodeAdditionalAuthenticatedData(associatedData);
93 
94     DecryptResponse decResponse =
95         kms.projects().locations().keyRings().cryptoKeys().decrypt(KEY_ID, decRequest).execute();
96 
97     assertThat(decResponse.decodePlaintext()).isNull();
98   }
99 
100   @Test
testEncryptWithUnknownKeyId_executeFails()101   public void testEncryptWithUnknownKeyId_executeFails() throws Exception {
102     CloudKMS kms = new FakeCloudKms(asList(KEY_ID));
103 
104     byte[] plaintext = "plaintext".getBytes(UTF_8);
105     byte[] associatedData = "associatedData".getBytes(UTF_8);
106 
107     EncryptRequest encRequest =
108         new EncryptRequest()
109             .encodePlaintext(plaintext)
110             .encodeAdditionalAuthenticatedData(associatedData);
111 
112     // The RPC to the KMS is done when execute is called. Therefore, calling encrypt for a
113     // valid but unknown key id does not (yet) fail.
114     CloudKMS.Projects.Locations.KeyRings.CryptoKeys.Encrypt enc =
115         kms.projects().locations().keyRings().cryptoKeys().encrypt(KEY_ID_2, encRequest);
116     assertThrows(IOException.class, enc::execute);
117   }
118 
119   @Test
testEncryptWithInvalidKeyId_encryptFails()120   public void testEncryptWithInvalidKeyId_encryptFails() throws Exception {
121     String invalidId = "invalid";
122 
123     CloudKMS kms = new FakeCloudKms(asList(invalidId));
124 
125     byte[] plaintext = "plaintext".getBytes(UTF_8);
126     byte[] associatedData = "associatedData".getBytes(UTF_8);
127 
128     EncryptRequest encRequest =
129         new EncryptRequest()
130             .encodePlaintext(plaintext)
131             .encodeAdditionalAuthenticatedData(associatedData);
132 
133     // Encrypts validates the format of the key id, and fails if it is invalid.
134     CloudKMS.Projects.Locations.KeyRings.CryptoKeys cryptoKeys =
135         kms.projects().locations().keyRings().cryptoKeys();
136     assertThrows(IllegalArgumentException.class, () -> cryptoKeys.encrypt(invalidId, encRequest));
137   }
138 
139   @Test
testDecryptWithInvalidKeyId_decryptFails()140   public void testDecryptWithInvalidKeyId_decryptFails() throws Exception {
141     String invalidId = "invalid";
142 
143     CloudKMS kms = new FakeCloudKms(asList(KEY_ID, invalidId));
144 
145     byte[] plaintext = "plaintext".getBytes(UTF_8);
146     byte[] associatedData = "associatedData".getBytes(UTF_8);
147 
148     EncryptRequest encRequest =
149         new EncryptRequest()
150             .encodePlaintext(plaintext)
151             .encodeAdditionalAuthenticatedData(associatedData);
152 
153     EncryptResponse encResponse =
154         kms.projects().locations().keyRings().cryptoKeys().encrypt(KEY_ID, encRequest).execute();
155 
156     DecryptRequest decRequest =
157         new DecryptRequest()
158             .encodeCiphertext(encResponse.decodeCiphertext())
159             .encodeAdditionalAuthenticatedData(associatedData);
160 
161     // Decrypt validates the format of the key id, and fails if it is invalid.
162     CloudKMS.Projects.Locations.KeyRings.CryptoKeys cryptoKeys =
163         kms.projects().locations().keyRings().cryptoKeys();
164     assertThrows(IllegalArgumentException.class, () -> cryptoKeys.decrypt(invalidId, decRequest));
165   }
166 
167 
168   @Test
testDecryptWithWrongKeyId_decryptFails()169   public void testDecryptWithWrongKeyId_decryptFails() throws Exception {
170     CloudKMS kms = new FakeCloudKms(asList(KEY_ID, KEY_ID_2));
171 
172     byte[] plaintext = "plaintext".getBytes(UTF_8);
173     byte[] associatedData = "associatedData".getBytes(UTF_8);
174 
175     EncryptRequest encRequest =
176         new EncryptRequest()
177             .encodePlaintext(plaintext)
178             .encodeAdditionalAuthenticatedData(associatedData);
179 
180     EncryptResponse encResponse =
181         kms.projects().locations().keyRings().cryptoKeys().encrypt(KEY_ID, encRequest).execute();
182 
183     DecryptRequest decRequest =
184         new DecryptRequest()
185             .encodeCiphertext(encResponse.decodeCiphertext())
186             .encodeAdditionalAuthenticatedData(associatedData);
187 
188     // The RPC to the KMS is done when execute is called. Therefore, calling decrypt with a wrong
189     // key id does not (yet) fail.
190     CloudKMS.Projects.Locations.KeyRings.CryptoKeys.Decrypt dec =
191         kms.projects()
192             .locations()
193             .keyRings()
194             .cryptoKeys()
195             .decrypt(KEY_ID_2, decRequest);
196     assertThrows(IOException.class, dec::execute);
197   }
198 
199   @Test
testDecryptExecuteWithInvalidCiphertext_executeFails()200   public void testDecryptExecuteWithInvalidCiphertext_executeFails() throws Exception {
201     CloudKMS kms = new FakeCloudKms(asList(KEY_ID));
202 
203     byte[] invalidCiphertext = "invalid".getBytes(UTF_8);
204     byte[] associatedData = "associatedData".getBytes(UTF_8);
205 
206     DecryptRequest decRequestWithInvalidCiphertext =
207         new DecryptRequest()
208             .encodeCiphertext(invalidCiphertext)
209             .encodeAdditionalAuthenticatedData(associatedData);
210 
211     CloudKMS.Projects.Locations.KeyRings.CryptoKeys.Decrypt dec =
212         kms.projects()
213             .locations()
214             .keyRings()
215             .cryptoKeys()
216             .decrypt(KEY_ID, decRequestWithInvalidCiphertext);
217     assertThrows(IOException.class, dec::execute);
218   }
219 
220   @Test
testEncryptDecryptWithTwoValidKeyId_success()221   public void testEncryptDecryptWithTwoValidKeyId_success() throws Exception {
222     CloudKMS kms = new FakeCloudKms(asList(KEY_ID, KEY_ID_2));
223 
224     byte[] plaintext = "plaintext".getBytes(UTF_8);
225     byte[] plaintext2 = "plaintext2".getBytes(UTF_8);
226     byte[] associatedData = "associatedData".getBytes(UTF_8);
227 
228     EncryptRequest encRequest =
229         new EncryptRequest()
230             .encodePlaintext(plaintext)
231             .encodeAdditionalAuthenticatedData(associatedData);
232     EncryptResponse encResponse =
233         kms.projects().locations().keyRings().cryptoKeys().encrypt(KEY_ID, encRequest).execute();
234 
235     EncryptRequest encRequest2 =
236         new EncryptRequest()
237             .encodePlaintext(plaintext2)
238             .encodeAdditionalAuthenticatedData(associatedData);
239 
240     EncryptResponse encResponse2 =
241         kms.projects().locations().keyRings().cryptoKeys().encrypt(KEY_ID, encRequest2).execute();
242 
243     DecryptRequest decRequest =
244         new DecryptRequest()
245             .encodeCiphertext(encResponse.decodeCiphertext())
246             .encodeAdditionalAuthenticatedData(associatedData);
247 
248     DecryptResponse decResponse =
249         kms.projects().locations().keyRings().cryptoKeys().decrypt(KEY_ID, decRequest).execute();
250 
251     assertThat(decResponse.decodePlaintext()).isEqualTo(plaintext);
252 
253     DecryptRequest decRequest2 =
254         new DecryptRequest()
255             .encodeCiphertext(encResponse2.decodeCiphertext())
256             .encodeAdditionalAuthenticatedData(associatedData);
257 
258     DecryptResponse decResponse2 =
259         kms.projects().locations().keyRings().cryptoKeys().decrypt(KEY_ID, decRequest2).execute();
260 
261     assertThat(decResponse2.decodePlaintext()).isEqualTo(plaintext2);
262   }
263 }
264