21
21
import net .i2p .crypto .eddsa .spec .EdDSAPrivateKeySpec ;
22
22
import net .schmizz .sshj .common .*;
23
23
import net .schmizz .sshj .common .Buffer .PlainBuffer ;
24
- import net .schmizz .sshj .transport .cipher .BlockCipher ;
25
24
import net .schmizz .sshj .transport .cipher .Cipher ;
26
25
import net .schmizz .sshj .userauth .keyprovider .BaseFileKeyProvider ;
27
26
import net .schmizz .sshj .userauth .keyprovider .FileKeyProvider ;
28
27
import net .schmizz .sshj .userauth .keyprovider .KeyFormat ;
28
+ import org .bouncycastle .asn1 .nist .NISTNamedCurves ;
29
+ import org .bouncycastle .asn1 .x9 .X9ECParameters ;
30
+ import org .bouncycastle .jce .spec .ECNamedCurveSpec ;
29
31
import org .mindrot .jbcrypt .BCrypt ;
30
32
import org .slf4j .Logger ;
31
33
import org .slf4j .LoggerFactory ;
32
34
33
35
import java .io .BufferedReader ;
34
36
import java .io .IOException ;
37
+ import java .math .BigInteger ;
35
38
import java .nio .ByteBuffer ;
36
39
import java .nio .CharBuffer ;
37
40
import java .nio .charset .Charset ;
38
- import java .security .GeneralSecurityException ;
39
- import java .security .KeyPair ;
40
- import java .security .PublicKey ;
41
+ import java .security .*;
42
+ import java .security .spec .ECPrivateKeySpec ;
43
+ import java .security .spec .InvalidKeySpecException ;
44
+ import java .security .spec .RSAPrivateKeySpec ;
41
45
import java .util .Arrays ;
42
46
43
47
/**
@@ -125,10 +129,12 @@ private PlainBuffer decryptBuffer(PlainBuffer privateKeyBuffer, String cipherNam
125
129
private void initializeCipher (String kdfName , byte [] kdfOptions , Cipher cipher ) throws Buffer .BufferException {
126
130
if (kdfName .equals (BCRYPT )) {
127
131
PlainBuffer opts = new PlainBuffer (kdfOptions );
128
- CharBuffer charBuffer = CharBuffer .wrap (pwdf .reqPassword (null ));
129
- ByteBuffer byteBuffer = Charset .forName ("UTF-8" ).encode (charBuffer );
130
- byte [] passphrase = Arrays .copyOfRange (byteBuffer .array (),
131
- byteBuffer .position (), byteBuffer .limit ());
132
+ byte [] passphrase = new byte [0 ];
133
+ if (pwdf != null ) {
134
+ CharBuffer charBuffer = CharBuffer .wrap (pwdf .reqPassword (null ));
135
+ ByteBuffer byteBuffer = Charset .forName ("UTF-8" ).encode (charBuffer );
136
+ passphrase = Arrays .copyOfRange (byteBuffer .array (), byteBuffer .position (), byteBuffer .limit ());
137
+ }
132
138
byte [] keyiv = new byte [48 ];
133
139
new BCrypt ().pbkdf (passphrase , opts .readBytes (), opts .readUInt32AsInt (), keyiv );
134
140
byte [] key = Arrays .copyOfRange (keyiv , 0 , 32 );
@@ -183,13 +189,40 @@ private KeyPair readUnencrypted(final PlainBuffer keyBuffer, final PublicKey pub
183
189
}
184
190
// The private key section contains both the public key and the private key
185
191
String keyType = keyBuffer .readString (); // string keytype
186
- logger .info ("Read key type: {}" , keyType );
187
-
188
- byte [] pubKey = keyBuffer .readBytes (); // string publickey (again...)
189
- keyBuffer .readUInt32 ();
190
- byte [] privKey = new byte [32 ];
191
- keyBuffer .readRawBytes (privKey ); // string privatekey
192
- keyBuffer .readRawBytes (new byte [32 ]); // string publickey (again...)
192
+ KeyType kt = KeyType .fromString (keyType );
193
+ logger .info ("Read key type: {}" , keyType , kt );
194
+ KeyPair kp ;
195
+ switch (kt ) {
196
+ case ED25519 :
197
+ byte [] pubKey = keyBuffer .readBytes (); // string publickey (again...)
198
+ keyBuffer .readUInt32 (); // length of privatekey+publickey
199
+ byte [] privKey = new byte [32 ];
200
+ keyBuffer .readRawBytes (privKey ); // string privatekey
201
+ keyBuffer .readRawBytes (new byte [32 ]); // string publickey (again...)
202
+ kp = new KeyPair (publicKey , new EdDSAPrivateKey (new EdDSAPrivateKeySpec (privKey , EdDSANamedCurveTable .getByName ("Ed25519" ))));
203
+ break ;
204
+ case RSA :
205
+ BigInteger n = keyBuffer .readMPInt (); // Modulus
206
+ BigInteger e = keyBuffer .readMPInt (); // Public Exponent
207
+ BigInteger d = keyBuffer .readMPInt (); // Private Exponent
208
+ keyBuffer .readMPInt (); // iqmp (q^-1 mod p)
209
+ keyBuffer .readMPInt (); // p (Prime 1)
210
+ keyBuffer .readMPInt (); // q (Prime 2)
211
+ kp = new KeyPair (publicKey , SecurityUtils .getKeyFactory ("RSA" ).generatePrivate (new RSAPrivateKeySpec (n , d )));
212
+ break ;
213
+ case ECDSA256 :
214
+ kp = new KeyPair (publicKey , createECDSAPrivateKey (kt , keyBuffer , "P-256" ));
215
+ break ;
216
+ case ECDSA384 :
217
+ kp = new KeyPair (publicKey , createECDSAPrivateKey (kt , keyBuffer , "P-384" ));
218
+ break ;
219
+ case ECDSA521 :
220
+ kp = new KeyPair (publicKey , createECDSAPrivateKey (kt , keyBuffer , "P-521" ));
221
+ break ;
222
+
223
+ default :
224
+ throw new IOException ("Cannot decode keytype " + keyType + " in openssh-key-v1 files (yet)." );
225
+ }
193
226
String comment = keyBuffer .readString (); // string comment
194
227
byte [] padding = new byte [keyBuffer .available ()];
195
228
keyBuffer .readRawBytes (padding ); // char[] padding
@@ -198,6 +231,16 @@ private KeyPair readUnencrypted(final PlainBuffer keyBuffer, final PublicKey pub
198
231
throw new IOException ("Padding of key format contained wrong byte at position: " + i );
199
232
}
200
233
}
201
- return new KeyPair (publicKey , new EdDSAPrivateKey (new EdDSAPrivateKeySpec (privKey , EdDSANamedCurveTable .getByName ("Ed25519" ))));
234
+ return kp ;
235
+ }
236
+
237
+ private PrivateKey createECDSAPrivateKey (KeyType kt , PlainBuffer buffer , String name ) throws GeneralSecurityException , Buffer .BufferException {
238
+ PublicKey pk = kt .readPubKeyFromBuffer (buffer ); // Public key
239
+ BigInteger s = new BigInteger (1 , buffer .readBytes ());
240
+ X9ECParameters ecParams = NISTNamedCurves .getByName (name );
241
+ ECNamedCurveSpec ecCurveSpec = new ECNamedCurveSpec (name , ecParams .getCurve (), ecParams .getG (), ecParams .getN ());
242
+ ECPrivateKeySpec pks = new ECPrivateKeySpec (s , ecCurveSpec );
243
+ return SecurityUtils .getKeyFactory ("ECDSA" ).generatePrivate (pks );
244
+
202
245
}
203
246
}
0 commit comments