1 /*
2 * Copyright (c) 2006, 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.io.IOException;
29 import java.math.BigInteger;
30
31 import java.security.*;
32 import java.security.interfaces.*;
33 import java.security.spec.*;
34
35 import sun.security.util.DerInputStream;
36 import sun.security.util.DerOutputStream;
37 import sun.security.util.DerValue;
38 import sun.security.util.ECParameters;
39 import sun.security.util.ECUtil;
40 import sun.security.x509.AlgorithmId;
41 import sun.security.pkcs.PKCS8Key;
42
43 /**
44 * Key implementation for EC private keys.
45 *
46 * ASN.1 syntax for EC private keys from SEC 1 v1.5 (draft):
47 *
48 * <pre>
49 * EXPLICIT TAGS
50 *
51 * ECPrivateKey ::= SEQUENCE {
52 * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
53 * privateKey OCTET STRING,
54 * parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
55 * publicKey [1] BIT STRING OPTIONAL
56 * }
57 * </pre>
58 *
59 * We currently ignore the optional parameters and publicKey fields. We
60 * require that the parameters are encoded as part of the AlgorithmIdentifier,
61 * not in the private key structure.
62 *
63 * @since 1.6
64 * @author Andreas Sterbenz
65 */
66 public final class ECPrivateKeyImpl extends PKCS8Key implements ECPrivateKey {
67
68 private static final long serialVersionUID = 88695385615075129L;
69
70 private BigInteger s; // private value
71 private ECParameterSpec params;
72
73 /**
74 * Construct a key from its encoding. Called by the ECKeyFactory.
75 */
76 ECPrivateKeyImpl(byte[] encoded) throws InvalidKeyException {
77 decode(encoded);
78 }
79
80 /**
81 * Construct a key from its components. Used by the
82 * KeyFactory.
83 */
84 ECPrivateKeyImpl(BigInteger s, ECParameterSpec params)
85 throws InvalidKeyException {
86 this.s = s;
87 this.params = params;
88 // generate the encoding
89 algid = new AlgorithmId
90 (AlgorithmId.EC_oid, ECParameters.getAlgorithmParameters(params));
91 try {
92 DerOutputStream out = new DerOutputStream();
93 out.putInteger(1); // version 1
94 byte[] privBytes = ECUtil.trimZeroes(s.toByteArray());
95 out.putOctetString(privBytes);
96 DerValue val =
97 new DerValue(DerValue.tag_Sequence, out.toByteArray());
98 key = val.toByteArray();
99 } catch (IOException exc) {
100 // should never occur
101 throw new InvalidKeyException(exc);
102 }
103 }
104
105 // see JCA doc
106 public String getAlgorithm() {
107 return "EC";
108 }
109
110 // see JCA doc
111 public BigInteger getS() {
112 return s;
113 }
114
115 // see JCA doc
116 public ECParameterSpec getParams() {
117 return params;
118 }
119
120 /**
121 * Parse the key. Called by PKCS8Key.
122 */
123 protected void parseKeyBits() throws InvalidKeyException {
124 try {
125 DerInputStream in = new DerInputStream(key);
126 DerValue derValue = in.getDerValue();
127 if (derValue.tag != DerValue.tag_Sequence) {
128 throw new IOException("Not a SEQUENCE");
129 }
130 DerInputStream data = derValue.data;
131 int version = data.getInteger();
132 if (version != 1) {
133 throw new IOException("Version must be 1");
134 }
135 byte[] privData = data.getOctetString();
136 s = new BigInteger(1, privData);
137 while (data.available() != 0) {
138 DerValue value = data.getDerValue();
139 if (value.isContextSpecific((byte)0)) {
140 // ignore for now
141 } else if (value.isContextSpecific((byte)1)) {
142 // ignore for now
143 } else {
144 throw new InvalidKeyException("Unexpected value: " + value);
145 }
146 }
147 AlgorithmParameters algParams = this.algid.getParameters();
148 if (algParams == null) {
149 throw new InvalidKeyException("EC domain parameters must be "
150 + "encoded in the algorithm identifier");
151 }
152 params = algParams.getParameterSpec(ECParameterSpec.class);
153 } catch (IOException e) {
154 throw new InvalidKeyException("Invalid EC private key", e);
155 } catch (InvalidParameterSpecException e) {
156 throw new InvalidKeyException("Invalid EC private key", e);
157 }
158 }
159 }
|
1 /*
2 * Copyright (c) 2006, 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
31 import java.security.*;
32 import java.security.interfaces.*;
33 import java.security.spec.*;
34
35 import sun.security.util.*;
36 import sun.security.x509.AlgorithmId;
37 import sun.security.pkcs.PKCS8Key;
38
39 /**
40 * Key implementation for EC private keys.
41 *
42 * ASN.1 syntax for EC private keys from SEC 1 v1.5 (draft):
43 *
44 * <pre>
45 * EXPLICIT TAGS
46 *
47 * ECPrivateKey ::= SEQUENCE {
48 * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
49 * privateKey OCTET STRING,
50 * parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
51 * publicKey [1] BIT STRING OPTIONAL
52 * }
53 * </pre>
54 *
55 * We currently ignore the optional parameters and publicKey fields. We
56 * require that the parameters are encoded as part of the AlgorithmIdentifier,
57 * not in the private key structure.
58 *
59 * @since 1.6
60 * @author Andreas Sterbenz
61 */
62 public final class ECPrivateKeyImpl extends PKCS8Key implements ECPrivateKey {
63
64 private static final long serialVersionUID = 88695385615075129L;
65
66 private BigInteger s; // private value
67 private byte[] arrayS; // private value as a little-endian array
68 private ECParameterSpec params;
69
70 /**
71 * Construct a key from its encoding. Called by the ECKeyFactory.
72 */
73 ECPrivateKeyImpl(byte[] encoded) throws InvalidKeyException {
74 decode(encoded);
75 }
76
77 /**
78 * Construct a key from its components. Used by the
79 * KeyFactory.
80 */
81 ECPrivateKeyImpl(BigInteger s, ECParameterSpec params)
82 throws InvalidKeyException {
83 this.s = s;
84 this.params = params;
85 makeEncoding(s);
86
87 }
88
89 ECPrivateKeyImpl(byte[] s, ECParameterSpec params)
90 throws InvalidKeyException {
91 this.arrayS = s.clone();
92 this.params = params;
93 makeEncoding(s);
94 }
95
96 private void makeEncoding(byte[] s) throws InvalidKeyException {
97 algid = new AlgorithmId
98 (AlgorithmId.EC_oid, ECParameters.getAlgorithmParameters(params));
99 try {
100 DerOutputStream out = new DerOutputStream();
101 out.putInteger(1); // version 1
102 byte[] privBytes = s.clone();
103 ArrayUtil.reverse(privBytes);
104 out.putOctetString(privBytes);
105 DerValue val =
106 new DerValue(DerValue.tag_Sequence, out.toByteArray());
107 key = val.toByteArray();
108 } catch (IOException exc) {
109 // should never occur
110 throw new InvalidKeyException(exc);
111 }
112 }
113
114 private void makeEncoding(BigInteger s) throws InvalidKeyException {
115 algid = new AlgorithmId
116 (AlgorithmId.EC_oid, ECParameters.getAlgorithmParameters(params));
117 try {
118 byte[] sArr = s.toByteArray();
119 // convert to fixed-length array
120 int numOctets = (params.getOrder().bitLength() + 7) / 8;
121 byte[] sOctets = new byte[numOctets];
122 int inPos = Math.max(sArr.length - sOctets.length, 0);
123 int outPos = Math.max(sOctets.length - sArr.length, 0);
124 int length = Math.min(sArr.length, sOctets.length);
125 System.arraycopy(sArr, inPos, sOctets, outPos, length);
126
127 DerOutputStream out = new DerOutputStream();
128 out.putInteger(1); // version 1
129 out.putOctetString(sOctets);
130 DerValue val =
131 new DerValue(DerValue.tag_Sequence, out.toByteArray());
132 key = val.toByteArray();
133 } catch (IOException exc) {
134 // should never occur
135 throw new InvalidKeyException(exc);
136 }
137 }
138
139 // see JCA doc
140 public String getAlgorithm() {
141 return "EC";
142 }
143
144 // see JCA doc
145 public BigInteger getS() {
146 if (s == null) {
147 byte[] arrCopy = arrayS.clone();
148 ArrayUtil.reverse(arrCopy);
149 s = new BigInteger(1, arrCopy);
150 }
151 return s;
152 }
153
154 public byte[] getArrayS() {
155 if (arrayS == null) {
156 byte[] arr = getS().toByteArray();
157 ArrayUtil.reverse(arr);
158 int byteLength = (params.getOrder().bitLength() + 7) / 8;
159 arrayS = new byte[byteLength];
160 int length = Math.min(byteLength, arr.length);
161 System.arraycopy(arr, 0, arrayS, 0, length);
162 }
163 return arrayS.clone();
164 }
165
166 // see JCA doc
167 public ECParameterSpec getParams() {
168 return params;
169 }
170
171 /**
172 * Parse the key. Called by PKCS8Key.
173 */
174 protected void parseKeyBits() throws InvalidKeyException {
175 try {
176 DerInputStream in = new DerInputStream(key);
177 DerValue derValue = in.getDerValue();
178 if (derValue.tag != DerValue.tag_Sequence) {
179 throw new IOException("Not a SEQUENCE");
180 }
181 DerInputStream data = derValue.data;
182 int version = data.getInteger();
183 if (version != 1) {
184 throw new IOException("Version must be 1");
185 }
186 byte[] privData = data.getOctetString();
187 ArrayUtil.reverse(privData);
188 arrayS = privData;
189 while (data.available() != 0) {
190 DerValue value = data.getDerValue();
191 if (value.isContextSpecific((byte) 0)) {
192 // ignore for now
193 } else if (value.isContextSpecific((byte) 1)) {
194 // ignore for now
195 } else {
196 throw new InvalidKeyException("Unexpected value: " + value);
197 }
198 }
199 AlgorithmParameters algParams = this.algid.getParameters();
200 if (algParams == null) {
201 throw new InvalidKeyException("EC domain parameters must be "
202 + "encoded in the algorithm identifier");
203 }
204 params = algParams.getParameterSpec(ECParameterSpec.class);
205 } catch (IOException e) {
206 throw new InvalidKeyException("Invalid EC private key", e);
207 } catch (InvalidParameterSpecException e) {
208 throw new InvalidKeyException("Invalid EC private key", e);
209 }
210 }
211 }
|