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 17package org.conscrypt; 18 19import java.security.InvalidAlgorithmParameterException; 20import java.security.InvalidParameterException; 21import java.security.KeyPair; 22import java.security.KeyPairGenerator; 23import java.security.SecureRandom; 24import java.security.spec.AlgorithmParameterSpec; 25import java.security.spec.ECGenParameterSpec; 26import java.security.spec.ECParameterSpec; 27import java.util.ArrayList; 28import java.util.Arrays; 29import java.util.HashMap; 30import java.util.Map; 31 32/** 33 * An implementation of {@link KeyPairGenerator} for EC keys which uses BoringSSL to perform all the 34 * operations. 35 * 36 * @hide 37 */ 38@Internal 39public final class OpenSSLECKeyPairGenerator extends KeyPairGenerator { 40 private static final String ALGORITHM = "EC"; 41 42 private static final int DEFAULT_KEY_SIZE = 256; 43 44 private static final Map<Integer, String> SIZE_TO_CURVE_NAME = new HashMap<Integer, String>(); 45 46 static { 47 /* NIST curves */ 48 SIZE_TO_CURVE_NAME.put(224, "secp224r1"); 49 SIZE_TO_CURVE_NAME.put(256, "prime256v1"); 50 SIZE_TO_CURVE_NAME.put(384, "secp384r1"); 51 SIZE_TO_CURVE_NAME.put(521, "secp521r1"); 52 } 53 54 private OpenSSLECGroupContext group; 55 56 public OpenSSLECKeyPairGenerator() { 57 super(ALGORITHM); 58 } 59 60 @Override 61 public KeyPair generateKeyPair() { 62 if (group == null) { 63 final String curveName = SIZE_TO_CURVE_NAME.get(DEFAULT_KEY_SIZE); 64 group = OpenSSLECGroupContext.getCurveByName(curveName); 65 if (group == null) { 66 throw new RuntimeException("Curve not recognized: " + curveName); 67 } 68 } 69 70 final OpenSSLKey key = new OpenSSLKey( 71 NativeCrypto.EC_KEY_generate_key(group.getNativeRef())); 72 return new KeyPair(new OpenSSLECPublicKey(group, key), new OpenSSLECPrivateKey(group, key)); 73 } 74 75 @Override 76 public void initialize(int keysize, SecureRandom random) { 77 final String name = SIZE_TO_CURVE_NAME.get(keysize); 78 if (name == null) { 79 throw new InvalidParameterException("unknown key size " + keysize); 80 } 81 82 /* 83 * Store the group in a temporary variable until we know this is a valid 84 * group. 85 */ 86 final OpenSSLECGroupContext possibleGroup = OpenSSLECGroupContext.getCurveByName(name); 87 if (possibleGroup == null) { 88 throw new InvalidParameterException("unknown curve " + name); 89 } 90 91 group = possibleGroup; 92 } 93 94 @Override 95 public void initialize(AlgorithmParameterSpec param, SecureRandom random) 96 throws InvalidAlgorithmParameterException { 97 if (param instanceof ECParameterSpec) { 98 ECParameterSpec ecParam = (ECParameterSpec) param; 99 100 group = OpenSSLECGroupContext.getInstance(ecParam); 101 } else if (param instanceof ECGenParameterSpec) { 102 ECGenParameterSpec ecParam = (ECGenParameterSpec) param; 103 104 final String curveName = ecParam.getName(); 105 106 /* 107 * Store the group in a temporary variable until we know this is a 108 * valid group. 109 */ 110 final OpenSSLECGroupContext possibleGroup = OpenSSLECGroupContext 111 .getCurveByName(curveName); 112 if (possibleGroup == null) { 113 throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName); 114 } 115 116 group = possibleGroup; 117 } else { 118 throw new InvalidAlgorithmParameterException( 119 "parameter must be ECParameterSpec or ECGenParameterSpec"); 120 } 121 } 122 123 /** For testing. */ 124 public static void assertCurvesAreValid() { 125 ArrayList<String> invalidCurves = new ArrayList<>(); 126 for (String curveName : SIZE_TO_CURVE_NAME.values()) { 127 if (OpenSSLECGroupContext.getCurveByName(curveName) == null) { 128 invalidCurves.add(curveName); 129 } 130 } 131 if (invalidCurves.size() > 0) { 132 throw new AssertionError("Invalid curve names: " 133 + Arrays.toString(invalidCurves.toArray())); 134 } 135 } 136} 137