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.io.IOException;
29 import java.math.BigInteger;
30 import java.security.*;
31 import java.security.spec.AlgorithmParameterSpec;
32 import java.security.spec.ECGenParameterSpec;
33 import java.security.spec.ECParameterSpec;
34 import java.security.spec.ECPoint;
35 import java.security.spec.InvalidParameterSpecException;
36
37 import sun.security.ec.ECPrivateKeyImpl;
38 import sun.security.ec.ECPublicKeyImpl;
39 import sun.security.jca.JCAUtil;
40 import sun.security.util.ECParameters;
41 import sun.security.util.ECUtil;
42 import static sun.security.util.SecurityProviderConstants.DEF_EC_KEY_SIZE;
43
44 /**
45 * EC keypair generator.
46 * Standard algorithm, minimum key length is 112 bits, maximum is 571 bits.
47 *
48 * @since 1.7
49 */
50 public final class ECKeyPairGenerator extends KeyPairGeneratorSpi {
51
52 private static final int KEY_SIZE_MIN = 112; // min bits (see ecc_impl.h)
53 private static final int KEY_SIZE_MAX = 571; // max bits (see ecc_impl.h)
54
55 // used to seed the keypair generator
56 private SecureRandom random;
57
58 // size of the key to generate, KEY_SIZE_MIN <= keySize <= KEY_SIZE_MAX
59 private int keySize;
60
61 // parameters specified via init, if any
62 private AlgorithmParameterSpec params = null;
73 @Override
74 public void initialize(int keySize, SecureRandom random) {
75
76 checkKeySize(keySize);
77 this.params = ECUtil.getECParameterSpec(null, keySize);
78 if (params == null) {
79 throw new InvalidParameterException(
80 "No EC parameters available for key size " + keySize + " bits");
81 }
82 this.random = random;
83 }
84
85 // second initialize method. See JCA doc
86 @Override
87 public void initialize(AlgorithmParameterSpec params, SecureRandom random)
88 throws InvalidAlgorithmParameterException {
89
90 ECParameterSpec ecSpec = null;
91
92 if (params instanceof ECParameterSpec) {
93 ecSpec = ECUtil.getECParameterSpec(null,
94 (ECParameterSpec)params);
95 if (ecSpec == null) {
96 throw new InvalidAlgorithmParameterException(
97 "Unsupported curve: " + params);
98 }
99 } else if (params instanceof ECGenParameterSpec) {
100 String name = ((ECGenParameterSpec)params).getName();
101 ecSpec = ECUtil.getECParameterSpec(null, name);
102 if (ecSpec == null) {
103 throw new InvalidAlgorithmParameterException(
104 "Unknown curve name: " + name);
105 }
106 } else {
107 throw new InvalidAlgorithmParameterException(
108 "ECParameterSpec or ECGenParameterSpec required for EC");
109 }
110
111 // Not all known curves are supported by the native implementation
112 ensureCurveIsSupported(ecSpec);
113 this.params = ecSpec;
114
115 this.keySize =
116 ((ECParameterSpec)this.params).getCurve().getField().getFieldSize();
117 this.random = random;
118 }
119
120 private static void ensureCurveIsSupported(ECParameterSpec ecSpec)
121 throws InvalidAlgorithmParameterException {
122
123 AlgorithmParameters ecParams = ECUtil.getECParameters(null);
124 byte[] encodedParams;
125 try {
126 ecParams.init(ecSpec);
127 encodedParams = ecParams.getEncoded();
128 } catch (InvalidParameterSpecException ex) {
129 throw new InvalidAlgorithmParameterException(
130 "Unsupported curve: " + ecSpec.toString());
131 } catch (IOException ex) {
132 throw new RuntimeException(ex);
133 }
134 if (!isCurveSupported(encodedParams)) {
135 throw new InvalidAlgorithmParameterException(
136 "Unsupported curve: " + ecParams.toString());
137 }
138 }
139
140 // generate the keypair. See JCA doc
141 @Override
142 public KeyPair generateKeyPair() {
143
144 byte[] encodedParams =
145 ECUtil.encodeECParameterSpec(null, (ECParameterSpec)params);
146
147 // seed is twice the key size (in bytes) plus 1
148 byte[] seed = new byte[(((keySize + 7) >> 3) + 1) * 2];
149 if (random == null) {
150 random = JCAUtil.getSecureRandom();
151 }
152 random.nextBytes(seed);
153
154 try {
155
156 Object[] keyBytes = generateECKeyPair(keySize, encodedParams, seed);
157
158 // The 'params' object supplied above is equivalent to the native
159 // one so there is no need to fetch it.
160 // keyBytes[0] is the encoding of the native private key
161 BigInteger s = new BigInteger(1, (byte[])keyBytes[0]);
162
163 PrivateKey privateKey =
164 new ECPrivateKeyImpl(s, (ECParameterSpec)params);
165
166 // keyBytes[1] is the encoding of the native public key
167 ECPoint w = ECUtil.decodePoint((byte[])keyBytes[1],
168 ((ECParameterSpec)params).getCurve());
169 PublicKey publicKey =
170 new ECPublicKeyImpl(w, (ECParameterSpec)params);
171
172 return new KeyPair(publicKey, privateKey);
173
174 } catch (Exception e) {
175 throw new ProviderException(e);
176 }
177 }
178
179 private void checkKeySize(int keySize) throws InvalidParameterException {
180 if (keySize < KEY_SIZE_MIN) {
181 throw new InvalidParameterException
182 ("Key size must be at least " + KEY_SIZE_MIN + " bits");
183 }
184 if (keySize > KEY_SIZE_MAX) {
185 throw new InvalidParameterException
186 ("Key size must be at most " + KEY_SIZE_MAX + " bits");
187 }
188 this.keySize = keySize;
189 }
190
191 /**
192 * Checks whether the curve in the encoded parameters is supported by the
193 * native implementation.
194 *
195 * @param encodedParams encoded parameters in the same form accepted
196 * by generateECKeyPair
197 * @return true if and only if generateECKeyPair will succeed for
198 * the supplied parameters
199 */
200 private static native boolean isCurveSupported(byte[] encodedParams);
201
202 /*
203 * Generates the keypair and returns a 2-element array of encoding bytes.
204 * The first one is for the private key, the second for the public key.
205 */
206 private static native Object[] generateECKeyPair(int keySize,
207 byte[] encodedParams, byte[] seed) throws GeneralSecurityException;
208 }
|
1 /*
2 * Copyright (c) 2009, 2018, 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.io.IOException;
29 import java.math.BigInteger;
30 import java.security.*;
31 import java.security.spec.AlgorithmParameterSpec;
32 import java.security.spec.ECGenParameterSpec;
33 import java.security.spec.ECParameterSpec;
34 import java.security.spec.ECPoint;
35 import java.security.spec.InvalidParameterSpecException;
36 import java.security.spec.*;
37 import java.util.Optional;
38
39 import sun.security.jca.JCAUtil;
40 import sun.security.util.ECUtil;
41 import sun.security.util.math.*;
42 import sun.security.ec.point.*;
43 import static sun.security.util.SecurityProviderConstants.DEF_EC_KEY_SIZE;
44 import static sun.security.ec.ECOperations.IntermediateValueException;
45
46 /**
47 * EC keypair generator.
48 * Standard algorithm, minimum key length is 112 bits, maximum is 571 bits.
49 *
50 * @since 1.7
51 */
52 public final class ECKeyPairGenerator extends KeyPairGeneratorSpi {
53
54 private static final int KEY_SIZE_MIN = 112; // min bits (see ecc_impl.h)
55 private static final int KEY_SIZE_MAX = 571; // max bits (see ecc_impl.h)
56
57 // used to seed the keypair generator
58 private SecureRandom random;
59
60 // size of the key to generate, KEY_SIZE_MIN <= keySize <= KEY_SIZE_MAX
61 private int keySize;
62
63 // parameters specified via init, if any
64 private AlgorithmParameterSpec params = null;
75 @Override
76 public void initialize(int keySize, SecureRandom random) {
77
78 checkKeySize(keySize);
79 this.params = ECUtil.getECParameterSpec(null, keySize);
80 if (params == null) {
81 throw new InvalidParameterException(
82 "No EC parameters available for key size " + keySize + " bits");
83 }
84 this.random = random;
85 }
86
87 // second initialize method. See JCA doc
88 @Override
89 public void initialize(AlgorithmParameterSpec params, SecureRandom random)
90 throws InvalidAlgorithmParameterException {
91
92 ECParameterSpec ecSpec = null;
93
94 if (params instanceof ECParameterSpec) {
95 ECParameterSpec ecParams = (ECParameterSpec) params;
96 ecSpec = ECUtil.getECParameterSpec(null, ecParams);
97 if (ecSpec == null) {
98 throw new InvalidAlgorithmParameterException(
99 "Unsupported curve: " + params);
100 }
101 } else if (params instanceof ECGenParameterSpec) {
102 String name = ((ECGenParameterSpec) params).getName();
103 ecSpec = ECUtil.getECParameterSpec(null, name);
104 if (ecSpec == null) {
105 throw new InvalidAlgorithmParameterException(
106 "Unknown curve name: " + name);
107 }
108 } else {
109 throw new InvalidAlgorithmParameterException(
110 "ECParameterSpec or ECGenParameterSpec required for EC");
111 }
112
113 // Not all known curves are supported by the native implementation
114 ensureCurveIsSupported(ecSpec);
115 this.params = ecSpec;
116
117 this.keySize = ecSpec.getCurve().getField().getFieldSize();
118 this.random = random;
119 }
120
121 private static void ensureCurveIsSupported(ECParameterSpec ecSpec)
122 throws InvalidAlgorithmParameterException {
123
124 AlgorithmParameters ecParams = ECUtil.getECParameters(null);
125 byte[] encodedParams;
126 try {
127 ecParams.init(ecSpec);
128 encodedParams = ecParams.getEncoded();
129 } catch (InvalidParameterSpecException ex) {
130 throw new InvalidAlgorithmParameterException(
131 "Unsupported curve: " + ecSpec.toString());
132 } catch (IOException ex) {
133 throw new RuntimeException(ex);
134 }
135 if (!isCurveSupported(encodedParams)) {
136 throw new InvalidAlgorithmParameterException(
137 "Unsupported curve: " + ecParams.toString());
138 }
139 }
140
141 // generate the keypair. See JCA doc
142 @Override
143 public KeyPair generateKeyPair() {
144
145 if (random == null) {
146 random = JCAUtil.getSecureRandom();
147 }
148
149 try {
150 Optional<KeyPair> kp = generateKeyPairImpl(random);
151 if (kp.isPresent()) {
152 return kp.get();
153 }
154 return generateKeyPairNative(random);
155 } catch (Exception ex) {
156 throw new ProviderException(ex);
157 }
158 }
159
160 private byte[] generatePrivateScalar(SecureRandom random,
161 ECOperations ecOps, int seedSize) {
162 // Attempt to create the private scalar in a loop that uses new random
163 // input each time. The chance of failure is very small assuming the
164 // implementation derives the nonce using extra bits
165 int numAttempts = 128;
166 byte[] seedArr = new byte[seedSize];
167 for (int i = 0; i < numAttempts; i++) {
168 random.nextBytes(seedArr);
169 try {
170 return ecOps.seedToScalar(seedArr);
171 } catch (IntermediateValueException ex) {
172 // try again in the next iteration
173 }
174 }
175
176 throw new ProviderException("Unable to produce private key after "
177 + numAttempts + " attempts");
178 }
179
180 private Optional<KeyPair> generateKeyPairImpl(SecureRandom random)
181 throws InvalidKeyException {
182
183 ECParameterSpec ecParams = (ECParameterSpec) params;
184
185 Optional<ECOperations> opsOpt = ECOperations.forParameters(ecParams);
186 if (opsOpt.isEmpty()) {
187 return Optional.empty();
188 }
189 ECOperations ops = opsOpt.get();
190 IntegerFieldModuloP field = ops.getField();
191 int numBits = ecParams.getOrder().bitLength();
192 int seedBits = numBits + 64;
193 int seedSize = (seedBits + 7) / 8;
194 byte[] privArr = generatePrivateScalar(random, ops, seedSize);
195
196 ECPoint genPoint = ecParams.getGenerator();
197 ImmutableIntegerModuloP x = field.getElement(genPoint.getAffineX());
198 ImmutableIntegerModuloP y = field.getElement(genPoint.getAffineY());
199 AffinePoint affGen = new AffinePoint(x, y);
200 Point pub = ops.multiply(affGen, privArr);
201 AffinePoint affPub = pub.asAffine();
202
203 PrivateKey privateKey = new ECPrivateKeyImpl(privArr, ecParams);
204
205 ECPoint w = new ECPoint(affPub.getX().asBigInteger(),
206 affPub.getY().asBigInteger());
207 PublicKey publicKey = new ECPublicKeyImpl(w, ecParams);
208
209 return Optional.of(new KeyPair(publicKey, privateKey));
210 }
211
212 private KeyPair generateKeyPairNative(SecureRandom random)
213 throws Exception {
214
215 ECParameterSpec ecParams = (ECParameterSpec) params;
216 byte[] encodedParams = ECUtil.encodeECParameterSpec(null, ecParams);
217
218 // seed is twice the key size (in bytes) plus 1
219 byte[] seed = new byte[(((keySize + 7) >> 3) + 1) * 2];
220 random.nextBytes(seed);
221 Object[] keyBytes = generateECKeyPair(keySize, encodedParams, seed);
222
223 // The 'params' object supplied above is equivalent to the native
224 // one so there is no need to fetch it.
225 // keyBytes[0] is the encoding of the native private key
226 BigInteger s = new BigInteger(1, (byte[]) keyBytes[0]);
227
228 PrivateKey privateKey = new ECPrivateKeyImpl(s, ecParams);
229
230 // keyBytes[1] is the encoding of the native public key
231 byte[] pubKey = (byte[]) keyBytes[1];
232 ECPoint w = ECUtil.decodePoint(pubKey, ecParams.getCurve());
233 PublicKey publicKey = new ECPublicKeyImpl(w, ecParams);
234
235 return new KeyPair(publicKey, privateKey);
236 }
237
238 private void checkKeySize(int keySize) throws InvalidParameterException {
239 if (keySize < KEY_SIZE_MIN) {
240 throw new InvalidParameterException
241 ("Key size must be at least " + KEY_SIZE_MIN + " bits");
242 }
243 if (keySize > KEY_SIZE_MAX) {
244 throw new InvalidParameterException
245 ("Key size must be at most " + KEY_SIZE_MAX + " bits");
246 }
247 this.keySize = keySize;
248 }
249
250 /**
251 * Checks whether the curve in the encoded parameters is supported by the
252 * native implementation. Some curve operations will be performed by the
253 * Java implementation, but not all of them. So native support is still
254 * required for all curves.
255 *
256 * @param encodedParams encoded parameters in the same form accepted
257 * by generateECKeyPair
258 * @return true if and only if generateECKeyPair will succeed for
259 * the supplied parameters
260 */
261 private static native boolean isCurveSupported(byte[] encodedParams);
262
263 /*
264 * Generates the keypair and returns a 2-element array of encoding bytes.
265 * The first one is for the private key, the second for the public key.
266 */
267 private static native Object[] generateECKeyPair(int keySize,
268 byte[] encodedParams, byte[] seed) throws GeneralSecurityException;
269 }
|