1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.conscrypt; 18 19 import java.security.InvalidAlgorithmParameterException; 20 import java.security.InvalidParameterException; 21 import java.security.KeyPair; 22 import java.security.KeyPairGenerator; 23 import java.security.SecureRandom; 24 import java.security.spec.AlgorithmParameterSpec; 25 import java.security.spec.ECGenParameterSpec; 26 import java.security.spec.ECParameterSpec; 27 import java.util.ArrayList; 28 import java.util.Arrays; 29 import java.util.HashMap; 30 import java.util.Map; 31 32 public final class OpenSSLECKeyPairGenerator extends KeyPairGenerator { 33 private static final String ALGORITHM = "EC"; 34 35 private static final int DEFAULT_KEY_SIZE = 256; 36 37 private static final Map<Integer, String> SIZE_TO_CURVE_NAME = new HashMap<Integer, String>(); 38 39 static { 40 /* NIST curves */ 41 SIZE_TO_CURVE_NAME.put(224, "secp224r1"); 42 SIZE_TO_CURVE_NAME.put(256, "prime256v1"); 43 SIZE_TO_CURVE_NAME.put(384, "secp384r1"); 44 SIZE_TO_CURVE_NAME.put(521, "secp521r1"); 45 } 46 47 private OpenSSLECGroupContext group; 48 OpenSSLECKeyPairGenerator()49 public OpenSSLECKeyPairGenerator() { 50 super(ALGORITHM); 51 } 52 53 @Override generateKeyPair()54 public KeyPair generateKeyPair() { 55 if (group == null) { 56 final String curveName = SIZE_TO_CURVE_NAME.get(DEFAULT_KEY_SIZE); 57 group = OpenSSLECGroupContext.getCurveByName(curveName); 58 if (group == null) { 59 throw new RuntimeException("Curve not recognized: " + curveName); 60 } 61 } 62 63 final OpenSSLKey key = new OpenSSLKey( 64 NativeCrypto.EC_KEY_generate_key(group.getNativeRef())); 65 return new KeyPair(new OpenSSLECPublicKey(group, key), new OpenSSLECPrivateKey(group, key)); 66 } 67 68 @Override initialize(int keysize, SecureRandom random)69 public void initialize(int keysize, SecureRandom random) { 70 final String name = SIZE_TO_CURVE_NAME.get(keysize); 71 if (name == null) { 72 throw new InvalidParameterException("unknown key size " + keysize); 73 } 74 75 /* 76 * Store the group in a temporary variable until we know this is a valid 77 * group. 78 */ 79 final OpenSSLECGroupContext possibleGroup = OpenSSLECGroupContext.getCurveByName(name); 80 if (possibleGroup == null) { 81 throw new InvalidParameterException("unknown curve " + name); 82 } 83 84 group = possibleGroup; 85 } 86 87 @Override initialize(AlgorithmParameterSpec param, SecureRandom random)88 public void initialize(AlgorithmParameterSpec param, SecureRandom random) 89 throws InvalidAlgorithmParameterException { 90 if (param instanceof ECParameterSpec) { 91 ECParameterSpec ecParam = (ECParameterSpec) param; 92 93 group = OpenSSLECGroupContext.getInstance(ecParam); 94 } else if (param instanceof ECGenParameterSpec) { 95 ECGenParameterSpec ecParam = (ECGenParameterSpec) param; 96 97 final String curveName = ecParam.getName(); 98 99 /* 100 * Store the group in a temporary variable until we know this is a 101 * valid group. 102 */ 103 final OpenSSLECGroupContext possibleGroup = OpenSSLECGroupContext 104 .getCurveByName(curveName); 105 if (possibleGroup == null) { 106 throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName); 107 } 108 109 group = possibleGroup; 110 } else { 111 throw new InvalidAlgorithmParameterException( 112 "parameter must be ECParameterSpec or ECGenParameterSpec"); 113 } 114 } 115 116 /** For testing. */ assertCurvesAreValid()117 public static void assertCurvesAreValid() { 118 ArrayList<String> invalidCurves = new ArrayList<>(); 119 for (String curveName : SIZE_TO_CURVE_NAME.values()) { 120 if (OpenSSLECGroupContext.getCurveByName(curveName) == null) { 121 invalidCurves.add(curveName); 122 } 123 } 124 if (invalidCurves.size() > 0) { 125 throw new AssertionError("Invalid curve names: " 126 + Arrays.toString(invalidCurves.toArray())); 127 } 128 } 129 } 130