• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ////////////////////////////////////////////////////////////////////////////////
16 
17 package com.google.crypto.tink;
18 
19 import com.google.crypto.tink.config.internal.TinkFipsUtil;
20 import com.google.crypto.tink.internal.KeyManagerRegistry;
21 import com.google.crypto.tink.internal.MutableParametersRegistry;
22 import com.google.crypto.tink.internal.MutablePrimitiveRegistry;
23 import com.google.crypto.tink.internal.PrimitiveSet;
24 import com.google.crypto.tink.prf.Prf;
25 import com.google.crypto.tink.proto.KeyData;
26 import com.google.protobuf.ByteString;
27 import com.google.protobuf.ExtensionRegistryLite;
28 import com.google.protobuf.InvalidProtocolBufferException;
29 import com.google.protobuf.MessageLite;
30 import java.security.GeneralSecurityException;
31 import java.util.Collections;
32 import java.util.HashSet;
33 import java.util.List;
34 import java.util.Locale;
35 import java.util.Set;
36 import java.util.concurrent.ConcurrentHashMap;
37 import java.util.concurrent.ConcurrentMap;
38 import java.util.logging.Logger;
39 import javax.annotation.Nullable;
40 
41 /**
42  * A global container of key managers and catalogues.
43  *
44  * <p>Registry maps each supported key type to a corresponding {@link KeyManager} object, which
45  * "understands" the key type (i.e., the KeyManager can instantiate the primitive corresponding to
46  * given key, or can generate new keys of the supported key type). It holds also a {@link
47  * PrimitiveWrapper} for each supported primitive, so that it can wrap a set of primitives
48  * (corresponding to a keyset) into a single primitive.
49  *
50  * <p>Keeping KeyManagers for all primitives in a single Registry (rather than having a separate
51  * KeyManager per primitive) enables modular construction of compound primitives from "simple" ones,
52  * e.g., AES-CTR-HMAC AEAD encryption uses IND-CPA encryption and a MAC.
53  *
54  * <p>Registry is initialized at startup, and is later used to instantiate primitives for given keys
55  * or keysets. Note that regular users will usually not work directly with Registry, but rather via
56  * {@link TinkConfig} and {@link KeysetHandle#getPrimitive(Class)}-methods, which in the background
57  * register and query the Registry for specific KeyManagers and PrimitiveWrappers. Registry is
58  * public though, to enable configurations with custom catalogues, primitives or KeyManagers.
59  *
60  * <p>To initialize the Registry with all key managers:
61  *
62  * <pre>{@code
63  * TinkConfig.register();
64  * }</pre>
65  *
66  * <p>Here's how to register only {@link Aead} key managers:
67  *
68  * <pre>{@code
69  * AeadConfig.register();
70  * }</pre>
71  *
72  * <p>After the Registry has been initialized, one can use get a primitive as follows:
73  *
74  * <pre>{@code
75  * KeysetHandle keysetHandle = ...;
76  * Aead aead = keysetHandle.getPrimitive(RegistryConfiguration.get(), Aead.class);
77  * }</pre>
78  *
79  * @since 1.0.0
80  */
81 public final class Registry {
82   private static final Logger logger = Logger.getLogger(Registry.class.getName());
83 
84   private static final ConcurrentMap<String, Catalogue<?>> catalogueMap =
85       new ConcurrentHashMap<>(); //  name -> catalogue mapping
86 
87   /**
88    * Resets the registry.
89    *
90    * <p>After reset the registry is empty, i.e. it contains no key managers. Thus one might need to
91    * call {@code XyzConfig.register()} to re-install the catalogues.
92    *
93    * <p>This method is intended for testing.
94    */
reset()95   static synchronized void reset() {
96     KeyManagerRegistry.resetGlobalInstanceTestOnly();
97     MutablePrimitiveRegistry.resetGlobalInstanceTestOnly();
98     catalogueMap.clear();
99   }
100 
101   /**
102    * Tries to add a catalogue, to enable custom configuration of key types and key managers.
103    *
104    * <p>Adding a custom catalogue should be a one-time operaton. There is an existing catalogue,
105    * throw exception if {@code catalogue} and the existing catalogue aren't instances of the same
106    * class, and do nothing if they are.
107    *
108    * @throws GeneralSecurityException if there's an existing catalogue and it is not an instance of
109    *     the same class as {@code catalogue}
110    * @deprecated Catalogues are no longer supported.
111    */
112   @Deprecated
addCatalogue( String catalogueName, Catalogue<?> catalogue)113   public static synchronized void addCatalogue(
114       String catalogueName, Catalogue<?> catalogue) throws GeneralSecurityException {
115     if (catalogueName == null) {
116       throw new IllegalArgumentException("catalogueName must be non-null.");
117     }
118     if (catalogue == null) {
119       throw new IllegalArgumentException("catalogue must be non-null.");
120     }
121     if (catalogueMap.containsKey(catalogueName.toLowerCase(Locale.US))) {
122       Catalogue<?> existing = catalogueMap.get(catalogueName.toLowerCase(Locale.US));
123       if (!catalogue.getClass().getName().equals(existing.getClass().getName())) {
124         logger.warning(
125             "Attempted overwrite of a catalogueName catalogue for name " + catalogueName);
126         throw new GeneralSecurityException(
127             "catalogue for name " + catalogueName + " has been already registered");
128       }
129     }
130     catalogueMap.put(catalogueName.toLowerCase(Locale.US), catalogue);
131   }
132 
133   /**
134    * Tries to get a catalogue associated with {@code catalogueName}.
135    *
136    * @deprecated Catalogues are no longer supported.
137    * @throws GeneralSecurityException if no catalogue is found
138    */
139   @Deprecated
getCatalogue(String catalogueName)140   public static Catalogue<?> getCatalogue(String catalogueName)
141       throws GeneralSecurityException {
142     if (catalogueName == null) {
143       throw new IllegalArgumentException("catalogueName must be non-null.");
144     }
145     Catalogue<?> catalogue = catalogueMap.get(catalogueName.toLowerCase(Locale.US));
146     if (catalogue == null) {
147       String error = String.format("no catalogue found for %s. ", catalogueName);
148       if (catalogueName.toLowerCase(Locale.US).startsWith("tinkaead")) {
149         error += "Maybe call AeadConfig.register().";
150       }
151       if (catalogueName.toLowerCase(Locale.US).startsWith("tinkdeterministicaead")) {
152         error += "Maybe call DeterministicAeadConfig.register().";
153       } else if (catalogueName.toLowerCase(Locale.US).startsWith("tinkstreamingaead")) {
154         error += "Maybe call StreamingAeadConfig.register().";
155       } else if (catalogueName.toLowerCase(Locale.US).startsWith("tinkhybriddecrypt")
156           || catalogueName.toLowerCase(Locale.US).startsWith("tinkhybridencrypt")) {
157         error += "Maybe call HybridConfig.register().";
158       } else if (catalogueName.toLowerCase(Locale.US).startsWith("tinkmac")) {
159         error += "Maybe call MacConfig.register().";
160       } else if (catalogueName.toLowerCase(Locale.US).startsWith("tinkpublickeysign")
161           || catalogueName.toLowerCase(Locale.US).startsWith("tinkpublickeyverify")) {
162         error += "Maybe call SignatureConfig.register().";
163       } else if (catalogueName.toLowerCase(Locale.US).startsWith("tink")) {
164         error += "Maybe call TinkConfig.register().";
165       }
166       throw new GeneralSecurityException(error);
167     }
168     return catalogue;
169   }
170 
171   /**
172    * Tries to register {@code manager} for {@code manager.getKeyType()}. Users can generate new keys
173    * with this manager using the {@link Registry#newKey} methods.
174    *
175    * <p>If there is an existing key manager, throws an exception if {@code manager} and the existing
176    * key manager aren't instances of the same class, or the existing key manager could not create
177    * new keys. Otherwise registration succeeds.
178    *
179    * @throws GeneralSecurityException if there's an existing key manager is not an instance of the
180    *     class of {@code manager}, or the registration tries to re-enable the generation of new
181    *     keys.
182    */
registerKeyManager(final KeyManager<P> manager)183   public static synchronized <P> void registerKeyManager(final KeyManager<P> manager)
184       throws GeneralSecurityException {
185     registerKeyManager(manager, /* newKeyAllowed= */ true);
186   }
187 
createAllowedPrimitives()188   private static Set<Class<?>> createAllowedPrimitives() {
189     HashSet<Class<?>> result = new HashSet<>();
190     result.add(Aead.class);
191     result.add(DeterministicAead.class);
192     result.add(StreamingAead.class);
193     result.add(HybridEncrypt.class);
194     result.add(HybridDecrypt.class);
195     result.add(Mac.class);
196     result.add(Prf.class);
197     result.add(PublicKeySign.class);
198     result.add(PublicKeyVerify.class);
199     return result;
200   }
201 
202   private static final Set<Class<?>> ALLOWED_PRIMITIVES =
203       Collections.unmodifiableSet(createAllowedPrimitives());
204 
205   /**
206    * Tries to register {@code manager} for {@code manager.getKeyType()}. If {@code newKeyAllowed} is
207    * true, users can generate new keys with this manager using the {@link Registry#newKey} methods.
208    *
209    * <p>If there is an existing key manager, throws an exception if {@code manager} and the existing
210    * key manager aren't instances of the same class, or if {@code newKeyAllowed} is true while the
211    * existing key manager could not create new keys. Otherwise registration succeeds.
212    *
213    * @throws GeneralSecurityException if there's an existing key manager is not an instance of the
214    *     class of {@code manager}, or the registration tries to re-enable the generation of new
215    *     keys.
216    */
registerKeyManager( final KeyManager<P> manager, boolean newKeyAllowed)217   public static synchronized <P> void registerKeyManager(
218       final KeyManager<P> manager, boolean newKeyAllowed) throws GeneralSecurityException {
219     if (manager == null) {
220       throw new IllegalArgumentException("key manager must be non-null.");
221     }
222     if (!ALLOWED_PRIMITIVES.contains(manager.getPrimitiveClass())) {
223       throw new GeneralSecurityException(
224           "Registration of key managers for class "
225               + manager.getPrimitiveClass()
226               + " has been disabled. Please file an issue on"
227               + " https://github.com/tink-crypto/tink-java");
228     }
229     if (!TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_NOT_FIPS.isCompatible()) {
230       throw new GeneralSecurityException("Registering key managers is not supported in FIPS mode");
231     }
232     KeyManagerRegistry.globalInstance().registerKeyManager(manager, newKeyAllowed);
233   }
234 
235   /**
236    * Tries to register {@code manager} for the given {@code typeUrl}. Users can generate new keys
237    * with this manager using the {@link Registry#newKey} methods.
238    *
239    * <p>Does nothing if there's an existing key manager and it's an instance of the same class as
240    * {@code manager}.
241    *
242    * @throws GeneralSecurityException if there's an existing key manager and it is not an instance
243    *     of the same class as {@code manager}
244    * @deprecated use {@link #registerKeyManager(KeyManager) registerKeyManager(KeyManager&lt;P&gt;)}
245    */
246   @Deprecated
registerKeyManager( String typeUrl, final KeyManager<P> manager)247   public static synchronized <P> void registerKeyManager(
248       String typeUrl, final KeyManager<P> manager) throws GeneralSecurityException {
249     registerKeyManager(typeUrl, manager, /* newKeyAllowed= */ true);
250   }
251 
252   /**
253    * Tries to register {@code manager} for the given {@code typeUrl}. If {@code newKeyAllowed} is
254    * true, users can generate new keys with this manager using the {@link Registry#newKey} methods.
255    *
256    * <p>Does nothing if there's an existing key manager and it's an instance of the same class as
257    * {@code manager}.
258    *
259    * @throws GeneralSecurityException if there's an existing key manager and it is not an instance
260    *     of the same class as {@code manager}
261    * @deprecated use {@link #registerKeyManager(KeyManager, boolean)
262    *     registerKeyManager(KeyManager&lt;P&gt;, boolean)}
263    */
264   @Deprecated
registerKeyManager( String typeUrl, final KeyManager<P> manager, boolean newKeyAllowed)265   public static synchronized <P> void registerKeyManager(
266       String typeUrl, final KeyManager<P> manager, boolean newKeyAllowed)
267       throws GeneralSecurityException {
268     if (manager == null) {
269       throw new IllegalArgumentException("key manager must be non-null.");
270     }
271     if (!typeUrl.equals(manager.getKeyType())) {
272       throw new GeneralSecurityException("Manager does not support key type " + typeUrl + ".");
273     }
274     registerKeyManager(manager, newKeyAllowed);
275   }
276 
277   /**
278    * Returns a {@link KeyManager} for the given {@code typeUrl} (if found).
279    *
280    * @deprecated KeyManagers should not be used directly. Use {@code newKeyData} or {@code
281    *     getPrimitive} instead.
282    */
283   @Deprecated
getKeyManager(String typeUrl, Class<P> primitiveClass)284   public static <P> KeyManager<P> getKeyManager(String typeUrl, Class<P> primitiveClass)
285       throws GeneralSecurityException {
286     return KeyManagerRegistry.globalInstance().getKeyManager(typeUrl, primitiveClass);
287   }
288 
289   /**
290    * Returns a {@link KeyManager} for the given {@code typeUrl} (if found).
291    *
292    * @deprecated KeyManagers should not be used directly. Use {@code newKeyData} or {@code
293    *     getPrimitive} instead.
294    */
295   @Deprecated
getUntypedKeyManager(String typeUrl)296   public static KeyManager<?> getUntypedKeyManager(String typeUrl)
297       throws GeneralSecurityException {
298     return KeyManagerRegistry.globalInstance().getUntypedKeyManager(typeUrl);
299   }
300 
301   /**
302    * Generates a new {@link KeyData} for the specified {@code template}.
303    *
304    * <p>It looks up a {@link KeyManager} identified by {@code keyTemplate.type_url}, and calls
305    * {@link KeyManager#newKeyData}.
306    *
307    * <p>This method should be used solely for key management.
308    *
309    * @return a new {@link KeyData}
310    * @deprecated Use {@code KeysetHandle.generateNew} with a Parameters object instead. To convert a
311    *     proto KeyTemplate to a parameters one can use {@code
312    *     TinkProtoParametersFormat.parse(t.toByteArray());}
313    */
314   @Deprecated
newKeyData( com.google.crypto.tink.proto.KeyTemplate keyTemplate)315   public static synchronized KeyData newKeyData(
316       com.google.crypto.tink.proto.KeyTemplate keyTemplate) throws GeneralSecurityException {
317     KeyManager<?> manager =
318         KeyManagerRegistry.globalInstance().getUntypedKeyManager(keyTemplate.getTypeUrl());
319     if (KeyManagerRegistry.globalInstance().isNewKeyAllowed(keyTemplate.getTypeUrl())) {
320       return manager.newKeyData(keyTemplate.getValue());
321     } else {
322       throw new GeneralSecurityException(
323           "newKey-operation not permitted for key type " + keyTemplate.getTypeUrl());
324     }
325   }
326 
327   /**
328    * Generates a new {@link KeyData} for the specified {@code template}.
329    *
330    * <p>It looks up a {@link KeyManager} identified by {@code keyTemplate.type_url}, and calls
331    * {@link KeyManager#newKeyData}.
332    *
333    * <p>This method should be used solely for key management.
334    *
335    * @return a new {@link KeyData}
336    * @deprecated Use {@code KeysetHandle.generateNew(keyTemplate.toParameters())} instead and use
337    *     the Keyset Handle API.
338    */
339   @Deprecated
newKeyData( com.google.crypto.tink.KeyTemplate keyTemplate)340   public static synchronized KeyData newKeyData(
341       com.google.crypto.tink.KeyTemplate keyTemplate) throws GeneralSecurityException {
342     byte[] serializedKeyTemplate = TinkProtoParametersFormat.serialize(keyTemplate.toParameters());
343     try {
344       return newKeyData(
345           com.google.crypto.tink.proto.KeyTemplate.parseFrom(
346               serializedKeyTemplate, ExtensionRegistryLite.getEmptyRegistry()));
347     } catch (InvalidProtocolBufferException e) {
348       throw new GeneralSecurityException("Failed to parse serialized parameters", e);
349     }
350   }
351 
352   /**
353    * Generates a new key for the specified {@code keyTemplate}.
354    *
355    * <p>It looks up a {@link KeyManager} identified by {@code keyTemplate.type_url}, and calls
356    * {@link KeyManager#newKey} with {@code keyTemplate} as the parameter.
357    *
358    * @return a new key
359    * @deprecated Use {@code newKeyData} instead.
360    */
361   @Deprecated
newKey( com.google.crypto.tink.proto.KeyTemplate keyTemplate)362   public static synchronized MessageLite newKey(
363       com.google.crypto.tink.proto.KeyTemplate keyTemplate) throws GeneralSecurityException {
364     KeyManager<?> manager = getUntypedKeyManager(keyTemplate.getTypeUrl());
365     if (KeyManagerRegistry.globalInstance().isNewKeyAllowed(keyTemplate.getTypeUrl())) {
366       return manager.newKey(keyTemplate.getValue());
367     } else {
368       throw new GeneralSecurityException(
369           "newKey-operation not permitted for key type " + keyTemplate.getTypeUrl());
370     }
371   }
372 
373   /**
374    * Generates a new key for the specified {@code format}.
375    *
376    * <p>It looks up a {@link KeyManager} identified by {@code keyTemplate.type_url}, and calls
377    * {@link KeyManager#newKey} with {@code format} as the parameter.
378    *
379    * @return a new key
380    * @deprecated Use {@code newKeyData} instead.
381    */
382   @Deprecated
newKey(String typeUrl, MessageLite format)383   public static synchronized MessageLite newKey(String typeUrl, MessageLite format)
384       throws GeneralSecurityException {
385     KeyManager<?> manager = getUntypedKeyManager(typeUrl);
386     if (KeyManagerRegistry.globalInstance().isNewKeyAllowed(typeUrl)) {
387       return manager.newKey(format);
388     } else {
389       throw new GeneralSecurityException("newKey-operation not permitted for key type " + typeUrl);
390     }
391   }
392 
393   /**
394    * Extracts the public key data from the private key given in {@code serializedPrivateKey}.
395    *
396    * <p>It looks up a {@link PrivateKeyManager} identified by {@code typeUrl}, and calls {@link
397    * PrivateKeyManager#getPublicKeyData} with {@code serializedPrivateKey} as the parameter.
398    *
399    * @return the public key of the corresponding private key
400    * @deprecated Instead, users should have their keys in a {@link KeysetHandle} and call {@code
401    *     keysetHandle.getPublicKeysetHandle}.
402    */
403   @Deprecated
getPublicKeyData(String typeUrl, ByteString serializedPrivateKey)404   public static KeyData getPublicKeyData(String typeUrl, ByteString serializedPrivateKey)
405       throws GeneralSecurityException {
406     KeyManager<?> manager = getUntypedKeyManager(typeUrl);
407     if (!(manager instanceof PrivateKeyManager)) {
408       throw new GeneralSecurityException(
409           "manager for key type " + typeUrl + " is not a PrivateKeyManager");
410     }
411     return ((PrivateKeyManager) manager).getPublicKeyData(serializedPrivateKey);
412   }
413 
414   /**
415    * Creates a new primitive for the key given in {@code key}.
416    *
417    * <p>It looks up a {@link KeyManager} identified by {@code type_url}, and calls {@link
418    * KeyManager#getPrimitive} with {@code key} as the parameter.
419    *
420    * @return a new primitive
421    * @deprecated Use {@code getPrimitive(typeUrl, serializedKey, Primitive.class} instead.
422    */
423   @Deprecated
getPrimitive( String typeUrl, MessageLite key, Class<P> primitiveClass)424   public static <P> P getPrimitive(
425       String typeUrl, MessageLite key, Class<P> primitiveClass) throws GeneralSecurityException {
426     KeyManager<P> manager =
427         KeyManagerRegistry.globalInstance().getKeyManager(typeUrl, primitiveClass);
428     return manager.getPrimitive(key.toByteString());
429   }
430 
431   /**
432    * Creates a new primitive for the key given in {@code serializedKey}.
433    *
434    * <p>It looks up a {@link KeyManager} identified by {@code type_url}, and calls {@link
435    * KeyManager#getPrimitive} with {@code serialized} as the parameter.
436    *
437    * @return a new primitive
438    */
getPrimitive( String typeUrl, ByteString serializedKey, Class<P> primitiveClass)439   public static <P> P getPrimitive(
440       String typeUrl, ByteString serializedKey, Class<P> primitiveClass)
441       throws GeneralSecurityException {
442     KeyManager<P> manager =
443         KeyManagerRegistry.globalInstance().getKeyManager(typeUrl, primitiveClass);
444     return manager.getPrimitive(serializedKey);
445   }
446 
447   /**
448    * Creates a new primitive for the key given in {@code serializedKey}.
449    *
450    * <p>It looks up a {@link KeyManager} identified by {@code type_url}, and calls {@link
451    * KeyManager#getPrimitive} with {@code serialized} as the parameter.
452    *
453    * @return a new primitive
454    */
getPrimitive(String typeUrl, byte[] serializedKey, Class<P> primitiveClass)455   public static <P> P getPrimitive(String typeUrl, byte[] serializedKey, Class<P> primitiveClass)
456       throws GeneralSecurityException {
457     return getPrimitive(typeUrl, ByteString.copyFrom(serializedKey), primitiveClass);
458   }
459 
460   /**
461    * Creates a new primitive for the key given in {@code keyData}.
462    *
463    * <p>It looks up a {@link KeyManager} identified by {@code keyData.type_url}, and calls {@link
464    * KeyManager#getPrimitive} with {@code keyData.value} as the parameter.
465    *
466    * @return a new primitive
467    */
getPrimitive(KeyData keyData, Class<P> primitiveClass)468   public static <P> P getPrimitive(KeyData keyData, Class<P> primitiveClass)
469       throws GeneralSecurityException {
470     return getPrimitive(keyData.getTypeUrl(), keyData.getValue(), primitiveClass);
471   }
472 
getFullPrimitive(KeyT key, Class<P> primitiveClass)473   static <KeyT extends Key, P> P getFullPrimitive(KeyT key, Class<P> primitiveClass)
474       throws GeneralSecurityException {
475     return MutablePrimitiveRegistry.globalInstance().getPrimitive(key, primitiveClass);
476   }
477 
478   /**
479    * Looks up the globally registered PrimitiveWrapper for this primitive and wraps the given
480    * PrimitiveSet with it.
481    */
wrap(PrimitiveSet<B> primitiveSet, Class<P> clazz)482   public static <B, P> P wrap(PrimitiveSet<B> primitiveSet, Class<P> clazz)
483       throws GeneralSecurityException {
484     return MutablePrimitiveRegistry.globalInstance().wrap(primitiveSet, clazz);
485   }
486 
wrap(PrimitiveSet<P> primitiveSet)487   public static <P> P wrap(PrimitiveSet<P> primitiveSet)
488       throws GeneralSecurityException {
489     return wrap(primitiveSet, primitiveSet.getPrimitiveClass());
490   }
491 
492   /**
493    * Returns an immutable list of key template names supported by registered key managers that are
494    * allowed to generate new keys.
495    *
496    * @since 1.6.0
497    */
keyTemplates()498   public static synchronized List<String> keyTemplates() {
499     return MutableParametersRegistry.globalInstance().getNames();
500   }
501 
502   /**
503    * Returns the input primitive required when creating a {@code wrappedPrimitive}.
504    *
505    * <p>This returns the primitive class of the objects required when we want to create a wrapped
506    * primitive of type {@code wrappedPrimitive}. Returns {@code null} if no wrapper for this
507    * primitive has been registered.
508    */
509   @Nullable
getInputPrimitive(Class<?> wrappedPrimitive)510   public static Class<?> getInputPrimitive(Class<?> wrappedPrimitive) {
511     try {
512       return MutablePrimitiveRegistry.globalInstance().getInputPrimitiveClass(wrappedPrimitive);
513     } catch (GeneralSecurityException e) {
514       return null;
515     }
516   }
517 
518   /**
519    * Tries to enable the FIPS restrictions if the Registry is empty.
520    *
521    * @throws GeneralSecurityException if any key manager has already been registered.
522    */
restrictToFipsIfEmpty()523   public static synchronized void restrictToFipsIfEmpty() throws GeneralSecurityException {
524     KeyManagerRegistry.globalInstance().restrictToFipsIfEmptyAndGlobalInstance();
525   }
526 
Registry()527   private Registry() {}
528 }
529