|
39 | 39 | import java.security.interfaces.DSAPrivateKey;
|
40 | 40 | import java.security.interfaces.DSAPublicKey;
|
41 | 41 | import java.security.interfaces.ECPrivateKey;
|
42 |
| -import java.security.interfaces.ECPublicKey; |
43 | 42 | import java.security.interfaces.RSAPrivateCrtKey;
|
44 | 43 | import java.security.interfaces.RSAPublicKey;
|
45 | 44 | import java.security.spec.DSAPrivateKeySpec;
|
46 | 45 | import java.security.spec.DSAPublicKeySpec;
|
47 |
| -import java.security.spec.ECParameterSpec; |
48 |
| -import java.security.spec.ECPrivateKeySpec; |
49 | 46 | import java.security.spec.InvalidKeySpecException;
|
50 | 47 | import java.security.spec.KeySpec;
|
51 | 48 | import java.security.spec.PKCS8EncodedKeySpec;
|
|
67 | 64 | import org.bouncycastle.asn1.DLSequence;
|
68 | 65 | import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
|
69 | 66 | import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
|
70 |
| -import org.bouncycastle.asn1.sec.ECPrivateKeyStructure; |
71 | 67 | import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
72 | 68 | import org.bouncycastle.asn1.x509.DSAParameter;
|
73 | 69 | import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
|
74 | 70 | import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
|
75 |
| -import org.bouncycastle.jce.ECNamedCurveTable; |
76 |
| -import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; |
77 |
| -import org.bouncycastle.jce.spec.ECPublicKeySpec; |
78 | 71 | import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
|
79 | 72 |
|
80 | 73 | import org.jruby.ext.openssl.SecurityHelper;
|
|
87 | 80 | */
|
88 | 81 | public class PKey {
|
89 | 82 |
|
90 |
| - public static KeyPair readPrivateKey(final byte[] input, final String type) |
| 83 | + public enum Type { RSA, DSA, EC; } |
| 84 | + |
| 85 | + public static KeyPair readPrivateKey(final Type type, final byte[] input) |
91 | 86 | throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
|
92 |
| - return readPrivateKey((ASN1Sequence) new ASN1InputStream(input).readObject(), type); |
| 87 | + return readPrivateKey(type, mockPrivateKeyInfo(type, input)); |
| 88 | + } |
| 89 | + |
| 90 | + private static PrivateKeyInfo mockPrivateKeyInfo(final Type type, final byte[] input) throws IOException { |
| 91 | + return new PrivateKeyInfo(null, new ASN1InputStream(input).readObject()); |
93 | 92 | }
|
94 | 93 |
|
95 |
| - public static KeyPair readPrivateKey(final ASN1Sequence seq, final String type) |
| 94 | + public static KeyPair readPrivateKey(final Type type, final PrivateKeyInfo keyInfo) |
96 | 95 | throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
|
97 |
| - KeySpec pubSpec; KeySpec privSpec; |
98 |
| - if ( type.equals("RSA") ) { |
99 |
| - ASN1Integer mod = (ASN1Integer) seq.getObjectAt(1); |
100 |
| - ASN1Integer pubExp = (ASN1Integer) seq.getObjectAt(2); |
101 |
| - ASN1Integer privExp = (ASN1Integer) seq.getObjectAt(3); |
102 |
| - ASN1Integer p1 = (ASN1Integer) seq.getObjectAt(4); |
103 |
| - ASN1Integer p2 = (ASN1Integer) seq.getObjectAt(5); |
104 |
| - ASN1Integer exp1 = (ASN1Integer) seq.getObjectAt(6); |
105 |
| - ASN1Integer exp2 = (ASN1Integer) seq.getObjectAt(7); |
106 |
| - ASN1Integer crtCoef = (ASN1Integer) seq.getObjectAt(8); |
107 |
| - pubSpec = new RSAPublicKeySpec(mod.getValue(), pubExp.getValue()); |
108 |
| - privSpec = new RSAPrivateCrtKeySpec(mod.getValue(), pubExp.getValue(), privExp.getValue(), p1.getValue(), p2.getValue(), exp1.getValue(), |
109 |
| - exp2.getValue(), crtCoef.getValue()); |
110 |
| - } |
111 |
| - else if ( type.equals("DSA") ) { |
112 |
| - ASN1Integer p = (ASN1Integer) seq.getObjectAt(1); |
113 |
| - ASN1Integer q = (ASN1Integer) seq.getObjectAt(2); |
114 |
| - ASN1Integer g = (ASN1Integer) seq.getObjectAt(3); |
115 |
| - ASN1Integer y = (ASN1Integer) seq.getObjectAt(4); |
116 |
| - ASN1Integer x = (ASN1Integer) seq.getObjectAt(5); |
117 |
| - privSpec = new DSAPrivateKeySpec(x.getValue(), p.getValue(), q.getValue(), g.getValue()); |
118 |
| - pubSpec = new DSAPublicKeySpec(y.getValue(), p.getValue(), q.getValue(), g.getValue()); |
| 96 | + KeySpec pubSpec; KeySpec privSpec; ASN1Sequence seq; |
| 97 | + switch (type) { |
| 98 | + case RSA: |
| 99 | + seq = (ASN1Sequence) keyInfo.parsePrivateKey(); |
| 100 | + ASN1Integer mod = (ASN1Integer) seq.getObjectAt(1); |
| 101 | + ASN1Integer pubExp = (ASN1Integer) seq.getObjectAt(2); |
| 102 | + ASN1Integer privExp = (ASN1Integer) seq.getObjectAt(3); |
| 103 | + ASN1Integer p1 = (ASN1Integer) seq.getObjectAt(4); |
| 104 | + ASN1Integer p2 = (ASN1Integer) seq.getObjectAt(5); |
| 105 | + ASN1Integer exp1 = (ASN1Integer) seq.getObjectAt(6); |
| 106 | + ASN1Integer exp2 = (ASN1Integer) seq.getObjectAt(7); |
| 107 | + ASN1Integer crtCoef = (ASN1Integer) seq.getObjectAt(8); |
| 108 | + pubSpec = new RSAPublicKeySpec(mod.getValue(), pubExp.getValue()); |
| 109 | + privSpec = new RSAPrivateCrtKeySpec( |
| 110 | + mod.getValue(), pubExp.getValue(), privExp.getValue(), |
| 111 | + p1.getValue(), p2.getValue(), |
| 112 | + exp1.getValue(), exp2.getValue(), crtCoef.getValue()); |
| 113 | + break; |
| 114 | + case DSA: |
| 115 | + seq = (ASN1Sequence) keyInfo.parsePrivateKey(); |
| 116 | + ASN1Integer p = (ASN1Integer) seq.getObjectAt(1); |
| 117 | + ASN1Integer q = (ASN1Integer) seq.getObjectAt(2); |
| 118 | + ASN1Integer g = (ASN1Integer) seq.getObjectAt(3); |
| 119 | + ASN1Integer y = (ASN1Integer) seq.getObjectAt(4); |
| 120 | + ASN1Integer x = (ASN1Integer) seq.getObjectAt(5); |
| 121 | + privSpec = new DSAPrivateKeySpec(x.getValue(), p.getValue(), q.getValue(), g.getValue()); |
| 122 | + pubSpec = new DSAPublicKeySpec(y.getValue(), p.getValue(), q.getValue(), g.getValue()); |
| 123 | + break; |
| 124 | + case EC: |
| 125 | + return readECPrivateKey(SecurityHelper.getKeyFactory("EC"), keyInfo); |
| 126 | + default: |
| 127 | + throw new AssertionError("unexpected key type: " + type); |
119 | 128 | }
|
120 |
| - else if ( type.equals("EC") ) { |
121 |
| - return readECPrivateKey(SecurityHelper.getKeyFactory("EC"), seq); |
122 |
| - } |
123 |
| - else { |
124 |
| - throw new IllegalStateException("unsupported type: " + type); |
125 |
| - } |
126 |
| - KeyFactory fact = SecurityHelper.getKeyFactory(type); |
127 |
| - return new KeyPair(fact.generatePublic(pubSpec), fact.generatePrivate(privSpec)); |
| 129 | + final KeyFactory keyFactory = SecurityHelper.getKeyFactory(type.name()); |
| 130 | + return new KeyPair(keyFactory.generatePublic(pubSpec), keyFactory.generatePrivate(privSpec)); |
128 | 131 | }
|
129 | 132 |
|
130 | 133 | // d2i_PUBKEY_bio
|
@@ -264,21 +267,23 @@ public static KeyPair readECPrivateKey(final byte[] input)
|
264 | 267 |
|
265 | 268 | public static KeyPair readECPrivateKey(final KeyFactory keyFactory, final byte[] input)
|
266 | 269 | throws IOException, InvalidKeySpecException {
|
267 |
| - return readECPrivateKey(keyFactory, (ASN1Sequence) ASN1Primitive.fromByteArray(input)); |
| 270 | + return readECPrivateKey(keyFactory, mockPrivateKeyInfo(Type.EC, input)); |
268 | 271 | }
|
269 | 272 |
|
270 |
| - public static KeyPair readECPrivateKey(final KeyFactory keyFactory, final ASN1Sequence input) |
| 273 | + public static KeyPair readECPrivateKey(final KeyFactory keyFactory, final PrivateKeyInfo keyInfo) |
271 | 274 | throws IOException, InvalidKeySpecException {
|
272 | 275 | try {
|
273 |
| - org.bouncycastle.asn1.sec.ECPrivateKey pKey = org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(input); |
274 |
| - AlgorithmIdentifier algId = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, pKey.getParametersObject().toASN1Primitive()); |
275 |
| - PrivateKeyInfo privInfo = new PrivateKeyInfo(algId, pKey.toASN1Primitive()); |
276 |
| - SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(algId, pKey.getPublicKey().getBytes()); |
277 |
| - PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(privInfo.getEncoded()); |
278 |
| - X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubInfo.getEncoded()); |
| 276 | + org.bouncycastle.asn1.sec.ECPrivateKey key = org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(keyInfo.parsePrivateKey()); |
| 277 | + AlgorithmIdentifier algId = keyInfo.getPrivateKeyAlgorithm(); |
| 278 | + // NOTE: should only happen when using mockPrivateKeyInfo(Type, byte[]) |
| 279 | + if (algId == null) algId = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey); |
| 280 | + |
| 281 | + SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(algId, key.getPublicKey().getBytes()); |
| 282 | + PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(keyInfo.getEncoded()); |
| 283 | + X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubInfo.getEncoded()); |
279 | 284 |
|
280 | 285 | ECPrivateKey privateKey = (ECPrivateKey) keyFactory.generatePrivate(privSpec);
|
281 |
| - if ( algId.getParameters() instanceof ASN1ObjectIdentifier ) { |
| 286 | + if (algId.getParameters() instanceof ASN1ObjectIdentifier) { |
282 | 287 | privateKey = ECPrivateKeyWithName.wrap(privateKey, (ASN1ObjectIdentifier) algId.getParameters());
|
283 | 288 | }
|
284 | 289 | return new KeyPair(keyFactory.generatePublic(pubSpec), privateKey);
|
@@ -311,10 +316,11 @@ public static byte[] toDerRSAKey(RSAPublicKey pubKey, RSAPrivateCrtKey privKey)
|
311 | 316 | return new DERSequence(vec).toASN1Primitive().getEncoded(ASN1Encoding.DER);
|
312 | 317 | }
|
313 | 318 |
|
314 |
| - public static ASN1Sequence toASN1Primitive(RSAPublicKey pubKey) { |
| 319 | + public static ASN1Sequence toASN1Primitive(final RSAPublicKey publicKey) { |
| 320 | + assert publicKey != null : "null public key"; |
315 | 321 | ASN1EncodableVector vec = new ASN1EncodableVector();
|
316 |
| - vec.add(new ASN1Integer(pubKey.getModulus())); |
317 |
| - vec.add(new ASN1Integer(pubKey.getPublicExponent())); |
| 322 | + vec.add(new ASN1Integer(publicKey.getModulus())); |
| 323 | + vec.add(new ASN1Integer(publicKey.getPublicExponent())); |
318 | 324 | return new DERSequence(vec);
|
319 | 325 | }
|
320 | 326 |
|
|
0 commit comments