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.aead; 18 19 import static com.google.crypto.tink.internal.TinkBugException.exceptionIsBug; 20 21 import com.google.crypto.tink.AccessesPartialKey; 22 import com.google.crypto.tink.Aead; 23 import com.google.crypto.tink.KeyManager; 24 import com.google.crypto.tink.KeyTemplate; 25 import com.google.crypto.tink.Parameters; 26 import com.google.crypto.tink.aead.internal.ChaCha20Poly1305Jce; 27 import com.google.crypto.tink.aead.internal.ChaCha20Poly1305ProtoSerialization; 28 import com.google.crypto.tink.config.internal.TinkFipsUtil; 29 import com.google.crypto.tink.internal.KeyManagerRegistry; 30 import com.google.crypto.tink.internal.LegacyKeyManagerImpl; 31 import com.google.crypto.tink.internal.MutableKeyCreationRegistry; 32 import com.google.crypto.tink.internal.MutableParametersRegistry; 33 import com.google.crypto.tink.internal.MutablePrimitiveRegistry; 34 import com.google.crypto.tink.internal.PrimitiveConstructor; 35 import com.google.crypto.tink.proto.KeyData.KeyMaterialType; 36 import com.google.crypto.tink.subtle.ChaCha20Poly1305; 37 import com.google.crypto.tink.util.SecretBytes; 38 import java.security.GeneralSecurityException; 39 import java.util.Collections; 40 import java.util.HashMap; 41 import java.util.Map; 42 import javax.annotation.Nullable; 43 44 /** 45 * This instance of {@code KeyManager} generates new {@code ChaCha20Poly1305} keys and produces new 46 * instances of {@code ChaCha20Poly1305}. 47 */ 48 public final class ChaCha20Poly1305KeyManager { 49 createAead(ChaCha20Poly1305Key key)50 private static Aead createAead(ChaCha20Poly1305Key key) throws GeneralSecurityException { 51 if (ChaCha20Poly1305Jce.isSupported()) { 52 return ChaCha20Poly1305Jce.create(key); 53 } 54 return ChaCha20Poly1305.create(key); 55 } 56 57 private static final PrimitiveConstructor<ChaCha20Poly1305Key, Aead> 58 CHA_CHA_20_POLY_1305_PRIMITIVE_CONSTRUCTOR = 59 PrimitiveConstructor.create( 60 ChaCha20Poly1305KeyManager::createAead, ChaCha20Poly1305Key.class, Aead.class); 61 62 private static final int KEY_SIZE_IN_BYTES = 32; 63 64 @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration. 65 private static final MutableKeyCreationRegistry.KeyCreator<ChaCha20Poly1305Parameters> 66 KEY_CREATOR = ChaCha20Poly1305KeyManager::createChaChaKey; 67 68 private static final KeyManager<Aead> legacyKeyManager = 69 LegacyKeyManagerImpl.create( 70 getKeyType(), 71 Aead.class, 72 KeyMaterialType.SYMMETRIC, 73 com.google.crypto.tink.proto.ChaCha20Poly1305Key.parser()); 74 75 @AccessesPartialKey createChaChaKey( ChaCha20Poly1305Parameters parameters, @Nullable Integer idRequirement)76 static com.google.crypto.tink.aead.ChaCha20Poly1305Key createChaChaKey( 77 ChaCha20Poly1305Parameters parameters, @Nullable Integer idRequirement) 78 throws GeneralSecurityException { 79 return com.google.crypto.tink.aead.ChaCha20Poly1305Key.create( 80 parameters.getVariant(), SecretBytes.randomBytes(KEY_SIZE_IN_BYTES), idRequirement); 81 } 82 getKeyType()83 static String getKeyType() { 84 return "type.googleapis.com/google.crypto.tink.ChaCha20Poly1305Key"; 85 } 86 namedParameters()87 private static Map<String, Parameters> namedParameters() throws GeneralSecurityException { 88 Map<String, Parameters> result = new HashMap<>(); 89 result.put( 90 "CHACHA20_POLY1305", 91 ChaCha20Poly1305Parameters.create(ChaCha20Poly1305Parameters.Variant.TINK)); 92 result.put( 93 "CHACHA20_POLY1305_RAW", 94 ChaCha20Poly1305Parameters.create(ChaCha20Poly1305Parameters.Variant.NO_PREFIX)); 95 return Collections.unmodifiableMap(result); 96 } 97 register(boolean newKeyAllowed)98 public static void register(boolean newKeyAllowed) throws GeneralSecurityException { 99 if (!TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_NOT_FIPS.isCompatible()) { 100 throw new GeneralSecurityException( 101 "Registering ChaCha20Poly1305 is not supported in FIPS mode"); 102 } 103 ChaCha20Poly1305ProtoSerialization.register(); 104 MutablePrimitiveRegistry.globalInstance() 105 .registerPrimitiveConstructor(CHA_CHA_20_POLY_1305_PRIMITIVE_CONSTRUCTOR); 106 MutableKeyCreationRegistry.globalInstance().add(KEY_CREATOR, ChaCha20Poly1305Parameters.class); 107 MutableParametersRegistry.globalInstance().putAll(namedParameters()); 108 KeyManagerRegistry.globalInstance().registerKeyManager(legacyKeyManager, newKeyAllowed); 109 } 110 111 /** 112 * @return a {@link KeyTemplate} that generates new instances of ChaCha20Poly1305 keys. 113 */ chaCha20Poly1305Template()114 public static final KeyTemplate chaCha20Poly1305Template() { 115 return exceptionIsBug( 116 () -> 117 KeyTemplate.createFrom( 118 ChaCha20Poly1305Parameters.create(ChaCha20Poly1305Parameters.Variant.TINK))); 119 } 120 121 /** 122 * @return a {@link KeyTemplate} that generates new instances of ChaCha20Poly1305 keys. Keys 123 * generated from this template create ciphertexts compatible with libsodium and other 124 * libraries. 125 */ rawChaCha20Poly1305Template()126 public static final KeyTemplate rawChaCha20Poly1305Template() { 127 return exceptionIsBug( 128 () -> 129 KeyTemplate.createFrom( 130 ChaCha20Poly1305Parameters.create(ChaCha20Poly1305Parameters.Variant.NO_PREFIX))); 131 } 132 ChaCha20Poly1305KeyManager()133 private ChaCha20Poly1305KeyManager() {} 134 } 135