1 // Copyright 2020 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 17 package com.google.crypto.tink.testing; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static java.nio.charset.StandardCharsets.UTF_8; 21 import static java.util.concurrent.TimeUnit.SECONDS; 22 import static org.junit.Assert.assertThrows; 23 24 import com.google.crypto.tink.config.TinkConfig; 25 import com.google.crypto.tink.hybrid.EciesAeadHkdfPrivateKeyManager; 26 import com.google.crypto.tink.internal.KeyTemplateProtoConverter; 27 import com.google.crypto.tink.signature.EcdsaSignKeyManager; 28 import com.google.crypto.tink.testing.proto.AnnotatedKeyset; 29 import com.google.crypto.tink.testing.proto.CreationRequest; 30 import com.google.crypto.tink.testing.proto.CreationResponse; 31 import com.google.crypto.tink.testing.proto.HybridDecryptRequest; 32 import com.google.crypto.tink.testing.proto.HybridDecryptResponse; 33 import com.google.crypto.tink.testing.proto.HybridEncryptRequest; 34 import com.google.crypto.tink.testing.proto.HybridEncryptResponse; 35 import com.google.crypto.tink.testing.proto.HybridGrpc; 36 import com.google.crypto.tink.testing.proto.KeysetGenerateRequest; 37 import com.google.crypto.tink.testing.proto.KeysetGenerateResponse; 38 import com.google.crypto.tink.testing.proto.KeysetGrpc; 39 import com.google.crypto.tink.testing.proto.KeysetPublicRequest; 40 import com.google.crypto.tink.testing.proto.KeysetPublicResponse; 41 import com.google.crypto.tink.testing.proto.SignatureGrpc; 42 import com.google.crypto.tink.testing.proto.SignatureSignRequest; 43 import com.google.crypto.tink.testing.proto.SignatureSignResponse; 44 import com.google.crypto.tink.testing.proto.SignatureVerifyRequest; 45 import com.google.crypto.tink.testing.proto.SignatureVerifyResponse; 46 import com.google.protobuf.ByteString; 47 import io.grpc.ManagedChannel; 48 import io.grpc.Server; 49 import io.grpc.inprocess.InProcessChannelBuilder; 50 import io.grpc.inprocess.InProcessServerBuilder; 51 import org.junit.After; 52 import org.junit.Before; 53 import org.junit.Test; 54 import org.junit.runner.RunWith; 55 import org.junit.runners.JUnit4; 56 57 @RunWith(JUnit4.class) 58 public final class AsymmetricTestingServicesTest { 59 private Server server; 60 private ManagedChannel channel; 61 KeysetGrpc.KeysetBlockingStub keysetStub; 62 HybridGrpc.HybridBlockingStub hybridStub; 63 SignatureGrpc.SignatureBlockingStub signatureStub; 64 65 @Before setUp()66 public void setUp() throws Exception { 67 TinkConfig.register(); 68 String serverName = InProcessServerBuilder.generateName(); 69 server = 70 InProcessServerBuilder.forName(serverName) 71 .directExecutor() 72 .addService(new KeysetServiceImpl()) 73 .addService(new HybridServiceImpl()) 74 .addService(new SignatureServiceImpl()) 75 .build() 76 .start(); 77 channel = InProcessChannelBuilder.forName(serverName).directExecutor().build(); 78 keysetStub = KeysetGrpc.newBlockingStub(channel); 79 hybridStub = HybridGrpc.newBlockingStub(channel); 80 signatureStub = SignatureGrpc.newBlockingStub(channel); 81 } 82 83 @After tearDown()84 public void tearDown() throws Exception { 85 assertThat(channel.shutdown().awaitTermination(5, SECONDS)).isTrue(); 86 assertThat(server.shutdown().awaitTermination(5, SECONDS)).isTrue(); 87 } 88 generateKeyset( KeysetGrpc.KeysetBlockingStub keysetStub, byte[] template)89 private static KeysetGenerateResponse generateKeyset( 90 KeysetGrpc.KeysetBlockingStub keysetStub, byte[] template) { 91 KeysetGenerateRequest genRequest = 92 KeysetGenerateRequest.newBuilder().setTemplate(ByteString.copyFrom(template)).build(); 93 return keysetStub.generate(genRequest); 94 } 95 publicKeyset( KeysetGrpc.KeysetBlockingStub keysetStub, byte[] privateKeyset)96 private static KeysetPublicResponse publicKeyset( 97 KeysetGrpc.KeysetBlockingStub keysetStub, byte[] privateKeyset) { 98 KeysetPublicRequest request = 99 KeysetPublicRequest.newBuilder() 100 .setPrivateKeyset(ByteString.copyFrom(privateKeyset)) 101 .build(); 102 return keysetStub.public_(request); 103 } 104 105 @Test hybridDecryptCreateKeyset_success()106 public void hybridDecryptCreateKeyset_success() throws Exception { 107 byte[] template = 108 KeyTemplateProtoConverter.toByteArray( 109 EciesAeadHkdfPrivateKeyManager.eciesP256HkdfHmacSha256Aes128GcmTemplate()); 110 KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template); 111 assertThat(keysetResponse.getErr()).isEmpty(); 112 CreationResponse response = 113 hybridStub.createHybridDecrypt( 114 CreationRequest.newBuilder() 115 .setAnnotatedKeyset( 116 AnnotatedKeyset.newBuilder() 117 .setSerializedKeyset(keysetResponse.getKeyset()) 118 .build()) 119 .build()); 120 assertThat(response.getErr()).isEmpty(); 121 } 122 123 @Test hybridDecryptCreateKeyset_fails()124 public void hybridDecryptCreateKeyset_fails() throws Exception { 125 CreationResponse response = 126 hybridStub.createHybridDecrypt( 127 CreationRequest.newBuilder() 128 .setAnnotatedKeyset( 129 AnnotatedKeyset.newBuilder() 130 .setSerializedKeyset(ByteString.copyFrom(new byte[] {(byte) 0x80})) 131 .build()) 132 .build()); 133 assertThat(response.getErr()).isNotEmpty(); 134 } 135 136 137 @Test hybridEncryptCreateKeyset_success()138 public void hybridEncryptCreateKeyset_success() throws Exception { 139 byte[] template = KeyTemplateProtoConverter.toByteArray( 140 EciesAeadHkdfPrivateKeyManager.eciesP256HkdfHmacSha256Aes128GcmTemplate()); 141 KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template); 142 assertThat(keysetResponse.getErr()).isEmpty(); 143 byte[] privateKeyset = keysetResponse.getKeyset().toByteArray(); 144 145 KeysetPublicResponse pubResponse = publicKeyset(keysetStub, privateKeyset); 146 assertThat(pubResponse.getErr()).isEmpty(); 147 CreationResponse response = 148 hybridStub.createHybridEncrypt( 149 CreationRequest.newBuilder() 150 .setAnnotatedKeyset( 151 AnnotatedKeyset.newBuilder() 152 .setSerializedKeyset(pubResponse.getPublicKeyset()) 153 .build()) 154 .build()); 155 assertThat(response.getErr()).isEmpty(); 156 } 157 158 @Test hybridEncryptCreateKeyset_fails()159 public void hybridEncryptCreateKeyset_fails() throws Exception { 160 CreationResponse response = 161 hybridStub.createHybridEncrypt( 162 CreationRequest.newBuilder() 163 .setAnnotatedKeyset( 164 AnnotatedKeyset.newBuilder() 165 .setSerializedKeyset(ByteString.copyFrom(new byte[] {(byte) 0x80})) 166 .build()) 167 .build()); 168 assertThat(response.getErr()).isNotEmpty(); 169 } 170 hybridEncrypt( HybridGrpc.HybridBlockingStub hybridStub, byte[] publicKeyset, byte[] plaintext, byte[] contextInfo)171 private static HybridEncryptResponse hybridEncrypt( 172 HybridGrpc.HybridBlockingStub hybridStub, 173 byte[] publicKeyset, 174 byte[] plaintext, 175 byte[] contextInfo) { 176 HybridEncryptRequest encRequest = 177 HybridEncryptRequest.newBuilder() 178 .setPublicAnnotatedKeyset( 179 AnnotatedKeyset.newBuilder() 180 .setSerializedKeyset(ByteString.copyFrom(publicKeyset)) 181 .build()) 182 .setPlaintext(ByteString.copyFrom(plaintext)) 183 .setContextInfo(ByteString.copyFrom(contextInfo)) 184 .build(); 185 return hybridStub.encrypt(encRequest); 186 } 187 hybridDecrypt( HybridGrpc.HybridBlockingStub hybridStub, byte[] privateKeyset, byte[] ciphertext, byte[] contextInfo)188 private static HybridDecryptResponse hybridDecrypt( 189 HybridGrpc.HybridBlockingStub hybridStub, 190 byte[] privateKeyset, 191 byte[] ciphertext, 192 byte[] contextInfo) { 193 HybridDecryptRequest decRequest = 194 HybridDecryptRequest.newBuilder() 195 .setPrivateAnnotatedKeyset( 196 AnnotatedKeyset.newBuilder() 197 .setSerializedKeyset(ByteString.copyFrom(privateKeyset)) 198 .build()) 199 .setCiphertext(ByteString.copyFrom(ciphertext)) 200 .setContextInfo(ByteString.copyFrom(contextInfo)) 201 .build(); 202 return hybridStub.decrypt(decRequest); 203 } 204 205 @Test hybridGenerateEncryptDecrypt_success()206 public void hybridGenerateEncryptDecrypt_success() throws Exception { 207 byte[] template = KeyTemplateProtoConverter.toByteArray( 208 EciesAeadHkdfPrivateKeyManager.eciesP256HkdfHmacSha256Aes128GcmTemplate()); 209 byte[] plaintext = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8); 210 byte[] associatedData = "generate_encrypt_decrypt".getBytes(UTF_8); 211 212 KeysetGenerateResponse genResponse = generateKeyset(keysetStub, template); 213 assertThat(genResponse.getErr()).isEmpty(); 214 byte[] privateKeyset = genResponse.getKeyset().toByteArray(); 215 216 KeysetPublicResponse pubResponse = publicKeyset(keysetStub, privateKeyset); 217 assertThat(pubResponse.getErr()).isEmpty(); 218 byte[] publicKeyset = pubResponse.getPublicKeyset().toByteArray(); 219 220 HybridEncryptResponse encResponse = 221 hybridEncrypt(hybridStub, publicKeyset, plaintext, associatedData); 222 assertThat(encResponse.getErr()).isEmpty(); 223 byte[] ciphertext = encResponse.getCiphertext().toByteArray(); 224 225 HybridDecryptResponse decResponse = 226 hybridDecrypt(hybridStub, privateKeyset, ciphertext, associatedData); 227 assertThat(decResponse.getErr()).isEmpty(); 228 byte[] output = decResponse.getPlaintext().toByteArray(); 229 230 assertThat(output).isEqualTo(plaintext); 231 } 232 233 @Test publicKeyset_failsOnBadKeyset()234 public void publicKeyset_failsOnBadKeyset() throws Exception { 235 byte[] badKeyset = "bad keyset".getBytes(UTF_8); 236 KeysetPublicResponse response = publicKeyset(keysetStub, badKeyset); 237 assertThat(response.getErr()).isNotEmpty(); 238 } 239 240 @Test hybridEncrypt_errorOnBadKeyset()241 public void hybridEncrypt_errorOnBadKeyset() throws Exception { 242 byte[] badKeyset = "bad keyset".getBytes(UTF_8); 243 byte[] plaintext = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8); 244 byte[] contextInfo = "hybrid_encrypt_bad_keyset".getBytes(UTF_8); 245 assertThrows( 246 io.grpc.StatusRuntimeException.class, 247 () -> hybridEncrypt(hybridStub, badKeyset, plaintext, contextInfo)); 248 } 249 250 @Test hybridDecrypt_errorOnBadCiphertext()251 public void hybridDecrypt_errorOnBadCiphertext() throws Exception { 252 byte[] template = KeyTemplateProtoConverter.toByteArray( 253 EciesAeadHkdfPrivateKeyManager.eciesP256HkdfHmacSha256Aes128GcmTemplate()); 254 byte[] badCiphertext = "bad ciphertext".getBytes(UTF_8); 255 byte[] contextInfo = "hybrid_decrypt_bad_ciphertext".getBytes(UTF_8); 256 257 KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template); 258 assertThat(keysetResponse.getErr()).isEmpty(); 259 byte[] privateKeyset = keysetResponse.getKeyset().toByteArray(); 260 261 KeysetPublicResponse pubResponse = publicKeyset(keysetStub, privateKeyset); 262 assertThat(pubResponse.getErr()).isEmpty(); 263 byte[] publicKeyset = pubResponse.getPublicKeyset().toByteArray(); 264 265 assertThrows( 266 io.grpc.StatusRuntimeException.class, 267 () -> hybridDecrypt(hybridStub, publicKeyset, badCiphertext, contextInfo)); 268 } 269 270 @Test hybridDecrypt_failsOnBadKeyset()271 public void hybridDecrypt_failsOnBadKeyset() throws Exception { 272 byte[] template = KeyTemplateProtoConverter.toByteArray( 273 EciesAeadHkdfPrivateKeyManager.eciesP256HkdfHmacSha256Aes128GcmTemplate()); 274 byte[] plaintext = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8); 275 byte[] contextInfo = "hybrid_decrypt_bad_keyset".getBytes(UTF_8); 276 277 KeysetGenerateResponse privateKeysetResponse = generateKeyset(keysetStub, template); 278 assertThat(privateKeysetResponse.getErr()).isEmpty(); 279 byte[] privateKeyset = privateKeysetResponse.getKeyset().toByteArray(); 280 281 KeysetPublicResponse pubResponse = publicKeyset(keysetStub, privateKeyset); 282 assertThat(pubResponse.getErr()).isEmpty(); 283 byte[] publicKeyset = pubResponse.getPublicKeyset().toByteArray(); 284 285 HybridEncryptResponse encResponse = 286 hybridEncrypt(hybridStub, publicKeyset, plaintext, contextInfo); 287 assertThat(encResponse.getErr()).isEmpty(); 288 byte[] ciphertext = encResponse.getCiphertext().toByteArray(); 289 290 byte[] badKeyset = "bad keyset".getBytes(UTF_8); 291 assertThrows( 292 io.grpc.StatusRuntimeException.class, 293 () -> hybridDecrypt(hybridStub, badKeyset, ciphertext, contextInfo)); 294 } 295 296 @Test publicKeySignCreateKeyset_success()297 public void publicKeySignCreateKeyset_success() throws Exception { 298 byte[] template = KeyTemplateProtoConverter.toByteArray( 299 EcdsaSignKeyManager.ecdsaP256Template()); 300 KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template); 301 assertThat(keysetResponse.getErr()).isEmpty(); 302 CreationResponse response = 303 signatureStub.createPublicKeySign( 304 CreationRequest.newBuilder() 305 .setAnnotatedKeyset( 306 AnnotatedKeyset.newBuilder() 307 .setSerializedKeyset(keysetResponse.getKeyset()) 308 .build()) 309 .build()); 310 assertThat(response.getErr()).isEmpty(); 311 } 312 313 @Test publicKeySignCreateKeyset_fails()314 public void publicKeySignCreateKeyset_fails() throws Exception { 315 CreationResponse response = 316 signatureStub.createPublicKeySign( 317 CreationRequest.newBuilder() 318 .setAnnotatedKeyset( 319 AnnotatedKeyset.newBuilder() 320 .setSerializedKeyset(ByteString.copyFrom(new byte[] {(byte) 0x80})) 321 .build()) 322 .build()); 323 assertThat(response.getErr()).isNotEmpty(); 324 } 325 326 327 @Test publicKeyVerifyCreateKeyset_success()328 public void publicKeyVerifyCreateKeyset_success() throws Exception { 329 byte[] template = KeyTemplateProtoConverter.toByteArray( 330 EcdsaSignKeyManager.ecdsaP256Template()); 331 KeysetGenerateResponse keysetResponse = generateKeyset(keysetStub, template); 332 assertThat(keysetResponse.getErr()).isEmpty(); 333 byte[] privateKeyset = keysetResponse.getKeyset().toByteArray(); 334 335 KeysetPublicResponse pubResponse = publicKeyset(keysetStub, privateKeyset); 336 assertThat(pubResponse.getErr()).isEmpty(); 337 CreationResponse response = 338 signatureStub.createPublicKeyVerify( 339 CreationRequest.newBuilder() 340 .setAnnotatedKeyset( 341 AnnotatedKeyset.newBuilder() 342 .setSerializedKeyset(pubResponse.getPublicKeyset()) 343 .build()) 344 .build()); 345 assertThat(response.getErr()).isEmpty(); 346 } 347 348 @Test publicKeyVerifyCreateKeyset_fails()349 public void publicKeyVerifyCreateKeyset_fails() throws Exception { 350 CreationResponse response = 351 signatureStub.createPublicKeyVerify( 352 CreationRequest.newBuilder() 353 .setAnnotatedKeyset( 354 AnnotatedKeyset.newBuilder() 355 .setSerializedKeyset(ByteString.copyFrom(new byte[] {(byte) 0x80})) 356 .build()) 357 .build()); 358 assertThat(response.getErr()).isNotEmpty(); 359 } 360 signatureSign( SignatureGrpc.SignatureBlockingStub signatureStub, byte[] privateKeyset, byte[] data)361 private static SignatureSignResponse signatureSign( 362 SignatureGrpc.SignatureBlockingStub signatureStub, byte[] privateKeyset, byte[] data) { 363 SignatureSignRequest request = 364 SignatureSignRequest.newBuilder() 365 .setPrivateAnnotatedKeyset( 366 AnnotatedKeyset.newBuilder() 367 .setSerializedKeyset(ByteString.copyFrom(privateKeyset)) 368 .build()) 369 .setData(ByteString.copyFrom(data)) 370 .build(); 371 return signatureStub.sign(request); 372 } 373 signatureVerify( SignatureGrpc.SignatureBlockingStub signatureStub, byte[] publicKeyset, byte[] signature, byte[] data)374 private static SignatureVerifyResponse signatureVerify( 375 SignatureGrpc.SignatureBlockingStub signatureStub, 376 byte[] publicKeyset, 377 byte[] signature, 378 byte[] data) { 379 SignatureVerifyRequest request = 380 SignatureVerifyRequest.newBuilder() 381 .setPublicAnnotatedKeyset( 382 AnnotatedKeyset.newBuilder() 383 .setSerializedKeyset(ByteString.copyFrom(publicKeyset)) 384 .build()) 385 .setSignature(ByteString.copyFrom(signature)) 386 .setData(ByteString.copyFrom(data)) 387 .build(); 388 return signatureStub.verify(request); 389 } 390 391 @Test signatureSignVerify_success()392 public void signatureSignVerify_success() throws Exception { 393 byte[] template = KeyTemplateProtoConverter.toByteArray( 394 EcdsaSignKeyManager.ecdsaP256Template()); 395 byte[] data = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8); 396 397 KeysetGenerateResponse genResponse = generateKeyset(keysetStub, template); 398 assertThat(genResponse.getErr()).isEmpty(); 399 byte[] privateKeyset = genResponse.getKeyset().toByteArray(); 400 401 KeysetPublicResponse pubResponse = publicKeyset(keysetStub, privateKeyset); 402 assertThat(pubResponse.getErr()).isEmpty(); 403 byte[] publicKeyset = pubResponse.getPublicKeyset().toByteArray(); 404 405 SignatureSignResponse signResponse = signatureSign(signatureStub, privateKeyset, data); 406 assertThat(signResponse.getErr()).isEmpty(); 407 byte[] signature = signResponse.getSignature().toByteArray(); 408 409 SignatureVerifyResponse verifyResponse = 410 signatureVerify(signatureStub, publicKeyset, signature, data); 411 assertThat(verifyResponse.getErr()).isEmpty(); 412 } 413 414 @Test signatureSign_failsOnBadKeyset()415 public void signatureSign_failsOnBadKeyset() throws Exception { 416 byte[] badKeyset = "bad keyset".getBytes(UTF_8); 417 byte[] data = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8); 418 419 SignatureSignResponse response = signatureSign(signatureStub, badKeyset, data); 420 assertThat(response.getErr()).isNotEmpty(); 421 } 422 423 @Test signatureVerify_failsOnBadSignature()424 public void signatureVerify_failsOnBadSignature() throws Exception { 425 byte[] template = KeyTemplateProtoConverter.toByteArray( 426 EcdsaSignKeyManager.ecdsaP256Template()); 427 byte[] data = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8); 428 429 KeysetGenerateResponse genResponse = generateKeyset(keysetStub, template); 430 assertThat(genResponse.getErr()).isEmpty(); 431 byte[] privateKeyset = genResponse.getKeyset().toByteArray(); 432 433 KeysetPublicResponse pubResponse = publicKeyset(keysetStub, privateKeyset); 434 assertThat(pubResponse.getErr()).isEmpty(); 435 byte[] publicKeyset = pubResponse.getPublicKeyset().toByteArray(); 436 437 SignatureVerifyResponse verifyResponse = 438 signatureVerify(signatureStub, publicKeyset, "bad signature".getBytes(UTF_8), data); 439 assertThat(verifyResponse.getErr()).isNotEmpty(); 440 } 441 442 @Test signatureVerify_failsOnBadKeyset()443 public void signatureVerify_failsOnBadKeyset() throws Exception { 444 byte[] template = KeyTemplateProtoConverter.toByteArray( 445 EcdsaSignKeyManager.ecdsaP256Template()); 446 byte[] data = "The quick brown fox jumps over the lazy dog".getBytes(UTF_8); 447 448 KeysetGenerateResponse genResponse = generateKeyset(keysetStub, template); 449 assertThat(genResponse.getErr()).isEmpty(); 450 byte[] privateKeyset = genResponse.getKeyset().toByteArray(); 451 452 SignatureSignResponse signResponse = signatureSign(signatureStub, privateKeyset, data); 453 assertThat(signResponse.getErr()).isEmpty(); 454 byte[] signature = signResponse.getSignature().toByteArray(); 455 456 byte[] badKeyset = "bad keyset".getBytes(UTF_8); 457 SignatureVerifyResponse verifyResponse = 458 signatureVerify(signatureStub, badKeyset, signature, data); 459 assertThat(verifyResponse.getErr()).isNotEmpty(); 460 } 461 462 } 463