1 /* 2 * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.ec; 27 28 import java.math.BigInteger; 29 import java.security.*; 30 import java.security.spec.AlgorithmParameterSpec; 31 import java.security.spec.ECGenParameterSpec; 32 import java.security.spec.ECParameterSpec; 33 import java.security.spec.ECPoint; 34 35 import sun.security.ec.NamedCurve; 36 import sun.security.ec.ECParameters; 37 import sun.security.ec.ECPrivateKeyImpl; 38 import sun.security.ec.ECPublicKeyImpl; 39 import sun.security.jca.JCAUtil; 40 import sun.security.util.ECUtil; 41 42 /** 43 * EC keypair generator. 44 * Standard algorithm, minimum key length is 112 bits, maximum is 571 bits. 45 * 46 * @since 1.7 47 */ 48 public final class ECKeyPairGenerator extends KeyPairGeneratorSpi { 49 50 private static final int KEY_SIZE_MIN = 112; // min bits (see ecc_impl.h) 51 private static final int KEY_SIZE_MAX = 571; // max bits (see ecc_impl.h) 52 private static final int KEY_SIZE_DEFAULT = 256; 53 54 // used to seed the keypair generator 55 private SecureRandom random; 56 57 // size of the key to generate, KEY_SIZE_MIN <= keySize <= KEY_SIZE_MAX 58 private int keySize; 59 60 // parameters specified via init, if any 61 private AlgorithmParameterSpec params = null; 62 63 /** 64 * Constructs a new ECKeyPairGenerator. 65 */ 66 public ECKeyPairGenerator() { 67 // initialize to default in case the app does not call initialize() 68 initialize(KEY_SIZE_DEFAULT, null); 69 } 70 71 // initialize the generator. See JCA doc 72 @Override 73 public void initialize(int keySize, SecureRandom random) { 74 75 checkKeySize(keySize); 76 this.params = ECUtil.getECParameterSpec(null, keySize); 77 if (params == null) { 78 throw new InvalidParameterException( 79 "No EC parameters available for key size " + keySize + " bits"); 80 } 81 this.random = random; 82 } 83 84 // second initialize method. See JCA doc 85 @Override 86 public void initialize(AlgorithmParameterSpec params, SecureRandom random) 87 throws InvalidAlgorithmParameterException { 88 89 if (params instanceof ECParameterSpec) { 90 this.params = ECUtil.getECParameterSpec(null, 91 (ECParameterSpec)params); 92 if (this.params == null) { 93 throw new InvalidAlgorithmParameterException( 94 "Unsupported curve: " + params); 95 } 96 } else if (params instanceof ECGenParameterSpec) { 97 String name = ((ECGenParameterSpec)params).getName(); 98 this.params = ECUtil.getECParameterSpec(null, name); 99 if (this.params == null) { 100 throw new InvalidAlgorithmParameterException( 101 "Unknown curve name: " + name); 102 } 103 } else { 104 throw new InvalidAlgorithmParameterException( 105 "ECParameterSpec or ECGenParameterSpec required for EC"); 106 } 107 this.keySize = 108 ((ECParameterSpec)this.params).getCurve().getField().getFieldSize(); 109 this.random = random; 110 } 111 112 // generate the keypair. See JCA doc 113 @Override 114 public KeyPair generateKeyPair() { 115 116 byte[] encodedParams = 117 ECUtil.encodeECParameterSpec(null, (ECParameterSpec)params); 118 119 // seed is twice the key size (in bytes) plus 1 120 byte[] seed = new byte[(((keySize + 7) >> 3) + 1) * 2]; 121 if (random == null) { 122 random = JCAUtil.getSecureRandom(); 123 } 124 random.nextBytes(seed); 125 126 long[] handles = null; 127 try { 128 129 handles = generateECKeyPair(keySize, encodedParams, seed); 130 131 // The 'params' object supplied above is equivalent to the native 132 // one so there is no need to fetch it. 133 134 // handles[0] points to the native private key 135 BigInteger s = new BigInteger(1, getEncodedBytes(handles[0])); 136 137 PrivateKey privateKey = 138 new ECPrivateKeyImpl(s, (ECParameterSpec)params); 139 140 // handles[1] points to the native public key 141 ECPoint w = ECUtil.decodePoint(getEncodedBytes(handles[1]), 142 ((ECParameterSpec)params).getCurve()); 143 PublicKey publicKey = 144 new ECPublicKeyImpl(w, (ECParameterSpec)params); 145 146 return new KeyPair(publicKey, privateKey); 147 148 } catch (Exception e) { 149 throw new ProviderException(e); 150 } finally { 151 if (handles != null) { 152 // handles[2] points to the data structure containing 153 // both the native public and private key. 154 releaseECKeyPairData(handles[2]); 155 } 156 } 157 } 158 159 private void checkKeySize(int keySize) throws InvalidParameterException { 160 if (keySize < KEY_SIZE_MIN) { 161 throw new InvalidParameterException 162 ("Key size must be at least " + KEY_SIZE_MIN + " bits"); 163 } 164 if (keySize > KEY_SIZE_MAX) { 165 throw new InvalidParameterException 166 ("Key size must be at most " + KEY_SIZE_MAX + " bits"); 167 } 168 this.keySize = keySize; 169 } 170 171 /* 172 * Generates the keypair and returns a 2-element array of handles. 173 * The first handle points to the private key, the second to the public key. 174 */ 175 private static native long[] generateECKeyPair(int keySize, 176 byte[] encodedParams, byte[] seed) throws GeneralSecurityException; 177 178 179 /* 180 * Releases the native memory allocated by generateECKeyPair. 181 */ 182 private static native void releaseECKeyPairData(long privKeyHandle); 183 184 /* 185 * Extracts the encoded key data using the supplied handle. 186 */ 187 private static native byte[] getEncodedBytes(long handle); 188 }