xref: /aosp_15_r20/external/tink/java_src/src/main/java/com/google/crypto/tink/Registry.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 specific language governing permissions and
13 // limitations under the License.
14 //
15 ////////////////////////////////////////////////////////////////////////////////
16 
17 package com.google.crypto.tink;
18 
19 import com.google.crypto.tink.config.internal.TinkFipsUtil;
20 import com.google.crypto.tink.internal.KeyTypeManager;
21 import com.google.crypto.tink.internal.MutablePrimitiveRegistry;
22 import com.google.crypto.tink.internal.PrivateKeyTypeManager;
23 import com.google.crypto.tink.proto.KeyData;
24 import com.google.protobuf.ByteString;
25 import com.google.protobuf.InvalidProtocolBufferException;
26 import com.google.protobuf.MessageLite;
27 import java.io.InputStream;
28 import java.security.GeneralSecurityException;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.List;
32 import java.util.Locale;
33 import java.util.Map;
34 import java.util.concurrent.ConcurrentHashMap;
35 import java.util.concurrent.ConcurrentMap;
36 import java.util.concurrent.atomic.AtomicReference;
37 import java.util.logging.Logger;
38 import javax.annotation.Nullable;
39 
40 /**
41  * A global container of key managers and catalogues.
42  *
43  * <p>Registry maps each supported key type to a corresponding {@link KeyManager} object, which
44  * "understands" the key type (i.e., the KeyManager can instantiate the primitive corresponding to
45  * given key, or can generate new keys of the supported key type). It holds also a {@link
46  * PrimitiveWrapper} for each supported primitive, so that it can wrap a set of primitives
47  * (corresponding to a keyset) into a single primitive.
48  *
49  * <p>Keeping KeyManagers for all primitives in a single Registry (rather than having a separate
50  * KeyManager per primitive) enables modular construction of compound primitives from "simple" ones,
51  * e.g., AES-CTR-HMAC AEAD encryption uses IND-CPA encryption and a MAC.
52  *
53  * <p>Registry is initialized at startup, and is later used to instantiate primitives for given keys
54  * or keysets. Note that regular users will usually not work directly with Registry, but rather via
55  * {@link TinkConfig} and {@link KeysetHandle#getPrimitive(Class)}-methods, which in the background
56  * register and query the Registry for specific KeyManagers and PrimitiveWrappers. Registry is
57  * public though, to enable configurations with custom catalogues, primitives or KeyManagers.
58  *
59  * <p>To initialize the Registry with all key managers:
60  *
61  * <pre>{@code
62  * TinkConfig.register();
63  * }</pre>
64  *
65  * <p>Here's how to register only {@link Aead} key managers:
66  *
67  * <pre>{@code
68  * AeadConfig.register();
69  * }</pre>
70  *
71  * <p>After the Registry has been initialized, one can use get a primitive as follows:
72  *
73  * <pre>{@code
74  * KeysetHandle keysetHandle = ...;
75  * Aead aead = keysetHandle.getPrimitive(Aead.class);
76  * }</pre>
77  *
78  * @since 1.0.0
79  */
80 public final class Registry {
81   private static final Logger logger = Logger.getLogger(Registry.class.getName());
82 
83   private static final AtomicReference<KeyManagerRegistry> keyManagerRegistry =
84       new AtomicReference<>(new KeyManagerRegistry());
85 
86   private static final ConcurrentMap<String, KeyDataDeriver> keyDeriverMap =
87       new ConcurrentHashMap<>(); // typeUrl -> deriver (created out of KeyTypeManager).
88 
89   private static final ConcurrentMap<String, Boolean> newKeyAllowedMap =
90       new ConcurrentHashMap<>(); // typeUrl -> newKeyAllowed mapping
91 
92   private static final ConcurrentMap<String, Catalogue<?>> catalogueMap =
93       new ConcurrentHashMap<>(); //  name -> catalogue mapping
94 
95   private static final ConcurrentMap<String, KeyTemplate> keyTemplateMap =
96       new ConcurrentHashMap<>(); // name -> KeyTemplate mapping
97 
98   private static interface KeyDataDeriver {
deriveKeyData(ByteString serializedKeyFormat, InputStream stream)99     KeyData deriveKeyData(ByteString serializedKeyFormat, InputStream stream)
100         throws GeneralSecurityException;
101   }
102 
createDeriverFor( final KeyTypeManager<KeyProtoT> keyManager)103   private static <KeyProtoT extends MessageLite> KeyDataDeriver createDeriverFor(
104       final KeyTypeManager<KeyProtoT> keyManager) {
105     return new KeyDataDeriver() {
106       private <KeyFormatProtoT extends MessageLite> MessageLite deriveKeyWithFactory(
107           ByteString serializedKeyFormat,
108           InputStream stream,
109           KeyTypeManager.KeyFactory<KeyFormatProtoT, KeyProtoT> keyFactory)
110           throws GeneralSecurityException {
111         KeyFormatProtoT keyFormat;
112         try {
113           keyFormat = keyFactory.parseKeyFormat(serializedKeyFormat);
114         } catch (InvalidProtocolBufferException e) {
115           throw new GeneralSecurityException("parsing key format failed in deriveKey", e);
116         }
117         keyFactory.validateKeyFormat(keyFormat);
118         return keyFactory.deriveKey(keyFormat, stream);
119       }
120 
121       @Override
122       public KeyData deriveKeyData(ByteString serializedKeyFormat, InputStream stream)
123           throws GeneralSecurityException {
124         KeyTypeManager.KeyFactory<?, KeyProtoT> keyFactory = keyManager.keyFactory();
125         MessageLite keyValue = deriveKeyWithFactory(serializedKeyFormat, stream, keyFactory);
126         return KeyData.newBuilder()
127             .setTypeUrl(keyManager.getKeyType())
128             .setValue(keyValue.toByteString())
129             .setKeyMaterialType(keyManager.keyMaterialType())
130             .build();
131       }
132     };
133   }
134 
135   /**
136    * Resets the registry.
137    *
138    * <p>After reset the registry is empty, i.e. it contains no key managers. Thus one might need to
139    * call {@code XyzConfig.register()} to re-install the catalogues.
140    *
141    * <p>This method is intended for testing.
142    */
143   static synchronized void reset() {
144     keyManagerRegistry.set(new KeyManagerRegistry());
145     MutablePrimitiveRegistry.resetGlobalInstanceTestOnly();
146     keyDeriverMap.clear();
147     newKeyAllowedMap.clear();
148     catalogueMap.clear();
149     keyTemplateMap.clear();
150   }
151 
152   /**
153    * Tries to add a catalogue, to enable custom configuration of key types and key managers.
154    *
155    * <p>Adding a custom catalogue should be a one-time operaton. There is an existing catalogue,
156    * throw exception if {@code catalogue} and the existing catalogue aren't instances of the same
157    * class, and do nothing if they are.
158    *
159    * @throws GeneralSecurityException if there's an existing catalogue and it is not an instance of
160    *     the same class as {@code catalogue}
161    * @deprecated Catalogues are no longer supported.
162    */
163   @Deprecated
164   public static synchronized void addCatalogue(
165       String catalogueName, Catalogue<?> catalogue) throws GeneralSecurityException {
166     if (catalogueName == null) {
167       throw new IllegalArgumentException("catalogueName must be non-null.");
168     }
169     if (catalogue == null) {
170       throw new IllegalArgumentException("catalogue must be non-null.");
171     }
172     if (catalogueMap.containsKey(catalogueName.toLowerCase(Locale.US))) {
173       Catalogue<?> existing = catalogueMap.get(catalogueName.toLowerCase(Locale.US));
174       if (!catalogue.getClass().getName().equals(existing.getClass().getName())) {
175         logger.warning(
176             "Attempted overwrite of a catalogueName catalogue for name " + catalogueName);
177         throw new GeneralSecurityException(
178             "catalogue for name " + catalogueName + " has been already registered");
179       }
180     }
181     catalogueMap.put(catalogueName.toLowerCase(Locale.US), catalogue);
182   }
183 
184   /**
185    * Tries to get a catalogue associated with {@code catalogueName}.
186    *
187    * @deprecated Catalogues are no longer supported.
188    * @throws GeneralSecurityException if no catalogue is found
189    */
190   @Deprecated
191   public static Catalogue<?> getCatalogue(String catalogueName)
192       throws GeneralSecurityException {
193     if (catalogueName == null) {
194       throw new IllegalArgumentException("catalogueName must be non-null.");
195     }
196     Catalogue<?> catalogue = catalogueMap.get(catalogueName.toLowerCase(Locale.US));
197     if (catalogue == null) {
198       String error = String.format("no catalogue found for %s. ", catalogueName);
199       if (catalogueName.toLowerCase(Locale.US).startsWith("tinkaead")) {
200         error += "Maybe call AeadConfig.register().";
201       }
202       if (catalogueName.toLowerCase(Locale.US).startsWith("tinkdeterministicaead")) {
203         error += "Maybe call DeterministicAeadConfig.register().";
204       } else if (catalogueName.toLowerCase(Locale.US).startsWith("tinkstreamingaead")) {
205         error += "Maybe call StreamingAeadConfig.register().";
206       } else if (catalogueName.toLowerCase(Locale.US).startsWith("tinkhybriddecrypt")
207           || catalogueName.toLowerCase(Locale.US).startsWith("tinkhybridencrypt")) {
208         error += "Maybe call HybridConfig.register().";
209       } else if (catalogueName.toLowerCase(Locale.US).startsWith("tinkmac")) {
210         error += "Maybe call MacConfig.register().";
211       } else if (catalogueName.toLowerCase(Locale.US).startsWith("tinkpublickeysign")
212           || catalogueName.toLowerCase(Locale.US).startsWith("tinkpublickeyverify")) {
213         error += "Maybe call SignatureConfig.register().";
214       } else if (catalogueName.toLowerCase(Locale.US).startsWith("tink")) {
215         error += "Maybe call TinkConfig.register().";
216       }
217       throw new GeneralSecurityException(error);
218     }
219     return catalogue;
220   }
221 
222   /**
223    * Tries to register {@code manager} for {@code manager.getKeyType()}. Users can generate new keys
224    * with this manager using the {@link Registry#newKey} methods.
225    *
226    * <p>If there is an existing key manager, throws an exception if {@code manager} and the existing
227    * key manager aren't instances of the same class, or the existing key manager could not create
228    * new keys. Otherwise registration succeeds.
229    *
230    * @throws GeneralSecurityException if there's an existing key manager is not an instance of the
231    *     class of {@code manager}, or the registration tries to re-enable the generation of new
232    *     keys.
233    */
234   public static synchronized <P> void registerKeyManager(final KeyManager<P> manager)
235       throws GeneralSecurityException {
236     registerKeyManager(manager, /* newKeyAllowed= */ true);
237   }
238 
239   /**
240    * Tries to register {@code manager} for {@code manager.getKeyType()}. If {@code newKeyAllowed} is
241    * true, users can generate new keys with this manager using the {@link Registry#newKey} methods.
242    *
243    * <p>If there is an existing key manager, throws an exception if {@code manager} and the existing
244    * key manager aren't instances of the same class, or if {@code newKeyAllowed} is true while the
245    * existing key manager could not create new keys. Otherwise registration succeeds.
246    *
247    * @throws GeneralSecurityException if there's an existing key manager is not an instance of the
248    *     class of {@code manager}, or the registration tries to re-enable the generation of new
249    *     keys.
250    */
251   public static synchronized <P> void registerKeyManager(
252       final KeyManager<P> manager, boolean newKeyAllowed) throws GeneralSecurityException {
253     if (manager == null) {
254       throw new IllegalArgumentException("key manager must be non-null.");
255     }
256     KeyManagerRegistry newKeyManagerRegistry = new KeyManagerRegistry(keyManagerRegistry.get());
257     newKeyManagerRegistry.registerKeyManager(manager);
258 
259     if (!TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_NOT_FIPS.isCompatible()) {
260       throw new GeneralSecurityException("Registering key managers is not supported in FIPS mode");
261     }
262     String typeUrl = manager.getKeyType();
263     // Use an empty key format because old-style key managers don't export their key formats
264     ensureKeyManagerInsertable(typeUrl, Collections.emptyMap(), newKeyAllowed);
265     newKeyAllowedMap.put(typeUrl, Boolean.valueOf(newKeyAllowed));
266     keyManagerRegistry.set(newKeyManagerRegistry);
267   }
268 
269   /**
270    * Tries to register {@code manager} for {@code manager.getKeyType()}. If {@code newKeyAllowed} is
271    * true, users can generate new keys with this manager using the {@link Registry#newKey} methods.
272    *
273    * <p>If there is an existing key manager, throws an exception if {@code manager} and the existing
274    * key manager aren't instances of the same class, or if {@code newKeyAllowed} is true while the
275    * existing key manager could not create new keys. Otherwise registration succeeds.
276    *
277    * <p>If {@code newKeyAllowed} is true, also tries to register the key templates supported by
278    * {@code manager}.
279    *
280    * @throws GeneralSecurityException if there's an existing key manager is not an instance of the
281    *     class of {@code manager}, or the registration tries to re-enable the generation of new
282    *     keys.
283    * @throws GeneralSecurityException if there's an existing key template.
284    * @throws GeneralSecurityException if the key manager is not compatible with the restrictions in
285    *     FIPS-mode.
286    */
287   public static synchronized <KeyProtoT extends MessageLite> void registerKeyManager(
288       final KeyTypeManager<KeyProtoT> manager, boolean newKeyAllowed)
289       throws GeneralSecurityException {
290     if (manager == null) {
291       throw new IllegalArgumentException("key manager must be non-null.");
292     }
293     KeyManagerRegistry newKeyManagerRegistry = new KeyManagerRegistry(keyManagerRegistry.get());
294     newKeyManagerRegistry.registerKeyManager(manager);
295     String typeUrl = manager.getKeyType();
296     ensureKeyManagerInsertable(
297         typeUrl,
298         newKeyAllowed ? manager.keyFactory().keyFormats() : Collections.emptyMap(),
299         newKeyAllowed);
300 
301     if (!keyManagerRegistry.get().typeUrlExists(typeUrl)) {
302       keyDeriverMap.put(typeUrl, createDeriverFor(manager));
303       if (newKeyAllowed) {
304         registerKeyTemplates(typeUrl, manager.keyFactory().keyFormats());
305       }
306     }
307     newKeyAllowedMap.put(typeUrl, Boolean.valueOf(newKeyAllowed));
308     keyManagerRegistry.set(newKeyManagerRegistry);
309   }
310 
311   /**
312    * Tries to register {@code manager} for the given {@code typeUrl}. Users can generate new keys
313    * with this manager using the {@link Registry#newKey} methods.
314    *
315    * <p>Does nothing if there's an existing key manager and it's an instance of the same class as
316    * {@code manager}.
317    *
318    * @throws GeneralSecurityException if there's an existing key manager and it is not an instance
319    *     of the same class as {@code manager}
320    * @deprecated use {@link #registerKeyManager(KeyManager) registerKeyManager(KeyManager&lt;P&gt;)}
321    */
322   @Deprecated
323   public static synchronized <P> void registerKeyManager(
324       String typeUrl, final KeyManager<P> manager) throws GeneralSecurityException {
325     registerKeyManager(typeUrl, manager, /* newKeyAllowed= */ true);
326   }
327 
328   /**
329    * Tries to register {@code manager} for the given {@code typeUrl}. If {@code newKeyAllowed} is
330    * true, users can generate new keys with this manager using the {@link Registry#newKey} methods.
331    *
332    * <p>Does nothing if there's an existing key manager and it's an instance of the same class as
333    * {@code manager}.
334    *
335    * @throws GeneralSecurityException if there's an existing key manager and it is not an instance
336    *     of the same class as {@code manager}
337    * @deprecated use {@link #registerKeyManager(KeyManager, boolean)
338    *     registerKeyManager(KeyManager&lt;P&gt;, boolean)}
339    */
340   @Deprecated
341   public static synchronized <P> void registerKeyManager(
342       String typeUrl, final KeyManager<P> manager, boolean newKeyAllowed)
343       throws GeneralSecurityException {
344     if (manager == null) {
345       throw new IllegalArgumentException("key manager must be non-null.");
346     }
347     if (!typeUrl.equals(manager.getKeyType())) {
348       throw new GeneralSecurityException("Manager does not support key type " + typeUrl + ".");
349     }
350     registerKeyManager(manager, newKeyAllowed);
351   }
352 
353   /**
354    * Throws a general security exception if one of these conditions holds:
355    *
356    * <ul>
357    *   <li>There is already a key manager registered for {@code typeURL}, and at least one of the
358    *       following is true:
359    *       <ul>
360    *         <li>The class implementing the existing key manager differs from the given one.
361    *         <li>The value of {@code newKeyAllowed} currently registered is false, but the input
362    *             parameter is true.
363    *       </ul>
364    *   <li>The {@code newKeyAllowed} flag is true, and at least one of the following is true:
365    *       <ul>
366    *         <li>The key manager was already registered, but it contains new key templates.
367    *         <li>The key manager is new, but it contains existing key templates.
368    */
369   private static synchronized <KeyFormatProtoT extends MessageLite> void ensureKeyManagerInsertable(
370       String typeUrl,
371       Map<String, KeyTypeManager.KeyFactory.KeyFormat<KeyFormatProtoT>> keyFormats,
372       boolean newKeyAllowed)
373       throws GeneralSecurityException {
374     if (newKeyAllowed && newKeyAllowedMap.containsKey(typeUrl) && !newKeyAllowedMap.get(typeUrl)) {
375       throw new GeneralSecurityException("New keys are already disallowed for key type " + typeUrl);
376     }
377 
378     if (newKeyAllowed) {
379       if (keyManagerRegistry.get().typeUrlExists(typeUrl)) {
380         // When re-inserting an already present KeyTypeManager, no new key templates should be
381         // present.
382         for (Map.Entry<String, KeyTypeManager.KeyFactory.KeyFormat<KeyFormatProtoT>> entry :
383             keyFormats.entrySet()) {
384           if (!keyTemplateMap.containsKey(entry.getKey())) {
385             throw new GeneralSecurityException(
386                 "Attempted to register a new key template "
387                     + entry.getKey()
388                     + " from an existing key manager of type "
389                     + typeUrl);
390           }
391         }
392       } else {
393         // Check that new key managers can't overwrite existing key templates.
394         for (Map.Entry<String, KeyTypeManager.KeyFactory.KeyFormat<KeyFormatProtoT>> entry :
395             keyFormats.entrySet()) {
396 
397           if (keyTemplateMap.containsKey(entry.getKey())) {
398             throw new GeneralSecurityException(
399                 "Attempted overwrite of a registered key template " + entry.getKey());
400           }
401         }
402       }
403     }
404   }
405 
406   /**
407    * Tries to register {@code manager} for {@code manager.getKeyType()}. If {@code newKeyAllowed} is
408    * true, users can generate new keys with this manager using the {@link Registry#newKey} methods.
409    *
410    * <p>If {@code newKeyAllowed} is true, also tries to register the key templates supported by
411    * {@code manager}.
412    *
413    * <p>If there is an existing key manager, throws an exception if {@code manager} and the existing
414    * key manager aren't instances of the same class, or if {@code newKeyAllowed} is true while the
415    * existing key manager could not create new keys. Otherwise registration succeeds.
416    *
417    * @throws GeneralSecurityException if there's an existing key manager is not an instance of the
418    *     class of {@code manager}, or the registration tries to re-enable the generation of new
419    *     keys.
420    * @throws GeneralSecurityException if there's an existing key template.
421    */
422   public static synchronized <KeyProtoT extends MessageLite, PublicKeyProtoT extends MessageLite>
423       void registerAsymmetricKeyManagers(
424           final PrivateKeyTypeManager<KeyProtoT, PublicKeyProtoT> privateKeyTypeManager,
425           final KeyTypeManager<PublicKeyProtoT> publicKeyTypeManager,
426           boolean newKeyAllowed)
427           throws GeneralSecurityException {
428     if (privateKeyTypeManager == null || publicKeyTypeManager == null) {
429       throw new IllegalArgumentException("given key managers must be non-null.");
430     }
431     KeyManagerRegistry newKeyManagerRegistry = new KeyManagerRegistry(keyManagerRegistry.get());
432     newKeyManagerRegistry.registerAsymmetricKeyManagers(
433         privateKeyTypeManager, publicKeyTypeManager);
434 
435     String privateTypeUrl = privateKeyTypeManager.getKeyType();
436     String publicTypeUrl = publicKeyTypeManager.getKeyType();
437     ensureKeyManagerInsertable(
438         privateTypeUrl,
439         newKeyAllowed ? privateKeyTypeManager.keyFactory().keyFormats() : Collections.emptyMap(),
440         newKeyAllowed);
441     // No key format because a public key manager cannot create new keys
442     ensureKeyManagerInsertable(publicTypeUrl, Collections.emptyMap(), false);
443 
444     if (!keyManagerRegistry.get().typeUrlExists(privateTypeUrl)) {
445       keyDeriverMap.put(privateTypeUrl, createDeriverFor(privateKeyTypeManager));
446       if (newKeyAllowed) {
447         registerKeyTemplates(
448             privateKeyTypeManager.getKeyType(), privateKeyTypeManager.keyFactory().keyFormats());
449       }
450     }
451     newKeyAllowedMap.put(privateTypeUrl, newKeyAllowed);
452     newKeyAllowedMap.put(publicTypeUrl, false);
453 
454     keyManagerRegistry.set(newKeyManagerRegistry);
455   }
456 
457   private static <KeyFormatProtoT extends MessageLite> void registerKeyTemplates(
458       String typeUrl,
459       Map<String, KeyTypeManager.KeyFactory.KeyFormat<KeyFormatProtoT>> keyFormats) {
460     for (Map.Entry<String, KeyTypeManager.KeyFactory.KeyFormat<KeyFormatProtoT>> entry :
461         keyFormats.entrySet()) {
462       keyTemplateMap.put(
463           entry.getKey(),
464           KeyTemplate.create(
465               typeUrl,
466               entry.getValue().keyFormat.toByteArray(),
467               entry.getValue().outputPrefixType));
468     }
469   }
470 
471   /**
472    * Tries to register {@code wrapper} as a new SetWrapper for primitive {@code P}.
473    *
474    * <p>If no SetWrapper is registered for {@code P}, registers the given one. If there already is a
475    * SetWrapper registered which is of the same class ass the passed in set wrapper, the call is
476    * silently ignored. If the new set wrapper is of a different type, the call fails with a {@code
477    * GeneralSecurityException}.
478    *
479    * @throws GeneralSecurityException if there's an existing key manager and it is not an instance
480    *     of the class of {@code manager}, or the registration tries to re-enable the generation of
481    *     new keys.
482    */
483   public static synchronized <B, P> void registerPrimitiveWrapper(
484       final PrimitiveWrapper<B, P> wrapper) throws GeneralSecurityException {
485     MutablePrimitiveRegistry.globalInstance().registerPrimitiveWrapper(wrapper);
486   }
487 
488   /**
489    * Returns a {@link KeyManager} for the given {@code typeUrl} (if found).
490    *
491    * @deprecated KeyManagers should not be used directly. Use {@code newKeyData} or {@code
492    *     getPrimitive} instead.
493    */
494   @Deprecated
495   public static <P> KeyManager<P> getKeyManager(String typeUrl)
496       throws GeneralSecurityException {
497     @SuppressWarnings("unchecked") // Unavoidable for the API we implement (hence it is deprecated)
498     KeyManager<P> result = (KeyManager<P>) getUntypedKeyManager(typeUrl);
499     return result;
500   }
501 
502   /**
503    * Returns a {@link KeyManager} for the given {@code typeUrl} (if found).
504    *
505    * @deprecated KeyManagers should not be used directly. Use {@code newKeyData} or {@code
506    *     getPrimitive} instead.
507    */
508   @Deprecated
509   public static <P> KeyManager<P> getKeyManager(String typeUrl, Class<P> primitiveClass)
510       throws GeneralSecurityException {
511     return keyManagerRegistry.get().getKeyManager(typeUrl, primitiveClass);
512   }
513 
514   /**
515    * Returns a {@link KeyManager} for the given {@code typeUrl} (if found).
516    *
517    * @deprecated KeyManagers should not be used directly. Use {@code newKeyData} or {@code
518    *     getPrimitive} instead.
519    */
520   @Deprecated
521   public static KeyManager<?> getUntypedKeyManager(String typeUrl)
522       throws GeneralSecurityException {
523     return keyManagerRegistry.get().getUntypedKeyManager(typeUrl);
524   }
525 
526   /**
527    * Generates a new {@link KeyData} for the specified {@code template}.
528    *
529    * <p>It looks up a {@link KeyManager} identified by {@code keyTemplate.type_url}, and calls
530    * {@link KeyManager#newKeyData}.
531    *
532    * <p>This method should be used solely for key management.
533    *
534    * @return a new {@link KeyData}
535    */
536   public static synchronized KeyData newKeyData(
537       com.google.crypto.tink.proto.KeyTemplate keyTemplate) throws GeneralSecurityException {
538     KeyManager<?> manager = keyManagerRegistry.get().getUntypedKeyManager(keyTemplate.getTypeUrl());
539     if (newKeyAllowedMap.get(keyTemplate.getTypeUrl()).booleanValue()) {
540       return manager.newKeyData(keyTemplate.getValue());
541     } else {
542       throw new GeneralSecurityException(
543           "newKey-operation not permitted for key type " + keyTemplate.getTypeUrl());
544     }
545   }
546 
547   /**
548    * Generates a new {@link KeyData} for the specified {@code template}.
549    *
550    * <p>It looks up a {@link KeyManager} identified by {@code keyTemplate.type_url}, and calls
551    * {@link KeyManager#newKeyData}.
552    *
553    * <p>This method should be used solely for key management.
554    *
555    * @return a new {@link KeyData}
556    */
557   public static synchronized KeyData newKeyData(com.google.crypto.tink.KeyTemplate keyTemplate)
558       throws GeneralSecurityException {
559     return newKeyData(keyTemplate.getProto());
560   }
561 
562   /**
563    * Generates a new key for the specified {@code keyTemplate}.
564    *
565    * <p>It looks up a {@link KeyManager} identified by {@code keyTemplate.type_url}, and calls
566    * {@link KeyManager#newKey} with {@code keyTemplate} as the parameter.
567    *
568    * @return a new key
569    * @deprecated Use {@code newKeyData} instead.
570    */
571   @Deprecated
572   public static synchronized MessageLite newKey(
573       com.google.crypto.tink.proto.KeyTemplate keyTemplate) throws GeneralSecurityException {
574     KeyManager<?> manager = getUntypedKeyManager(keyTemplate.getTypeUrl());
575     if (newKeyAllowedMap.get(keyTemplate.getTypeUrl()).booleanValue()) {
576       return manager.newKey(keyTemplate.getValue());
577     } else {
578       throw new GeneralSecurityException(
579           "newKey-operation not permitted for key type " + keyTemplate.getTypeUrl());
580     }
581   }
582 
583   /**
584    * Generates a new key for the specified {@code format}.
585    *
586    * <p>It looks up a {@link KeyManager} identified by {@code keyTemplate.type_url}, and calls
587    * {@link KeyManager#newKey} with {@code format} as the parameter.
588    *
589    * @return a new key
590    * @deprecated Use {@code newKeyData} instead.
591    */
592   @Deprecated
593   public static synchronized MessageLite newKey(String typeUrl, MessageLite format)
594       throws GeneralSecurityException {
595     KeyManager<?> manager = getKeyManager(typeUrl);
596     if (newKeyAllowedMap.get(typeUrl).booleanValue()) {
597       return manager.newKey(format);
598     } else {
599       throw new GeneralSecurityException("newKey-operation not permitted for key type " + typeUrl);
600     }
601   }
602 
603   /**
604    * Derives a key, using the given {@code keyTemplate}, with the randomness as provided by the
605    * second argument.
606    *
607    * <p>This method is on purpose not in the public interface. Calling it twice using different key
608    * templates and the same randomness can completely destroy any security in a system, so we
609    * prevent this by making it accessible only to safe call sites.
610    *
611    * <p>This functions ignores {@code keyTemplate.getOutputPrefix()}.
612    */
613   static synchronized KeyData deriveKey(
614       com.google.crypto.tink.proto.KeyTemplate keyTemplate, InputStream randomStream)
615       throws GeneralSecurityException {
616     String typeUrl = keyTemplate.getTypeUrl();
617     if (!keyDeriverMap.containsKey(typeUrl)) {
618       throw new GeneralSecurityException(
619           "No keymanager registered or key manager cannot derive keys for " + typeUrl);
620     }
621     KeyDataDeriver deriver = keyDeriverMap.get(typeUrl);
622     return deriver.deriveKeyData(keyTemplate.getValue(), randomStream);
623   }
624 
625   /**
626    * Extracts the public key data from the private key given in {@code serializedPrivateKey}.
627    *
628    * <p>It looks up a {@link PrivateKeyManager} identified by {@code typeUrl}, and calls {@link
629    * PrivateKeyManager#getPublicKeyData} with {@code serializedPrivateKey} as the parameter.
630    *
631    * @return a new key
632    */
633   public static KeyData getPublicKeyData(String typeUrl, ByteString serializedPrivateKey)
634       throws GeneralSecurityException {
635     KeyManager<?> manager = getKeyManager(typeUrl);
636     if (!(manager instanceof PrivateKeyManager)) {
637       throw new GeneralSecurityException(
638           "manager for key type " + typeUrl + " is not a PrivateKeyManager");
639     }
640     return ((PrivateKeyManager) manager).getPublicKeyData(serializedPrivateKey);
641   }
642 
643   /**
644    * Creates a new primitive for the key given in {@code proto}.
645    *
646    * <p>It looks up a {@link KeyManager} identified by {@code type_url}, and calls {@link
647    * KeyManager#getPrimitive} with {@code key} as the parameter.
648    *
649    * @return a new primitive
650    * @deprecated Use {@code getPrimitive(typeUrl, serializedKey, P.class)} instead.
651    */
652   @SuppressWarnings("TypeParameterUnusedInFormals")
653   @Deprecated
654   public static <P> P getPrimitive(String typeUrl, MessageLite key)
655       throws GeneralSecurityException {
656     KeyManager<P> manager = getKeyManager(typeUrl);
657     return manager.getPrimitive(key.toByteString());
658   }
659 
660   /**
661    * Creates a new primitive for the key given in {@code key}.
662    *
663    * <p>It looks up a {@link KeyManager} identified by {@code type_url}, and calls {@link
664    * KeyManager#getPrimitive} with {@code key} as the parameter.
665    *
666    * @return a new primitive
667    * @deprecated Use {@code getPrimitive(typeUrl, serializedKey, Primitive.class} instead.
668    */
669   @Deprecated
670   public static <P> P getPrimitive(
671       String typeUrl, MessageLite key, Class<P> primitiveClass) throws GeneralSecurityException {
672     KeyManager<P> manager = keyManagerRegistry.get().getKeyManager(typeUrl, primitiveClass);
673     return manager.getPrimitive(key.toByteString());
674   }
675 
676   /**
677    * Creates a new primitive for the key given in {@code proto}.
678    *
679    * <p>It looks up a {@link KeyManager} identified by {@code type_url}, and calls {@link
680    * KeyManager#getPrimitive} with {@code serializedKey} as the parameter.
681    *
682    * @return a new primitive
683    * @deprecated Use {@code getPrimitive(typeUrl, serializedKey, Primitive.class} instead.
684    */
685   @SuppressWarnings("TypeParameterUnusedInFormals")
686   @Deprecated
687   public static <P> P getPrimitive(String typeUrl, ByteString serializedKey)
688       throws GeneralSecurityException {
689     KeyManager<P> manager = getKeyManager(typeUrl);
690     return manager.getPrimitive(serializedKey);
691   }
692 
693   /**
694    * Creates a new primitive for the key given in {@code serializedKey}.
695    *
696    * <p>It looks up a {@link KeyManager} identified by {@code type_url}, and calls {@link
697    * KeyManager#getPrimitive} with {@code serialized} as the parameter.
698    *
699    * @return a new primitive
700    */
701   public static <P> P getPrimitive(
702       String typeUrl, ByteString serializedKey, Class<P> primitiveClass)
703       throws GeneralSecurityException {
704     KeyManager<P> manager = keyManagerRegistry.get().getKeyManager(typeUrl, primitiveClass);
705     return manager.getPrimitive(serializedKey);
706   }
707 
708   /**
709    * Creates a new primitive for the key given in {@code serializedKey}.
710    *
711    * <p>It looks up a {@link KeyManager} identified by {@code type_url}, and calls {@link
712    * KeyManager#getPrimitive} with {@code serialized} as the parameter.
713    *
714    * @deprecated Use {@code getPrimitive(typeUrl, serializedKey, Primitive.class)} instead.
715    * @return a new primitive
716    */
717   @SuppressWarnings("TypeParameterUnusedInFormals")
718   @Deprecated
719   public static <P> P getPrimitive(String typeUrl, byte[] serializedKey)
720       throws GeneralSecurityException {
721     return getPrimitive(typeUrl, ByteString.copyFrom(serializedKey));
722   }
723 
724   /**
725    * Creates a new primitive for the key given in {@code serializedKey}.
726    *
727    * <p>It looks up a {@link KeyManager} identified by {@code type_url}, and calls {@link
728    * KeyManager#getPrimitive} with {@code serialized} as the parameter.
729    *
730    * @return a new primitive
731    */
732   public static <P> P getPrimitive(String typeUrl, byte[] serializedKey, Class<P> primitiveClass)
733       throws GeneralSecurityException {
734     return getPrimitive(typeUrl, ByteString.copyFrom(serializedKey), primitiveClass);
735   }
736 
737   /**
738    * Creates a new primitive for the key given in {@code keyData}.
739    *
740    * <p>It looks up a {@link KeyManager} identified by {@code keyData.type_url}, and calls {@link
741    * KeyManager#getPrimitive} with {@code keyData.value} as the parameter.
742    *
743    * @return a new primitive
744    * @deprecated Use {@code getPrimitive(keyData, Primitive.class)} instead.
745    */
746   @SuppressWarnings("TypeParameterUnusedInFormals")
747   @Deprecated
748   public static <P> P getPrimitive(KeyData keyData) throws GeneralSecurityException {
749     return getPrimitive(keyData.getTypeUrl(), keyData.getValue());
750   }
751 
752   /**
753    * Creates a new primitive for the key given in {@code keyData}.
754    *
755    * <p>It looks up a {@link KeyManager} identified by {@code keyData.type_url}, and calls {@link
756    * KeyManager#getPrimitive} with {@code keyData.value} as the parameter.
757    *
758    * @return a new primitive
759    */
760   public static <P> P getPrimitive(KeyData keyData, Class<P> primitiveClass)
761       throws GeneralSecurityException {
762     return getPrimitive(keyData.getTypeUrl(), keyData.getValue(), primitiveClass);
763   }
764 
765   static <KeyT extends Key, P> P getFullPrimitive(KeyT key, Class<P> primitiveClass)
766       throws GeneralSecurityException {
767     return MutablePrimitiveRegistry.globalInstance().getPrimitive(key, primitiveClass);
768   }
769 
770   /**
771    * Looks up the globally registered PrimitiveWrapper for this primitive and wraps the given
772    * PrimitiveSet with it.
773    */
774   public static <B, P> P wrap(PrimitiveSet<B> primitiveSet, Class<P> clazz)
775       throws GeneralSecurityException {
776     return MutablePrimitiveRegistry.globalInstance().wrap(primitiveSet, clazz);
777   }
778 
779   public static <P> P wrap(PrimitiveSet<P> primitiveSet)
780       throws GeneralSecurityException {
781     return wrap(primitiveSet, primitiveSet.getPrimitiveClass());
782   }
783 
784   /**
785    * Returns an immutable list of key template names supported by registered key managers that are
786    * allowed to generate new keys.
787    *
788    * @since 1.6.0
789    */
790   public static synchronized List<String> keyTemplates() {
791     List<String> results = new ArrayList<>();
792     results.addAll(keyTemplateMap.keySet());
793 
794     return Collections.unmodifiableList(results);
795   }
796 
797   /** Internal API that returns an unmodifiable map of registered key templates and their names. */
798   static synchronized Map<String, KeyTemplate> keyTemplateMap() {
799     return Collections.unmodifiableMap(keyTemplateMap);
800   }
801 
802   /**
803    * Returns the input primitive required when creating a {@code wrappedPrimitive}.
804    *
805    * <p>This returns the primitive class of the objects required when we want to create a wrapped
806    * primitive of type {@code wrappedPrimitive}. Returns {@code null} if no wrapper for this
807    * primitive has been registered.
808    */
809   @Nullable
810   public static Class<?> getInputPrimitive(Class<?> wrappedPrimitive) {
811     try {
812       return MutablePrimitiveRegistry.globalInstance().getInputPrimitiveClass(wrappedPrimitive);
813     } catch (GeneralSecurityException e) {
814       return null;
815     }
816   }
817 
818   /**
819    * Tries to enable the FIPS restrictions if the Registry is empty.
820    *
821    * @throws GeneralSecurityException if any key manager has already been registered.
822    */
823   public static synchronized void restrictToFipsIfEmpty() throws GeneralSecurityException {
824     // If we are already using FIPS mode, do nothing.
825     if (TinkFipsUtil.useOnlyFips()) {
826       return;
827     }
828     if (keyManagerRegistry.get().isEmpty()) {
829       TinkFipsUtil.setFipsRestricted();
830       return;
831     }
832     throw new GeneralSecurityException("Could not enable FIPS mode as Registry is not empty.");
833   }
834 
835   private Registry() {}
836 }
837