30
30
import java .io .IOException ;
31
31
import java .math .BigInteger ;
32
32
33
- import java .security .GeneralSecurityException ;
34
33
import java .security .KeyFactory ;
35
34
import java .security .KeyPair ;
36
35
import java .security .NoSuchAlgorithmException ;
39
38
import java .security .interfaces .DSAParams ;
40
39
import java .security .interfaces .DSAPrivateKey ;
41
40
import java .security .interfaces .DSAPublicKey ;
41
+ import java .security .interfaces .ECPrivateKey ;
42
+ import java .security .interfaces .ECPublicKey ;
42
43
import java .security .interfaces .RSAPrivateCrtKey ;
43
44
import java .security .interfaces .RSAPublicKey ;
44
45
import java .security .spec .DSAPrivateKeySpec ;
45
46
import java .security .spec .DSAPublicKeySpec ;
47
+ import java .security .spec .ECParameterSpec ;
48
+ import java .security .spec .ECPrivateKeySpec ;
46
49
import java .security .spec .InvalidKeySpecException ;
47
50
import java .security .spec .KeySpec ;
51
+ import java .security .spec .PKCS8EncodedKeySpec ;
48
52
import java .security .spec .RSAPrivateCrtKeySpec ;
49
53
import java .security .spec .RSAPublicKeySpec ;
54
+ import java .security .spec .X509EncodedKeySpec ;
50
55
import javax .crypto .spec .DHParameterSpec ;
51
56
52
57
import org .bouncycastle .asn1 .ASN1EncodableVector ;
53
58
import org .bouncycastle .asn1 .ASN1InputStream ;
54
59
import org .bouncycastle .asn1 .ASN1Integer ;
60
+ import org .bouncycastle .asn1 .ASN1ObjectIdentifier ;
61
+ import org .bouncycastle .asn1 .ASN1Primitive ;
55
62
import org .bouncycastle .asn1 .ASN1Sequence ;
56
63
import org .bouncycastle .asn1 .DLSequence ;
64
+ import org .bouncycastle .asn1 .pkcs .PrivateKeyInfo ;
65
+ import org .bouncycastle .asn1 .sec .ECPrivateKeyStructure ;
66
+ import org .bouncycastle .asn1 .x509 .AlgorithmIdentifier ;
67
+ import org .bouncycastle .asn1 .x509 .SubjectPublicKeyInfo ;
68
+ import org .bouncycastle .asn1 .x9 .X9ObjectIdentifiers ;
69
+ import org .bouncycastle .jce .ECNamedCurveTable ;
70
+ import org .bouncycastle .jce .spec .ECNamedCurveParameterSpec ;
71
+ import org .bouncycastle .jce .spec .ECPublicKeySpec ;
57
72
58
73
import org .jruby .ext .openssl .SecurityHelper ;
59
74
65
80
*/
66
81
public class PKey {
67
82
68
- public static KeyPair readPrivateKey (byte [] input , String type ) throws IOException , GeneralSecurityException {
83
+ public static KeyPair readPrivateKey (final byte [] input , final String type )
84
+ throws IOException , NoSuchAlgorithmException , InvalidKeySpecException {
69
85
KeySpec pubSpec ; KeySpec privSpec ;
70
86
ASN1Sequence seq = (ASN1Sequence ) new ASN1InputStream (input ).readObject ();
71
87
if ( type .equals ("RSA" ) ) {
@@ -80,7 +96,8 @@ public static KeyPair readPrivateKey(byte[] input, String type) throws IOExcepti
80
96
pubSpec = new RSAPublicKeySpec (mod .getValue (), pubExp .getValue ());
81
97
privSpec = new RSAPrivateCrtKeySpec (mod .getValue (), pubExp .getValue (), privExp .getValue (), p1 .getValue (), p2 .getValue (), exp1 .getValue (),
82
98
exp2 .getValue (), crtCoef .getValue ());
83
- } else { // assume "DSA" for now.
99
+ }
100
+ else if ( type .equals ("DSA" ) ) {
84
101
ASN1Integer p = (ASN1Integer ) seq .getObjectAt (1 );
85
102
ASN1Integer q = (ASN1Integer ) seq .getObjectAt (2 );
86
103
ASN1Integer g = (ASN1Integer ) seq .getObjectAt (3 );
@@ -89,6 +106,12 @@ public static KeyPair readPrivateKey(byte[] input, String type) throws IOExcepti
89
106
privSpec = new DSAPrivateKeySpec (x .getValue (), p .getValue (), q .getValue (), g .getValue ());
90
107
pubSpec = new DSAPublicKeySpec (y .getValue (), p .getValue (), q .getValue (), g .getValue ());
91
108
}
109
+ else if ( type .equals ("ECDSA" ) ) {
110
+ return readECPrivateKey (input );
111
+ }
112
+ else {
113
+ throw new IllegalStateException ("unsupported type: " + type );
114
+ }
92
115
KeyFactory fact = SecurityHelper .getKeyFactory (type );
93
116
return new KeyPair (fact .generatePublic (pubSpec ), fact .generatePrivate (privSpec ));
94
117
}
@@ -147,7 +170,6 @@ public static KeyPair readRSAPrivateKey(final byte[] input)
147
170
148
171
public static KeyPair readRSAPrivateKey (final KeyFactory rsaFactory , final byte [] input )
149
172
throws IOException , InvalidKeySpecException {
150
- // KeyFactory fact = SecurityHelper.getKeyFactory("RSA");
151
173
ASN1Sequence seq = (ASN1Sequence ) new ASN1InputStream (input ).readObject ();
152
174
if ( seq .size () == 9 ) {
153
175
BigInteger mod = ((ASN1Integer ) seq .getObjectAt (1 )).getValue ();
@@ -232,6 +254,36 @@ public static DHParameterSpec readDHParameter(final byte[] input) throws IOExcep
232
254
return new DHParameterSpec (p , g );
233
255
}
234
256
257
+ public static KeyPair readECPrivateKey (final byte [] input )
258
+ throws IOException , NoSuchAlgorithmException , InvalidKeySpecException {
259
+ return readECPrivateKey (SecurityHelper .getKeyFactory ("ECDSA" ), input );
260
+ }
261
+
262
+ public static KeyPair readECPrivateKey (final KeyFactory ecFactory , final byte [] input )
263
+ throws IOException , InvalidKeySpecException {
264
+ try {
265
+ ECPrivateKeyStructure pKey = new ECPrivateKeyStructure ((ASN1Sequence ) ASN1Primitive .fromByteArray (input ));
266
+ AlgorithmIdentifier algId = new AlgorithmIdentifier (X9ObjectIdentifiers .id_ecPublicKey , pKey .getParameters ());
267
+ PrivateKeyInfo privInfo = new PrivateKeyInfo (algId , pKey .toASN1Primitive ());
268
+ SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo (algId , pKey .getPublicKey ().getBytes ());
269
+ PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec (privInfo .getEncoded ());
270
+ X509EncodedKeySpec pubSpec = new X509EncodedKeySpec (pubInfo .getEncoded ());
271
+ //KeyFactory fact = KeyFactory.getInstance("ECDSA", provider);
272
+
273
+ ECPrivateKey privateKey = (ECPrivateKey ) ecFactory .generatePrivate (privSpec );
274
+ if ( algId .getParameters () instanceof ASN1ObjectIdentifier ) {
275
+ privateKey = ECPrivateKeyWithName .wrap (privateKey , (ASN1ObjectIdentifier ) algId .getParameters ());
276
+ }
277
+ return new KeyPair (ecFactory .generatePublic (pubSpec ), privateKey );
278
+ }
279
+ catch (ClassCastException ex ) {
280
+ throw new IOException ("wrong ASN.1 object found in stream" , ex );
281
+ }
282
+ //catch (Exception ex) {
283
+ // throw new IOException("problem parsing EC private key: " + ex);
284
+ //}
285
+ }
286
+
235
287
public static byte [] toDerRSAKey (RSAPublicKey pubKey , RSAPrivateCrtKey privKey ) throws IOException {
236
288
ASN1EncodableVector vec = new ASN1EncodableVector ();
237
289
if ( pubKey != null && privKey == null ) {
@@ -268,7 +320,7 @@ public static byte[] toDerDSAKey(DSAPublicKey pubKey, DSAPrivateKey privKey) thr
268
320
return new DLSequence (vec ).getEncoded ();
269
321
}
270
322
if ( privKey == null ) {
271
- throw new IllegalArgumentException ("passed private key as well as public key are null" );
323
+ throw new IllegalArgumentException ("private key as well as public key are null" );
272
324
}
273
325
return privKey .getEncoded ();
274
326
}
0 commit comments