xref: /aosp_15_r20/external/tink/java_src/src/main/java/com/google/crypto/tink/testing/TestUtil.java (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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