1 /* 2 * Copyright (c) 2009, 2017, 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 import static sun.security.util.SecurityProviderConstants.DEF_EC_KEY_SIZE; 42 43 /** 44 * EC keypair generator. 45 * Standard algorithm, minimum key length is 112 bits, maximum is 571 bits. 46 * 47 * @since 1.7 48 */ 49 public final class ECKeyPairGenerator extends KeyPairGeneratorSpi { 50 51 private static final int KEY_SIZE_MIN = 112; // min bits (see ecc_impl.h) 52 private static final int KEY_SIZE_MAX = 571; // max bits (see ecc_impl.h) 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(DEF_EC_KEY_SIZE, 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 try { 127 128 Object[] keyBytes = generateECKeyPair(keySize, encodedParams, seed); 129 130 // The 'params' object supplied above is equivalent to the native 131 // one so there is no need to fetch it. 132 // keyBytes[0] is the encoding of the native private key 133 BigInteger s = new BigInteger(1, (byte[])keyBytes[0]); 134 135 PrivateKey privateKey = 136 new ECPrivateKeyImpl(s, (ECParameterSpec)params); 137 138 // keyBytes[1] is the encoding of the native public key 139 ECPoint w = ECUtil.decodePoint((byte[])keyBytes[1], 140 ((ECParameterSpec)params).getCurve()); 141 PublicKey publicKey = 142 new ECPublicKeyImpl(w, (ECParameterSpec)params); 143 144 return new KeyPair(publicKey, privateKey); 145 146 } catch (Exception e) { 147 throw new ProviderException(e); 148 } 149 } 150 151 private void checkKeySize(int keySize) throws InvalidParameterException { 152 if (keySize < KEY_SIZE_MIN) { 153 throw new InvalidParameterException 154 ("Key size must be at least " + KEY_SIZE_MIN + " bits"); 155 } 156 if (keySize > KEY_SIZE_MAX) { 157 throw new InvalidParameterException 158 ("Key size must be at most " + KEY_SIZE_MAX + " bits"); 159 } 160 this.keySize = keySize; 161 } 162 163 /* 164 * Generates the keypair and returns a 2-element array of encoding bytes. 165 * The first one is for the private key, the second for the public key. 166 */ 167 private static native Object[] generateECKeyPair(int keySize, 168 byte[] encodedParams, byte[] seed) throws GeneralSecurityException; 169 }