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<P>)} 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<P>, 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