1 // Copyright 2017 Google Inc. 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 specified 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 org.junit.Assert.assertArrayEquals; 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertTrue; 23 24 import com.google.crypto.tink.Aead; 25 import com.google.crypto.tink.InsecureSecretKeyAccess; 26 import com.google.crypto.tink.KeysetHandle; 27 import com.google.crypto.tink.PrimitiveSet; 28 import com.google.crypto.tink.Registry; 29 import com.google.crypto.tink.TinkProtoKeysetFormat; 30 import com.google.crypto.tink.aead.AeadConfig; 31 import com.google.crypto.tink.daead.DeterministicAeadConfig; 32 import com.google.crypto.tink.internal.KeyTemplateProtoConverter; 33 import com.google.crypto.tink.mac.MacConfig; 34 import com.google.crypto.tink.monitoring.MonitoringAnnotations; 35 import com.google.crypto.tink.prf.PrfConfig; 36 import com.google.crypto.tink.proto.AesCtrHmacAeadKey; 37 import com.google.crypto.tink.proto.AesCtrHmacStreamingKey; 38 import com.google.crypto.tink.proto.AesCtrHmacStreamingParams; 39 import com.google.crypto.tink.proto.AesCtrKey; 40 import com.google.crypto.tink.proto.AesCtrParams; 41 import com.google.crypto.tink.proto.AesEaxKey; 42 import com.google.crypto.tink.proto.AesEaxParams; 43 import com.google.crypto.tink.proto.AesGcmHkdfStreamingKey; 44 import com.google.crypto.tink.proto.AesGcmHkdfStreamingParams; 45 import com.google.crypto.tink.proto.AesGcmKey; 46 import com.google.crypto.tink.proto.AesSivKey; 47 import com.google.crypto.tink.proto.EcPointFormat; 48 import com.google.crypto.tink.proto.EcdsaParams; 49 import com.google.crypto.tink.proto.EcdsaPrivateKey; 50 import com.google.crypto.tink.proto.EcdsaPublicKey; 51 import com.google.crypto.tink.proto.EcdsaSignatureEncoding; 52 import com.google.crypto.tink.proto.EciesAeadDemParams; 53 import com.google.crypto.tink.proto.EciesAeadHkdfParams; 54 import com.google.crypto.tink.proto.EciesAeadHkdfPrivateKey; 55 import com.google.crypto.tink.proto.EciesAeadHkdfPublicKey; 56 import com.google.crypto.tink.proto.EciesHkdfKemParams; 57 import com.google.crypto.tink.proto.EllipticCurveType; 58 import com.google.crypto.tink.proto.HashType; 59 import com.google.crypto.tink.proto.HkdfPrfKey; 60 import com.google.crypto.tink.proto.HkdfPrfParams; 61 import com.google.crypto.tink.proto.HmacKey; 62 import com.google.crypto.tink.proto.HmacKeyFormat; 63 import com.google.crypto.tink.proto.HmacParams; 64 import com.google.crypto.tink.proto.KeyData; 65 import com.google.crypto.tink.proto.KeyStatusType; 66 import com.google.crypto.tink.proto.KeyTemplate; 67 import com.google.crypto.tink.proto.KeyTypeEntry; 68 import com.google.crypto.tink.proto.Keyset; 69 import com.google.crypto.tink.proto.Keyset.Key; 70 import com.google.crypto.tink.proto.KeysetInfo; 71 import com.google.crypto.tink.proto.OutputPrefixType; 72 import com.google.crypto.tink.proto.RsaSsaPkcs1Params; 73 import com.google.crypto.tink.proto.RsaSsaPkcs1PublicKey; 74 import com.google.crypto.tink.proto.RsaSsaPssParams; 75 import com.google.crypto.tink.proto.RsaSsaPssPublicKey; 76 import com.google.crypto.tink.streamingaead.StreamingAeadConfig; 77 import com.google.crypto.tink.subtle.EllipticCurves; 78 import com.google.crypto.tink.subtle.Hex; 79 import com.google.crypto.tink.subtle.Random; 80 import com.google.errorprone.annotations.InlineMe; 81 import com.google.protobuf.ByteString; 82 import com.google.protobuf.ExtensionRegistryLite; 83 import com.google.protobuf.MessageLite; 84 import java.io.IOException; 85 import java.nio.ByteBuffer; 86 import java.security.GeneralSecurityException; 87 import java.security.KeyPair; 88 import java.security.KeyPairGenerator; 89 import java.security.NoSuchAlgorithmException; 90 import java.security.interfaces.ECPrivateKey; 91 import java.security.interfaces.ECPublicKey; 92 import java.security.spec.ECParameterSpec; 93 import java.security.spec.ECPoint; 94 import java.util.ArrayList; 95 import java.util.Arrays; 96 import java.util.List; 97 import javax.annotation.Nullable; 98 import javax.crypto.Cipher; 99 100 /** Test helpers. */ 101 public final class TestUtil { 102 /** A place holder to keep mutated bytes and its description. */ 103 public static class BytesMutation { 104 public byte[] value; 105 public String description; 106 BytesMutation(byte[] value, String description)107 public BytesMutation(byte[] value, String description) { 108 this.value = value; 109 this.description = description; 110 } 111 } 112 113 // This GCP KMS CryptoKey is restricted to the service account in {@code SERVICE_ACCOUNT_FILE}. 114 public static final String GCP_KMS_TEST_KEY_URI = 115 String.format( 116 "gcp-kms://projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", 117 "tink-test-infrastructure", "global", "unit-and-integration-testing", "aead-key"); 118 119 // This is a credential of a service account that is granted access to 120 // {@code RESTRICTED_CRYPTO_KEY_URI}. 121 public static final String SERVICE_ACCOUNT_FILE = "testdata/gcp/credential.json"; 122 123 // This AWS KMS CryptoKey is restricted to Google use only and {@code AWS_CREDS}. 124 public static final String AWS_KMS_TEST_KEY_URI = 125 "aws-kms://arn:aws:kms:us-east-2:235739564943:key/3ee50705-5a82-4f5b-9753-05c4f473922f"; 126 127 // This is a credential for the AWS service account with granted access to 128 // {@code AWS_KMS_TEST_KEY_URI}. 129 public static final String AWS_CREDS = "testdata/aws/credentials.cred"; 130 131 /** A dummy Aead-implementation that just throws exception. */ 132 public static class DummyAead implements Aead { DummyAead()133 public DummyAead() {} 134 135 @Override encrypt(byte[] plaintext, byte[] aad)136 public byte[] encrypt(byte[] plaintext, byte[] aad) throws GeneralSecurityException { 137 throw new GeneralSecurityException("dummy"); 138 } 139 140 @Override decrypt(byte[] ciphertext, byte[] aad)141 public byte[] decrypt(byte[] ciphertext, byte[] aad) throws GeneralSecurityException { 142 throw new GeneralSecurityException("dummy"); 143 } 144 } 145 146 /** @return a {@code PrimitiveSet} from a {@code KeySet} */ createPrimitiveSet(Keyset keyset, Class<P> inputClass)147 public static <P> PrimitiveSet<P> createPrimitiveSet(Keyset keyset, Class<P> inputClass) 148 throws GeneralSecurityException { 149 return createPrimitiveSetWithAnnotations(keyset, null, inputClass); 150 } 151 152 /** 153 * @return a {@code PrimitiveSet} from a {@code KeySet} 154 */ createPrimitiveSetWithAnnotations( Keyset keyset, @Nullable MonitoringAnnotations annotations, Class<P> inputClass)155 public static <P> PrimitiveSet<P> createPrimitiveSetWithAnnotations( 156 Keyset keyset, @Nullable MonitoringAnnotations annotations, Class<P> inputClass) 157 throws GeneralSecurityException { 158 PrimitiveSet.Builder<P> builder = PrimitiveSet.newBuilder(inputClass); 159 if (annotations != null) { 160 builder.setAnnotations(annotations); 161 } 162 for (Keyset.Key key : keyset.getKeyList()) { 163 if (key.getStatus() == KeyStatusType.ENABLED) { 164 P primitive = Registry.getPrimitive(key.getKeyData(), inputClass); 165 if (key.getKeyId() == keyset.getPrimaryKeyId()) { 166 builder.addPrimaryPrimitive(primitive, key); 167 } else { 168 builder.addPrimitive(primitive, key); 169 } 170 } 171 } 172 return builder.build(); 173 } 174 175 /** 176 * @return a {@code Keyset} from a {@code handle}. 177 * @deprecated The return value of this function is a Keyset and typically should not be used. 178 * Instead, operate on the KeysetHandle directly. 179 */ 180 @Deprecated getKeyset(final KeysetHandle handle)181 public static Keyset getKeyset(final KeysetHandle handle) { 182 try { 183 return Keyset.parseFrom( 184 TinkProtoKeysetFormat.serializeKeyset(handle, InsecureSecretKeyAccess.get()), 185 ExtensionRegistryLite.getEmptyRegistry()); 186 } catch (GeneralSecurityException | IOException e) { 187 throw new RuntimeException(e); 188 } 189 } 190 191 /** @return a keyset handle from a {@code keyset}. */ createKeysetHandle(Keyset keyset)192 public static KeysetHandle createKeysetHandle(Keyset keyset) throws Exception { 193 return TinkProtoKeysetFormat.parseKeyset(keyset.toByteArray(), InsecureSecretKeyAccess.get()); 194 } 195 196 /** @return a keyset from a list of keys. The first key is primary. */ createKeyset(Key primary, Key... keys)197 public static Keyset createKeyset(Key primary, Key... keys) throws Exception { 198 Keyset.Builder builder = Keyset.newBuilder(); 199 builder.addKey(primary).setPrimaryKeyId(primary.getKeyId()); 200 for (Key key : keys) { 201 builder.addKey(key); 202 } 203 return builder.build(); 204 } 205 206 /** @return a KeyTemplate with an non-existing type url. */ createKeyTemplateWithNonExistingTypeUrl()207 public static KeyTemplate createKeyTemplateWithNonExistingTypeUrl() throws Exception { 208 return KeyTemplate.newBuilder().setTypeUrl("does-not-exist").build(); 209 } 210 211 /** @return a key with some specified properties. */ createKey( KeyData keyData, int keyId, KeyStatusType status, OutputPrefixType prefixType)212 public static Key createKey( 213 KeyData keyData, int keyId, KeyStatusType status, OutputPrefixType prefixType) 214 throws Exception { 215 return Key.newBuilder() 216 .setKeyData(keyData) 217 .setStatus(status) 218 .setKeyId(keyId) 219 .setOutputPrefixType(prefixType) 220 .build(); 221 } 222 223 /** @return a {@code HmacKey}. */ createHmacKey(byte[] keyValue, int tagSize)224 public static HmacKey createHmacKey(byte[] keyValue, int tagSize) throws Exception { 225 HmacParams params = 226 HmacParams.newBuilder().setHash(HashType.SHA256).setTagSize(tagSize).build(); 227 228 return HmacKey.newBuilder() 229 .setParams(params) 230 .setKeyValue(ByteString.copyFrom(keyValue)) 231 .build(); 232 } 233 234 /** 235 * @return a {@code HkdfPrfKey}. 236 * @deprecated Do not use this function 237 */ 238 @Deprecated createPrfKey(byte[] keyValue)239 public static HkdfPrfKey createPrfKey(byte[] keyValue) throws Exception { 240 HkdfPrfParams params = HkdfPrfParams.newBuilder().setHash(HashType.SHA256).build(); 241 242 return HkdfPrfKey.newBuilder() 243 .setParams(params) 244 .setKeyValue(ByteString.copyFrom(keyValue)) 245 .build(); 246 } 247 248 /** @return a {@code KeyData} from a specified key. */ createKeyData(MessageLite key, String typeUrl, KeyData.KeyMaterialType type)249 public static KeyData createKeyData(MessageLite key, String typeUrl, KeyData.KeyMaterialType type) 250 throws Exception { 251 return KeyData.newBuilder() 252 .setValue(key.toByteString()) 253 .setTypeUrl(typeUrl) 254 .setKeyMaterialType(type) 255 .build(); 256 } 257 258 /** @return a {@code KeyData} containing a {@code HmacKey}. */ createHmacKeyData(byte[] keyValue, int tagSize)259 public static KeyData createHmacKeyData(byte[] keyValue, int tagSize) throws Exception { 260 return createKeyData( 261 createHmacKey(keyValue, tagSize), 262 MacConfig.HMAC_TYPE_URL, 263 KeyData.KeyMaterialType.SYMMETRIC); 264 } 265 266 /** @return a {@code KeyData} containing a {@code HkdfPrfKey}. */ createPrfKeyData(byte[] keyValue)267 public static KeyData createPrfKeyData(byte[] keyValue) throws Exception { 268 return createKeyData( 269 createPrfKey(keyValue), PrfConfig.PRF_TYPE_URL, KeyData.KeyMaterialType.SYMMETRIC); 270 } 271 272 /** @return a {@code AesCtrKey}. */ createAesCtrKey(byte[] keyValue, int ivSize)273 public static AesCtrKey createAesCtrKey(byte[] keyValue, int ivSize) throws Exception { 274 AesCtrParams aesCtrParams = AesCtrParams.newBuilder().setIvSize(ivSize).build(); 275 return AesCtrKey.newBuilder() 276 .setParams(aesCtrParams) 277 .setKeyValue(ByteString.copyFrom(keyValue)) 278 .build(); 279 } 280 281 /** @return a {@code KeyData} containing a {@code AesCtrHmacStreamingKey}. */ createAesCtrHmacStreamingKeyData( byte[] keyValue, int derivedKeySize, int ciphertextSegmentSize)282 public static KeyData createAesCtrHmacStreamingKeyData( 283 byte[] keyValue, int derivedKeySize, int ciphertextSegmentSize) throws Exception { 284 HmacParams hmacParams = HmacParams.newBuilder().setHash(HashType.SHA256).setTagSize(16).build(); 285 AesCtrHmacStreamingParams keyParams = 286 AesCtrHmacStreamingParams.newBuilder() 287 .setCiphertextSegmentSize(ciphertextSegmentSize) 288 .setDerivedKeySize(derivedKeySize) 289 .setHkdfHashType(HashType.SHA256) 290 .setHmacParams(hmacParams) 291 .build(); 292 AesCtrHmacStreamingKey keyProto = 293 AesCtrHmacStreamingKey.newBuilder() 294 .setVersion(0) 295 .setKeyValue(ByteString.copyFrom(keyValue)) 296 .setParams(keyParams) 297 .build(); 298 return createKeyData( 299 keyProto, 300 StreamingAeadConfig.AES_CTR_HMAC_STREAMINGAEAD_TYPE_URL, 301 KeyData.KeyMaterialType.SYMMETRIC); 302 } 303 304 /** @return a {@code KeyData} containing a {@code AesGcmHkdfStreamingKey}. */ createAesGcmHkdfStreamingKeyData( byte[] keyValue, int derivedKeySize, int ciphertextSegmentSize)305 public static KeyData createAesGcmHkdfStreamingKeyData( 306 byte[] keyValue, int derivedKeySize, int ciphertextSegmentSize) throws Exception { 307 AesGcmHkdfStreamingParams keyParams = 308 AesGcmHkdfStreamingParams.newBuilder() 309 .setCiphertextSegmentSize(ciphertextSegmentSize) 310 .setDerivedKeySize(derivedKeySize) 311 .setHkdfHashType(HashType.SHA256) 312 .build(); 313 AesGcmHkdfStreamingKey keyProto = 314 AesGcmHkdfStreamingKey.newBuilder() 315 .setVersion(0) 316 .setKeyValue(ByteString.copyFrom(keyValue)) 317 .setParams(keyParams) 318 .build(); 319 return createKeyData( 320 keyProto, 321 StreamingAeadConfig.AES_GCM_HKDF_STREAMINGAEAD_TYPE_URL, 322 KeyData.KeyMaterialType.SYMMETRIC); 323 } 324 325 /** 326 * @return a {@code KeyData} containing a {@code AesCtrHmacAeadKey}. 327 * @deprecated Do not use this function 328 */ 329 @Deprecated createAesCtrHmacAeadKeyData( byte[] aesCtrKeyValue, int ivSize, byte[] hmacKeyValue, int tagSize)330 public static KeyData createAesCtrHmacAeadKeyData( 331 byte[] aesCtrKeyValue, int ivSize, byte[] hmacKeyValue, int tagSize) throws Exception { 332 AesCtrKey aesCtrKey = createAesCtrKey(aesCtrKeyValue, ivSize); 333 HmacKey hmacKey = createHmacKey(hmacKeyValue, tagSize); 334 335 AesCtrHmacAeadKey keyProto = 336 AesCtrHmacAeadKey.newBuilder().setAesCtrKey(aesCtrKey).setHmacKey(hmacKey).build(); 337 return createKeyData( 338 keyProto, AeadConfig.AES_CTR_HMAC_AEAD_TYPE_URL, KeyData.KeyMaterialType.SYMMETRIC); 339 } 340 341 /** @return a {@code KeyData} containing a {@code AesSivKey}. */ createAesSivKeyData(int keySize)342 public static KeyData createAesSivKeyData(int keySize) throws Exception { 343 AesSivKey keyProto = 344 AesSivKey.newBuilder().setKeyValue(ByteString.copyFrom(Random.randBytes(keySize))).build(); 345 return TestUtil.createKeyData( 346 keyProto, DeterministicAeadConfig.AES_SIV_TYPE_URL, KeyData.KeyMaterialType.SYMMETRIC); 347 } 348 349 /** @return a {@code KeyData} containing a {@code AesGcmKey}. */ createAesGcmKeyData(byte[] keyValue)350 public static KeyData createAesGcmKeyData(byte[] keyValue) throws Exception { 351 AesGcmKey keyProto = AesGcmKey.newBuilder().setKeyValue(ByteString.copyFrom(keyValue)).build(); 352 return createKeyData(keyProto, AeadConfig.AES_GCM_TYPE_URL, KeyData.KeyMaterialType.SYMMETRIC); 353 } 354 355 /** 356 * @return a {@code KeyData} containing a {@code AesEaxKey}. 357 * @deprecated DO not use this function. 358 */ 359 @Deprecated createAesEaxKeyData(byte[] keyValue, int ivSizeInBytes)360 public static KeyData createAesEaxKeyData(byte[] keyValue, int ivSizeInBytes) 361 throws Exception { 362 AesEaxKey keyProto = 363 AesEaxKey.newBuilder() 364 .setKeyValue(ByteString.copyFrom(keyValue)) 365 .setParams(AesEaxParams.newBuilder().setIvSize(ivSizeInBytes).build()) 366 .build(); 367 return createKeyData(keyProto, AeadConfig.AES_EAX_TYPE_URL, KeyData.KeyMaterialType.SYMMETRIC); 368 } 369 370 /** @return a KMS key URI in a format defined by Google Cloud KMS. */ createGcpKmsKeyUri( String projectId, String location, String ringId, String keyId)371 public static String createGcpKmsKeyUri( 372 String projectId, String location, String ringId, String keyId) { 373 return String.format( 374 "projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", projectId, location, ringId, keyId); 375 } 376 377 /** 378 * @return a {@code EcdsaPrivateKey} constructed from {@code EcdsaPublicKey} and the byte array of 379 * private key. 380 */ createEcdsaPrivKey(EcdsaPublicKey pubKey, byte[] privKey)381 public static EcdsaPrivateKey createEcdsaPrivKey(EcdsaPublicKey pubKey, byte[] privKey) { 382 final int version = 0; 383 return EcdsaPrivateKey.newBuilder() 384 .setVersion(version) 385 .setPublicKey(pubKey) 386 .setKeyValue(ByteString.copyFrom(privKey)) 387 .build(); 388 } 389 390 /** 391 * @return a {@code EcdsaPublicKey} constructed from {@code EllipticCurveType} and {@code 392 * HashType}. 393 */ generateEcdsaPubKey( EllipticCurveType curve, HashType hashType, EcdsaSignatureEncoding encoding)394 public static EcdsaPublicKey generateEcdsaPubKey( 395 EllipticCurveType curve, HashType hashType, EcdsaSignatureEncoding encoding) 396 throws Exception { 397 EcdsaPrivateKey privKey = generateEcdsaPrivKey(curve, hashType, encoding); 398 return privKey.getPublicKey(); 399 } 400 401 /** 402 * @return a {@code EcdsaPrivateKey} constructed from {@code EllipticCurveType} and {@code 403 * HashType}. 404 */ generateEcdsaPrivKey( EllipticCurveType curve, HashType hashType, EcdsaSignatureEncoding encoding)405 public static EcdsaPrivateKey generateEcdsaPrivKey( 406 EllipticCurveType curve, HashType hashType, EcdsaSignatureEncoding encoding) 407 throws Exception { 408 ECParameterSpec ecParams; 409 switch (curve) { 410 case NIST_P256: 411 ecParams = EllipticCurves.getNistP256Params(); 412 break; 413 case NIST_P384: 414 ecParams = EllipticCurves.getNistP384Params(); 415 break; 416 case NIST_P521: 417 ecParams = EllipticCurves.getNistP521Params(); 418 break; 419 default: 420 throw new NoSuchAlgorithmException("Curve not implemented:" + curve); 421 } 422 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); 423 keyGen.initialize(ecParams); 424 KeyPair keyPair = keyGen.generateKeyPair(); 425 ECPublicKey pubKey = (ECPublicKey) keyPair.getPublic(); 426 ECPrivateKey privKey = (ECPrivateKey) keyPair.getPrivate(); 427 ECPoint w = pubKey.getW(); 428 EcdsaPublicKey ecdsaPubKey = 429 createEcdsaPubKey( 430 hashType, curve, encoding, w.getAffineX().toByteArray(), w.getAffineY().toByteArray()); 431 432 return createEcdsaPrivKey(ecdsaPubKey, privKey.getS().toByteArray()); 433 } 434 435 /** 436 * @return a {@code EcdsaPublicKey} constructed from {@code HashType}, {@code EllipticCurveType} 437 * and affine coordinates of the public key. 438 */ createEcdsaPubKey( HashType hashType, EllipticCurveType curve, EcdsaSignatureEncoding encoding, byte[] pubX, byte[] pubY)439 public static EcdsaPublicKey createEcdsaPubKey( 440 HashType hashType, 441 EllipticCurveType curve, 442 EcdsaSignatureEncoding encoding, 443 byte[] pubX, 444 byte[] pubY) 445 throws Exception { 446 final int version = 0; 447 EcdsaParams ecdsaParams = 448 EcdsaParams.newBuilder() 449 .setHashType(hashType) 450 .setCurve(curve) 451 .setEncoding(encoding) 452 .build(); 453 return EcdsaPublicKey.newBuilder() 454 .setVersion(version) 455 .setParams(ecdsaParams) 456 .setX(ByteString.copyFrom(pubX)) 457 .setY(ByteString.copyFrom(pubY)) 458 .build(); 459 } 460 461 /** 462 * @return a {@code RsaSsaPkcs1PublicKey} constructed from {@code modulus}, {@code exponent} and 463 * {@code hashType}. 464 */ createRsaSsaPkcs1PubKey( byte[] modulus, byte[] exponent, HashType hashType)465 public static RsaSsaPkcs1PublicKey createRsaSsaPkcs1PubKey( 466 byte[] modulus, byte[] exponent, HashType hashType) throws Exception { 467 final int version = 0; 468 RsaSsaPkcs1Params params = RsaSsaPkcs1Params.newBuilder().setHashType(hashType).build(); 469 470 return RsaSsaPkcs1PublicKey.newBuilder() 471 .setVersion(version) 472 .setParams(params) 473 .setN(ByteString.copyFrom(modulus)) 474 .setE(ByteString.copyFrom(exponent)) 475 .build(); 476 } 477 478 /** 479 * Returns a {@code RsaSsaPssPublicKey} constructed from {@code modulus}, {@code exponent}, {@code 480 * sigHash}, {@code mgf1Hash} and {@code saltLength}. 481 */ createRsaSsaPssPubKey( byte[] modulus, byte[] exponent, HashType sigHash, HashType mgf1Hash, int saltLength)482 public static RsaSsaPssPublicKey createRsaSsaPssPubKey( 483 byte[] modulus, byte[] exponent, HashType sigHash, HashType mgf1Hash, int saltLength) 484 throws Exception { 485 final int version = 0; 486 RsaSsaPssParams params = 487 RsaSsaPssParams.newBuilder() 488 .setSigHash(sigHash) 489 .setMgf1Hash(mgf1Hash) 490 .setSaltLength(saltLength) 491 .build(); 492 493 return RsaSsaPssPublicKey.newBuilder() 494 .setVersion(version) 495 .setParams(params) 496 .setN(ByteString.copyFrom(modulus)) 497 .setE(ByteString.copyFrom(exponent)) 498 .build(); 499 } 500 /** 501 * @return a freshly generated {@code EciesAeadHkdfPrivateKey} constructed with specified 502 * parameters. 503 */ generateEciesAeadHkdfPrivKey( EllipticCurveType curve, HashType hashType, EcPointFormat pointFormat, KeyTemplate demKeyTemplate, byte[] salt)504 public static EciesAeadHkdfPrivateKey generateEciesAeadHkdfPrivKey( 505 EllipticCurveType curve, 506 HashType hashType, 507 EcPointFormat pointFormat, 508 KeyTemplate demKeyTemplate, 509 byte[] salt) 510 throws Exception { 511 ECParameterSpec ecParams; 512 switch (curve) { 513 case NIST_P256: 514 ecParams = EllipticCurves.getNistP256Params(); 515 break; 516 case NIST_P384: 517 ecParams = EllipticCurves.getNistP384Params(); 518 break; 519 case NIST_P521: 520 ecParams = EllipticCurves.getNistP521Params(); 521 break; 522 default: 523 throw new NoSuchAlgorithmException("Curve not implemented:" + curve); 524 } 525 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); 526 keyGen.initialize(ecParams); 527 KeyPair keyPair = keyGen.generateKeyPair(); 528 ECPublicKey pubKey = (ECPublicKey) keyPair.getPublic(); 529 ECPrivateKey privKey = (ECPrivateKey) keyPair.getPrivate(); 530 ECPoint w = pubKey.getW(); 531 EciesAeadHkdfPublicKey eciesPubKey = 532 createEciesAeadHkdfPubKey( 533 curve, 534 hashType, 535 pointFormat, 536 demKeyTemplate, 537 w.getAffineX().toByteArray(), 538 w.getAffineY().toByteArray(), 539 salt); 540 return createEciesAeadHkdfPrivKey(eciesPubKey, privKey.getS().toByteArray()); 541 } 542 543 /** 544 * @return a {@code KeyData} containing a {@code EciesAeadHkdfPrivateKey} with the specified key 545 * material and parameters. 546 * @deprecated Do not use this function 547 */ 548 @Deprecated createEciesAeadHkdfPrivKey( EciesAeadHkdfPublicKey pubKey, byte[] privKeyValue)549 public static EciesAeadHkdfPrivateKey createEciesAeadHkdfPrivKey( 550 EciesAeadHkdfPublicKey pubKey, byte[] privKeyValue) throws Exception { 551 final int version = 0; 552 return EciesAeadHkdfPrivateKey.newBuilder() 553 .setVersion(version) 554 .setPublicKey(pubKey) 555 .setKeyValue(ByteString.copyFrom(privKeyValue)) 556 .build(); 557 } 558 createEciesAeadHkdfParams( EllipticCurveType curve, HashType hashType, EcPointFormat ecPointFormat, KeyTemplate demKeyTemplate, byte[] salt)559 private static EciesAeadHkdfParams createEciesAeadHkdfParams( 560 EllipticCurveType curve, 561 HashType hashType, 562 EcPointFormat ecPointFormat, 563 KeyTemplate demKeyTemplate, 564 byte[] salt) { 565 EciesHkdfKemParams kemParams = 566 EciesHkdfKemParams.newBuilder() 567 .setCurveType(curve) 568 .setHkdfHashType(hashType) 569 .setHkdfSalt(ByteString.copyFrom(salt)) 570 .build(); 571 EciesAeadDemParams demParams = 572 EciesAeadDemParams.newBuilder().setAeadDem(demKeyTemplate).build(); 573 return EciesAeadHkdfParams.newBuilder() 574 .setKemParams(kemParams) 575 .setDemParams(demParams) 576 .setEcPointFormat(ecPointFormat) 577 .build(); 578 } 579 580 /** 581 * @return a {@code EciesAeadHkdfPublicKey} with the specified key material and parameters. 582 * @deprecated Do not use this function. 583 */ 584 @Deprecated createEciesAeadHkdfPubKey( EllipticCurveType curve, HashType hashType, EcPointFormat ecPointFormat, KeyTemplate demKeyTemplate, byte[] pubX, byte[] pubY, byte[] salt)585 public static EciesAeadHkdfPublicKey createEciesAeadHkdfPubKey( 586 EllipticCurveType curve, 587 HashType hashType, 588 EcPointFormat ecPointFormat, 589 KeyTemplate demKeyTemplate, 590 byte[] pubX, 591 byte[] pubY, 592 byte[] salt) 593 throws Exception { 594 final int version = 0; 595 EciesAeadHkdfParams params = 596 createEciesAeadHkdfParams(curve, hashType, ecPointFormat, demKeyTemplate, salt); 597 return EciesAeadHkdfPublicKey.newBuilder() 598 .setVersion(version) 599 .setParams(params) 600 .setX(ByteString.copyFrom(pubX)) 601 .setY(ByteString.copyFrom(pubY)) 602 .build(); 603 } 604 605 /** Runs basic tests against an Aead primitive. */ runBasicAeadTests(Aead aead)606 public static void runBasicAeadTests(Aead aead) throws Exception { 607 byte[] plaintext = Random.randBytes(20); 608 byte[] associatedData = Random.randBytes(20); 609 byte[] ciphertext = aead.encrypt(plaintext, associatedData); 610 byte[] decrypted = aead.decrypt(ciphertext, associatedData); 611 assertArrayEquals(plaintext, decrypted); 612 } 613 614 /** 615 * Decodes hex string. 616 * 617 * @deprecated Usages should be inlined. 618 */ 619 @InlineMe( 620 replacement = "Hex.decode(hexData)", 621 imports = {"com.google.crypto.tink.subtle.Hex"}) 622 @Deprecated hexDecode(String hexData)623 public static byte[] hexDecode(String hexData) { 624 return Hex.decode(hexData); 625 } 626 627 /** 628 * Encodes bytes to hex string. 629 * 630 * @deprecated Usages should be inlined. 631 */ 632 @InlineMe( 633 replacement = "Hex.encode(data)", 634 imports = {"com.google.crypto.tink.subtle.Hex"}) 635 @Deprecated hexEncode(byte[] data)636 public static String hexEncode(byte[] data) { 637 return Hex.encode(data); 638 } 639 640 /** @return true iff two arrays are equal. */ arrayEquals(byte[] a, byte[] b)641 public static boolean arrayEquals(byte[] a, byte[] b) { 642 if (a.length != b.length) { 643 return false; 644 } 645 byte res = 0; 646 for (int i = 0; i < a.length; i++) { 647 res |= (byte) (a[i] ^ b[i]); 648 } 649 return res == 0; 650 } 651 652 /** 653 * Best-effort checks that this is Android. 654 * 655 * @return true if running on Android. 656 */ isAndroid()657 public static boolean isAndroid() { 658 // https://developer.android.com/reference/java/lang/System#getProperties%28%29 659 return "The Android Project".equals(System.getProperty("java.vendor")); 660 } 661 662 /** 663 * Check that this is running in Remote Build Execution. 664 * 665 * @return true if running on Remote Build Execution. 666 * @deprecated This isn't supported anymore 667 */ 668 @Deprecated isRemoteBuildExecution()669 public static boolean isRemoteBuildExecution() { 670 return false; 671 } 672 673 /** 674 * Best-effort checks that this is running under tsan. Returns false in doubt and externally to 675 * google. 676 */ isTsan()677 public static boolean isTsan() { 678 return false; 679 } 680 681 /** 682 * Returns whether we should skip a test with some AES key size. 683 * 684 * @deprecated Do not call this function. If you have any instance, you probably want to use 685 * "false" instead. 686 */ 687 @Deprecated shouldSkipTestWithAesKeySize(int keySizeInBytes)688 public static boolean shouldSkipTestWithAesKeySize(int keySizeInBytes) 689 throws NoSuchAlgorithmException { 690 int maxKeySize = Cipher.getMaxAllowedKeyLength("AES/CTR/NoPadding"); 691 if ((keySizeInBytes * 8) > maxKeySize) { 692 System.out.println( 693 String.format( 694 "Unlimited Strength Jurisdiction Policy Files are required" 695 + " but not installed. Skip tests with keys larger than %s bits.", 696 maxKeySize)); 697 return true; 698 } 699 // Android is using Conscrypt as its default JCE provider, but Conscrypt 700 // does not support 192-bit keys. 701 if (isAndroid() && keySizeInBytes == 24) { 702 System.out.println("Skipping tests with 192-bit keys on Android"); 703 return true; 704 } 705 706 return false; 707 } 708 709 /** 710 * Assertion that an exception's message contains the right message. When this fails, the 711 * exception's message and the expected value will be in the failure log. 712 */ assertExceptionContains(Throwable e, String contains)713 public static void assertExceptionContains(Throwable e, String contains) { 714 String message = 715 String.format( 716 "Got exception with message \"%s\", expected it to contain \"%s\".", 717 e.getMessage(), contains); 718 assertTrue(message, e.getMessage().contains(contains)); 719 } 720 721 /** 722 * Asserts that {@code key} is generated from {@code keyTemplate}. 723 * 724 * @deprecated Do not use this function. 725 */ 726 @Deprecated assertHmacKey( com.google.crypto.tink.KeyTemplate keyTemplate, Keyset.Key key)727 public static void assertHmacKey( 728 com.google.crypto.tink.KeyTemplate keyTemplate, Keyset.Key key) throws Exception { 729 KeyTemplate protoTemplate = KeyTemplateProtoConverter.toProto(keyTemplate); 730 731 assertThat(key.getKeyId()).isGreaterThan(0); 732 assertThat(key.getStatus()).isEqualTo(KeyStatusType.ENABLED); 733 assertThat(key.getOutputPrefixType()).isEqualTo(OutputPrefixType.TINK); 734 assertThat(key.hasKeyData()).isTrue(); 735 assertThat(key.getKeyData().getTypeUrl()).isEqualTo(protoTemplate.getTypeUrl()); 736 737 HmacKeyFormat hmacKeyFormat = 738 HmacKeyFormat.parseFrom(protoTemplate.getValue(), ExtensionRegistryLite.getEmptyRegistry()); 739 HmacKey hmacKey = 740 HmacKey.parseFrom(key.getKeyData().getValue(), ExtensionRegistryLite.getEmptyRegistry()); 741 assertThat(hmacKey.getParams()).isEqualTo(hmacKeyFormat.getParams()); 742 assertThat(hmacKey.getKeyValue().size()).isEqualTo(hmacKeyFormat.getKeySize()); 743 } 744 745 /** 746 * Asserts that {@code KeyInfo} is corresponding to a key from {@code keyTemplate}. 747 * 748 * @deprecated Do not use this function. 749 */ 750 @Deprecated assertKeyInfo( com.google.crypto.tink.KeyTemplate keyTemplate, KeysetInfo.KeyInfo keyInfo)751 public static void assertKeyInfo( 752 com.google.crypto.tink.KeyTemplate keyTemplate, KeysetInfo.KeyInfo keyInfo) throws Exception { 753 assertThat(keyInfo.getKeyId()).isGreaterThan(0); 754 com.google.crypto.tink.proto.KeyTemplate protoTemplate = 755 KeyTemplateProtoConverter.toProto(keyTemplate); 756 assertThat(keyInfo.getTypeUrl()).isEqualTo(protoTemplate.getTypeUrl()); 757 assertThat(keyInfo.getStatus()).isEqualTo(KeyStatusType.ENABLED); 758 assertThat(keyInfo.getOutputPrefixType()).isEqualTo(OutputPrefixType.TINK); 759 } 760 761 /** 762 * Replacement for org.junit.Assert.assertEquals, since org.junit.Assert.assertEquals is quite 763 * slow. 764 */ assertByteArrayEquals(String txt, byte[] expected, byte[] actual)765 public static void assertByteArrayEquals(String txt, byte[] expected, byte[] actual) 766 throws Exception { 767 assertEquals(txt + " arrays not of the same length", expected.length, actual.length); 768 for (int i = 0; i < expected.length; i++) { 769 if (expected[i] != actual[i]) { 770 assertEquals(txt + " difference at position:" + i, expected[i], actual[i]); 771 } 772 } 773 } 774 assertByteArrayEquals(byte[] expected, byte[] actual)775 public static void assertByteArrayEquals(byte[] expected, byte[] actual) throws Exception { 776 assertByteArrayEquals("", expected, actual); 777 } 778 779 /** 780 * Checks whether the bytes from buffer.position() to buffer.limit() are the same bytes as 781 * expected. 782 */ assertByteBufferContains(String txt, byte[] expected, ByteBuffer buffer)783 public static void assertByteBufferContains(String txt, byte[] expected, ByteBuffer buffer) 784 throws Exception { 785 assertEquals( 786 txt + " unexpected number of bytes in buffer", expected.length, buffer.remaining()); 787 byte[] content = new byte[buffer.remaining()]; 788 buffer.duplicate().get(content); 789 assertByteArrayEquals(txt, expected, content); 790 } 791 assertByteBufferContains(byte[] expected, ByteBuffer buffer)792 public static void assertByteBufferContains(byte[] expected, ByteBuffer buffer) throws Exception { 793 assertByteBufferContains("", expected, buffer); 794 } 795 796 /** 797 * Verifies that the given entry has the specified contents. 798 * 799 * @deprecated Do not use this function. 800 */ 801 @Deprecated verifyConfigEntry( KeyTypeEntry entry, String catalogueName, String primitiveName, String typeUrl, Boolean newKeyAllowed, int keyManagerVersion)802 public static void verifyConfigEntry( 803 KeyTypeEntry entry, 804 String catalogueName, 805 String primitiveName, 806 String typeUrl, 807 Boolean newKeyAllowed, 808 int keyManagerVersion) { 809 assertEquals(catalogueName, entry.getCatalogueName()); 810 assertEquals(primitiveName, entry.getPrimitiveName()); 811 assertEquals(typeUrl, entry.getTypeUrl()); 812 assertEquals(newKeyAllowed, entry.getNewKeyAllowed()); 813 assertEquals(keyManagerVersion, entry.getKeyManagerVersion()); 814 } 815 816 /** Convert an array of long to an array of int. */ twoCompInt(long[] a)817 public static int[] twoCompInt(long[] a) { 818 int[] ret = new int[a.length]; 819 for (int i = 0; i < a.length; i++) { 820 ret[i] = (int) (a[i] - (a[i] > Integer.MAX_VALUE ? (1L << 32) : 0)); 821 } 822 return ret; 823 } 824 825 /** 826 * Generates mutations of {@code bytes}, e.g., flipping bits and truncating. 827 * 828 * @return a list of pairs of mutated value and mutation description. 829 */ generateMutations(byte[] bytes)830 public static List<BytesMutation> generateMutations(byte[] bytes) { 831 List<BytesMutation> res = new ArrayList<>(); 832 833 // Flip bits. 834 for (int i = 0; i < bytes.length; i++) { 835 for (int j = 0; j < 8; j++) { 836 byte[] modifiedBytes = Arrays.copyOf(bytes, bytes.length); 837 modifiedBytes[i] = (byte) (modifiedBytes[i] ^ (1 << j)); 838 res.add(new BytesMutation(modifiedBytes, String.format("Flip bit %d of data", i))); 839 } 840 } 841 842 // Truncate bytes. 843 for (int i = 0; i < bytes.length; i++) { 844 byte[] modifiedBytes = Arrays.copyOf(bytes, i); 845 res.add(new BytesMutation(modifiedBytes, String.format("Truncate upto %d bytes of data", i))); 846 } 847 848 // Append an extra byte. 849 res.add(new BytesMutation(Arrays.copyOf(bytes, bytes.length + 1), "Append an extra zero byte")); 850 return res; 851 } 852 853 854 /** 855 * Uses a z test on the given byte string, expecting all bits to be uniformly set with probability 856 * 1/2. Returns non ok status if the z test fails by more than 10 standard deviations. 857 * 858 * <p>With less statistics jargon: This counts the number of bits set and expects the number to be 859 * roughly half of the length of the string. The law of large numbers suggests that we can assume 860 * that the longer the string is, the more accurate that estimate becomes for a random string. 861 * This test is useful to detect things like strings that are entirely zero. 862 * 863 * <p>Note: By itself, this is a very weak test for randomness. 864 * 865 * @throws GeneralSecurityException if uniformity error is detected, otherwise returns normally. 866 */ ztestUniformString(byte[] string)867 public static void ztestUniformString(byte[] string) throws GeneralSecurityException { 868 final double minAcceptableStdDevs = 10.0; 869 double totalBits = string.length * 8; 870 double expected = totalBits / 2.0; 871 double stddev = Math.sqrt(totalBits / 4.0); 872 873 // This test is very limited at low string lengths. Below a certain threshold it tests nothing. 874 if (expected < stddev * minAcceptableStdDevs) { 875 throw new GeneralSecurityException( 876 "Test will always succeed with strings of the given length " 877 + string.length 878 + ". Use more bytes."); 879 } 880 881 long numSetBits = 0; 882 for (byte b : string) { 883 int unsignedInt = toUnsignedInt(b); 884 // Counting the number of bits set in byte: 885 while (unsignedInt != 0) { 886 numSetBits++; 887 unsignedInt = (unsignedInt & (unsignedInt - 1)); 888 } 889 } 890 // Check that the number of bits is within 10 stddevs. 891 if (Math.abs((double) numSetBits - expected) < minAcceptableStdDevs * stddev) { 892 return; 893 } 894 throw new GeneralSecurityException( 895 "Z test for uniformly distributed variable out of bounds; " 896 + "Actual number of set bits was " 897 + numSetBits 898 + " expected was " 899 + expected 900 + " 10 * standard deviation is 10 * " 901 + stddev 902 + " = " 903 + 10.0 * stddev); 904 } 905 906 /** 907 * Tests that the crosscorrelation of two strings of equal length points to independent and 908 * uniformly distributed strings. Returns non ok status if the z test fails by more than 10 909 * standard deviations. 910 * 911 * <p>With less statistics jargon: This xors two strings and then performs the ZTestUniformString 912 * on the result. If the two strings are independent and uniformly distributed, the xor'ed string 913 * is as well. A cross correlation test will find whether two strings overlap more or less than it 914 * would be expected. 915 * 916 * <p>Note: Having a correlation of zero is only a necessary but not sufficient condition for 917 * independence. 918 * 919 * @throws GeneralSecurityException if uniformity error is detected, otherwise returns normally. 920 */ ztestCrossCorrelationUniformStrings(byte[] string1, byte[] string2)921 public static void ztestCrossCorrelationUniformStrings(byte[] string1, byte[] string2) 922 throws GeneralSecurityException { 923 if (string1.length != string2.length) { 924 throw new GeneralSecurityException("Strings are not of equal length"); 925 } 926 byte[] crossed = new byte[string1.length]; 927 for (int i = 0; i < string1.length; i++) { 928 crossed[i] = (byte) (string1[i] ^ string2[i]); 929 } 930 ztestUniformString(crossed); 931 } 932 933 /** 934 * Tests that the autocorrelation of a string points to the bits being independent and uniformly 935 * distributed. Rotates the string in a cyclic fashion. Returns non ok status if the z test fails 936 * by more than 10 standard deviations. 937 * 938 * <p>With less statistics jargon: This rotates the string bit by bit and performs 939 * ZTestCrosscorrelationUniformStrings on each of the rotated strings and the original. This will 940 * find self similarity of the input string, especially periodic self similarity. For example, it 941 * is a decent test to find English text (needs about 180 characters with the current settings). 942 * 943 * <p>Note: Having a correlation of zero is only a necessary but not sufficient condition for 944 * independence. 945 * 946 * @throws GeneralSecurityException if uniformity error is detected, otherwise returns normally. 947 */ ztestAutocorrelationUniformString(byte[] string)948 public static void ztestAutocorrelationUniformString(byte[] string) 949 throws GeneralSecurityException { 950 byte[] rotated = Arrays.copyOf(string, string.length); 951 952 for (int i = 1; i < string.length * 8; i++) { 953 rotate(rotated); 954 ztestCrossCorrelationUniformStrings(string, rotated); 955 } 956 } 957 958 /** Manual implementation of Byte.toUnsignedByte. The Android JDK does not have this method. */ toUnsignedInt(byte b)959 private static int toUnsignedInt(byte b) { 960 return b & 0xff; 961 } 962 rotate(byte[] string)963 private static void rotate(byte[] string) { 964 byte[] ref = Arrays.copyOf(string, string.length); 965 for (int i = 0; i < string.length; i++) { 966 string[i] = 967 (byte) 968 ((toUnsignedInt(string[i]) >> 1) 969 | ((1 & toUnsignedInt(ref[(i == 0 ? string.length : i) - 1])) << 7)); 970 } 971 } 972 TestUtil()973 private TestUtil() {} 974 } 975