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.SecretKeyAccess; 27 import com.google.crypto.tink.aead.internal.XChaCha20Poly1305Jce; 28 import com.google.crypto.tink.aead.internal.XChaCha20Poly1305ProtoSerialization; 29 import com.google.crypto.tink.config.internal.TinkFipsUtil; 30 import com.google.crypto.tink.internal.KeyManagerRegistry; 31 import com.google.crypto.tink.internal.LegacyKeyManagerImpl; 32 import com.google.crypto.tink.internal.MutableKeyCreationRegistry; 33 import com.google.crypto.tink.internal.MutableKeyDerivationRegistry; 34 import com.google.crypto.tink.internal.MutableParametersRegistry; 35 import com.google.crypto.tink.internal.MutablePrimitiveRegistry; 36 import com.google.crypto.tink.internal.PrimitiveConstructor; 37 import com.google.crypto.tink.internal.Util; 38 import com.google.crypto.tink.proto.KeyData.KeyMaterialType; 39 import com.google.crypto.tink.subtle.XChaCha20Poly1305; 40 import com.google.crypto.tink.util.SecretBytes; 41 import java.io.InputStream; 42 import java.security.GeneralSecurityException; 43 import java.util.Collections; 44 import java.util.HashMap; 45 import java.util.Map; 46 import javax.annotation.Nullable; 47 48 /** 49 * This instance of {@code KeyManager} generates new {@code XChaCha20Poly1305} keys and produces new 50 * instances of {@code XChaCha20Poly1305}. 51 */ 52 public final class XChaCha20Poly1305KeyManager { 53 createAead(XChaCha20Poly1305Key key)54 private static Aead createAead(XChaCha20Poly1305Key key) throws GeneralSecurityException { 55 if (XChaCha20Poly1305Jce.isSupported()) { 56 return XChaCha20Poly1305Jce.create(key); 57 } 58 return XChaCha20Poly1305.create(key); 59 } 60 61 private static final PrimitiveConstructor<XChaCha20Poly1305Key, Aead> 62 X_CHA_CHA_20_POLY_1305_PRIMITIVE_CONSTRUCTOR = 63 PrimitiveConstructor.create( 64 XChaCha20Poly1305KeyManager::createAead, XChaCha20Poly1305Key.class, Aead.class); 65 66 private static final int KEY_SIZE_IN_BYTES = 32; 67 getKeyType()68 static String getKeyType() { 69 return "type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key"; 70 } 71 72 private static final KeyManager<Aead> legacyKeyManager = 73 LegacyKeyManagerImpl.create( 74 getKeyType(), 75 Aead.class, 76 KeyMaterialType.SYMMETRIC, 77 com.google.crypto.tink.proto.XChaCha20Poly1305Key.parser()); 78 79 @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration. 80 private static final MutableKeyDerivationRegistry.InsecureKeyCreator<XChaCha20Poly1305Parameters> 81 KEY_DERIVER = XChaCha20Poly1305KeyManager::createXChaChaKeyFromRandomness; 82 83 @AccessesPartialKey createXChaChaKeyFromRandomness( XChaCha20Poly1305Parameters parameters, InputStream stream, @Nullable Integer idRequirement, SecretKeyAccess access)84 static com.google.crypto.tink.aead.XChaCha20Poly1305Key createXChaChaKeyFromRandomness( 85 XChaCha20Poly1305Parameters parameters, 86 InputStream stream, 87 @Nullable Integer idRequirement, 88 SecretKeyAccess access) 89 throws GeneralSecurityException { 90 return com.google.crypto.tink.aead.XChaCha20Poly1305Key.create( 91 parameters.getVariant(), 92 Util.readIntoSecretBytes(stream, KEY_SIZE_IN_BYTES, access), 93 idRequirement); 94 } 95 96 @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration. 97 private static final MutableKeyCreationRegistry.KeyCreator<XChaCha20Poly1305Parameters> 98 KEY_CREATOR = XChaCha20Poly1305KeyManager::createXChaChaKey; 99 100 @AccessesPartialKey createXChaChaKey( XChaCha20Poly1305Parameters parameters, @Nullable Integer idRequirement)101 static com.google.crypto.tink.aead.XChaCha20Poly1305Key createXChaChaKey( 102 XChaCha20Poly1305Parameters parameters, @Nullable Integer idRequirement) 103 throws GeneralSecurityException { 104 return com.google.crypto.tink.aead.XChaCha20Poly1305Key.create( 105 parameters.getVariant(), SecretBytes.randomBytes(KEY_SIZE_IN_BYTES), idRequirement); 106 } 107 namedParameters()108 private static Map<String, Parameters> namedParameters() throws GeneralSecurityException { 109 Map<String, Parameters> result = new HashMap<>(); 110 result.put( 111 "XCHACHA20_POLY1305", 112 XChaCha20Poly1305Parameters.create(XChaCha20Poly1305Parameters.Variant.TINK)); 113 result.put( 114 "XCHACHA20_POLY1305_RAW", 115 XChaCha20Poly1305Parameters.create(XChaCha20Poly1305Parameters.Variant.NO_PREFIX)); 116 return Collections.unmodifiableMap(result); 117 } 118 register(boolean newKeyAllowed)119 public static void register(boolean newKeyAllowed) throws GeneralSecurityException { 120 if (!TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_NOT_FIPS.isCompatible()) { 121 throw new GeneralSecurityException( 122 "Registering XChaCha20Poly1305 is not supported in FIPS mode"); 123 } 124 XChaCha20Poly1305ProtoSerialization.register(); 125 MutablePrimitiveRegistry.globalInstance() 126 .registerPrimitiveConstructor(X_CHA_CHA_20_POLY_1305_PRIMITIVE_CONSTRUCTOR); 127 MutableParametersRegistry.globalInstance().putAll(namedParameters()); 128 MutableKeyCreationRegistry.globalInstance().add(KEY_CREATOR, XChaCha20Poly1305Parameters.class); 129 MutableKeyDerivationRegistry.globalInstance() 130 .add(KEY_DERIVER, XChaCha20Poly1305Parameters.class); 131 KeyManagerRegistry.globalInstance().registerKeyManager(legacyKeyManager, newKeyAllowed); 132 } 133 134 /** 135 * @return a {@link KeyTemplate} that generates new instances of XChaCha20Poly1305 keys. 136 */ xChaCha20Poly1305Template()137 public static final KeyTemplate xChaCha20Poly1305Template() { 138 return exceptionIsBug( 139 () -> 140 KeyTemplate.createFrom( 141 XChaCha20Poly1305Parameters.create(XChaCha20Poly1305Parameters.Variant.TINK))); 142 } 143 144 /** 145 * @return a {@link KeyTemplate} that generates new instances of XChaCha20Poly1305 keys. Keys 146 * generated from this template create ciphertexts compatible with libsodium and other 147 * libraries. 148 */ rawXChaCha20Poly1305Template()149 public static final KeyTemplate rawXChaCha20Poly1305Template() { 150 return exceptionIsBug( 151 () -> 152 KeyTemplate.createFrom( 153 XChaCha20Poly1305Parameters.create(XChaCha20Poly1305Parameters.Variant.NO_PREFIX))); 154 } 155 XChaCha20Poly1305KeyManager()156 private XChaCha20Poly1305KeyManager() {} 157 } 158