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.signature; 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.InsecureSecretKeyAccess; 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.PrivateKeyManager; 27 import com.google.crypto.tink.PublicKeySign; 28 import com.google.crypto.tink.PublicKeyVerify; 29 import com.google.crypto.tink.SecretKeyAccess; 30 import com.google.crypto.tink.config.internal.TinkFipsUtil; 31 import com.google.crypto.tink.internal.KeyManagerRegistry; 32 import com.google.crypto.tink.internal.LegacyKeyManagerImpl; 33 import com.google.crypto.tink.internal.MutableKeyCreationRegistry; 34 import com.google.crypto.tink.internal.MutableKeyDerivationRegistry; 35 import com.google.crypto.tink.internal.MutableParametersRegistry; 36 import com.google.crypto.tink.internal.MutablePrimitiveRegistry; 37 import com.google.crypto.tink.internal.PrimitiveConstructor; 38 import com.google.crypto.tink.internal.Util; 39 import com.google.crypto.tink.proto.KeyData.KeyMaterialType; 40 import com.google.crypto.tink.signature.internal.Ed25519ProtoSerialization; 41 import com.google.crypto.tink.subtle.Ed25519Sign; 42 import com.google.crypto.tink.subtle.Ed25519Verify; 43 import com.google.crypto.tink.util.Bytes; 44 import com.google.crypto.tink.util.SecretBytes; 45 import java.io.InputStream; 46 import java.security.GeneralSecurityException; 47 import java.util.Collections; 48 import java.util.HashMap; 49 import java.util.Map; 50 import javax.annotation.Nullable; 51 52 /** 53 * This instance of {@code KeyManager} generates new {@code Ed25519PrivateKey} keys and produces new 54 * instances of {@code Ed25519Sign}. 55 */ 56 public final class Ed25519PrivateKeyManager { 57 private static final PrimitiveConstructor<Ed25519PrivateKey, PublicKeySign> 58 PUBLIC_KEY_SIGN_PRIMITIVE_CONSTRUCTOR = 59 PrimitiveConstructor.create( 60 Ed25519Sign::create, Ed25519PrivateKey.class, PublicKeySign.class); 61 62 private static final PrimitiveConstructor<Ed25519PublicKey, PublicKeyVerify> 63 PUBLIC_KEY_VERIFY_PRIMITIVE_CONSTRUCTOR = 64 PrimitiveConstructor.create( 65 Ed25519Verify::create, Ed25519PublicKey.class, PublicKeyVerify.class); 66 67 private static final PrivateKeyManager<PublicKeySign> legacyPrivateKeyManager = 68 LegacyKeyManagerImpl.createPrivateKeyManager( 69 getKeyType(), 70 PublicKeySign.class, 71 com.google.crypto.tink.proto.Ed25519PrivateKey.parser()); 72 73 private static final KeyManager<PublicKeyVerify> legacyPublicKeyManager = 74 LegacyKeyManagerImpl.create( 75 Ed25519PublicKeyManager.getKeyType(), 76 PublicKeyVerify.class, 77 KeyMaterialType.ASYMMETRIC_PUBLIC, 78 com.google.crypto.tink.proto.Ed25519PublicKey.parser()); 79 getKeyType()80 static String getKeyType() { 81 return "type.googleapis.com/google.crypto.tink.Ed25519PrivateKey"; 82 } 83 84 @AccessesPartialKey createEd25519KeyFromRandomness( Ed25519Parameters parameters, InputStream stream, @Nullable Integer idRequirement, SecretKeyAccess access)85 static com.google.crypto.tink.signature.Ed25519PrivateKey createEd25519KeyFromRandomness( 86 Ed25519Parameters parameters, 87 InputStream stream, 88 @Nullable Integer idRequirement, 89 SecretKeyAccess access) 90 throws GeneralSecurityException { 91 SecretBytes pseudorandomness = 92 Util.readIntoSecretBytes(stream, Ed25519Sign.SECRET_KEY_LEN, access); 93 Ed25519Sign.KeyPair keyPair = 94 Ed25519Sign.KeyPair.newKeyPairFromSeed(pseudorandomness.toByteArray(access)); 95 com.google.crypto.tink.signature.Ed25519PublicKey publicKey = 96 com.google.crypto.tink.signature.Ed25519PublicKey.create( 97 parameters.getVariant(), Bytes.copyFrom(keyPair.getPublicKey()), idRequirement); 98 return com.google.crypto.tink.signature.Ed25519PrivateKey.create( 99 publicKey, SecretBytes.copyFrom(keyPair.getPrivateKey(), access)); 100 } 101 102 @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration. 103 private static final MutableKeyDerivationRegistry.InsecureKeyCreator<Ed25519Parameters> 104 KEY_DERIVER = Ed25519PrivateKeyManager::createEd25519KeyFromRandomness; 105 106 @AccessesPartialKey createEd25519Key( Ed25519Parameters parameters, @Nullable Integer idRequirement)107 static com.google.crypto.tink.signature.Ed25519PrivateKey createEd25519Key( 108 Ed25519Parameters parameters, @Nullable Integer idRequirement) 109 throws GeneralSecurityException { 110 Ed25519Sign.KeyPair keyPair = Ed25519Sign.KeyPair.newKeyPair(); 111 com.google.crypto.tink.signature.Ed25519PublicKey publicKey = 112 com.google.crypto.tink.signature.Ed25519PublicKey.create( 113 parameters.getVariant(), Bytes.copyFrom(keyPair.getPublicKey()), idRequirement); 114 return com.google.crypto.tink.signature.Ed25519PrivateKey.create( 115 publicKey, SecretBytes.copyFrom(keyPair.getPrivateKey(), InsecureSecretKeyAccess.get())); 116 } 117 118 @SuppressWarnings("InlineLambdaConstant") // We need a correct Object#equals in registration. 119 private static final MutableKeyCreationRegistry.KeyCreator<Ed25519Parameters> KEY_CREATOR = 120 Ed25519PrivateKeyManager::createEd25519Key; 121 namedParameters()122 private static Map<String, Parameters> namedParameters() throws GeneralSecurityException { 123 Map<String, Parameters> result = new HashMap<>(); 124 result.put("ED25519", Ed25519Parameters.create(Ed25519Parameters.Variant.TINK)); 125 result.put("ED25519_RAW", Ed25519Parameters.create(Ed25519Parameters.Variant.NO_PREFIX)); 126 // This is identical to ED25519_RAW. 127 // It is needed to maintain backward compatibility with SignatureKeyTemplates. 128 result.put( 129 "ED25519WithRawOutput", Ed25519Parameters.create(Ed25519Parameters.Variant.NO_PREFIX)); 130 return Collections.unmodifiableMap(result); 131 } 132 133 /** 134 * Registers the {@link Ed25519PrivateKeyManager} and the {@link Ed25519PublicKeyManager} with the 135 * registry, so that the the Ed25519-Keys can be used with Tink. 136 */ registerPair(boolean newKeyAllowed)137 public static void registerPair(boolean newKeyAllowed) throws GeneralSecurityException { 138 if (!TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_NOT_FIPS.isCompatible()) { 139 throw new GeneralSecurityException("Registering AES GCM SIV is not supported in FIPS mode"); 140 } 141 Ed25519ProtoSerialization.register(); 142 MutableParametersRegistry.globalInstance().putAll(namedParameters()); 143 MutableKeyCreationRegistry.globalInstance().add(KEY_CREATOR, Ed25519Parameters.class); 144 MutableKeyDerivationRegistry.globalInstance().add(KEY_DERIVER, Ed25519Parameters.class); 145 MutablePrimitiveRegistry.globalInstance() 146 .registerPrimitiveConstructor(PUBLIC_KEY_SIGN_PRIMITIVE_CONSTRUCTOR); 147 MutablePrimitiveRegistry.globalInstance() 148 .registerPrimitiveConstructor(PUBLIC_KEY_VERIFY_PRIMITIVE_CONSTRUCTOR); 149 KeyManagerRegistry.globalInstance().registerKeyManager(legacyPrivateKeyManager, newKeyAllowed); 150 KeyManagerRegistry.globalInstance() 151 .registerKeyManager(legacyPublicKeyManager, /* newKeyAllowed= */ false); 152 } 153 154 /** 155 * @return A {@link KeyTemplate} that generates new instances of ED25519 keys. 156 */ ed25519Template()157 public static final KeyTemplate ed25519Template() { 158 return exceptionIsBug( 159 () -> KeyTemplate.createFrom(Ed25519Parameters.create(Ed25519Parameters.Variant.TINK))); 160 } 161 162 /** 163 * @return A {@link KeyTemplate} that generates new instances of Ed25519 keys. Keys generated from 164 * this template creates raw signatures of exactly 64 bytes. It's compatible with most other 165 * libraries. 166 */ rawEd25519Template()167 public static final KeyTemplate rawEd25519Template() { 168 return exceptionIsBug( 169 () -> 170 KeyTemplate.createFrom(Ed25519Parameters.create(Ed25519Parameters.Variant.NO_PREFIX))); 171 } 172 Ed25519PrivateKeyManager()173 private Ed25519PrivateKeyManager() {} 174 } 175