问题
I'm using java.security.KeyPairGenerator to gen an RSA key pair, and then try to load the private key via the KeyPair class provided in Jsch(0.1.49). The code:
public static void main(String[] args) {
String header = "-----BEGIN RSA PRIVATE KEY-----";
String footer = "-----END RSA PRIVATE KEY-----";
KeyPairGenerator keyPairGenerator;
try {
keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048, new SecureRandom());
PrivateKey privateKey = keyPairGenerator.genKeyPair().getPrivate();
String key = new String(Base64.encodeBase64(privateKey.getEncoded()));
StringBuffer pem = new StringBuffer(header+"\n");
int len=key.length();
for( int idx=0 ; idx < len ; idx+= 64 )
pem.append(key.substring(idx, (idx+64)<len?(idx+64):len)+"\n");
pem.append(footer);
String privateKeyStr = pem.toString();
System.out.println(privateKeyStr);
com.jcraft.jsch.KeyPair.load(null, privateKeyStr.getBytes(), null);
} catch (JSchException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
The output by System.out:
-----BEGIN RSA PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCABIDFa/cp23OH
PZwpnBme3mvVun8ErtTpMtjCHBKbFyiVKI84e1sZt6BosIiXVbhJ3wsG+tmcJAVK
+rVRqSHUjPh9lHSI+4QQNvWIQC+v6zPyLKVRo47VK6dKTIZrsfA/A/+3hk/GrNx8
gbx9yENZ6WLg7GQ0mUwdV+kDwudll5sXjL7PHMIkVuxDOFv1cXXYmPuCtnFKvn/X
5XnD6fV8IOgLbwXTNzUxLdfnBn90PFYbRRUJVwIXzqSVJb3EXsEL6WAl2KdQ2BPS
UEv7jEw2Ja+fztUZUjqxWcrckq3rKUeHn3ykhTlq0+Iqg5sbgqz2zYt+6Zq4w42E
XrCqGlmVAgMBAAECggEAYLcGMiBnEpBgr4O0PxtXn9aZ0VacL4WGBMgNSli7FcBh
QI7r5NgM81jvLyhviSWRnP2M7zEExhnQhdzyr0b/7/ywnu9RO0wJcdaTmOQlItqm
3Acuvoa6mgHo2REHXMWJo5H510T5cDeYO9gn9z8c4wiXUyZEbhiCkIih2d2dw/mv
SBwfwOQN/3JXNBlW5c012usG6MLKvbOAYhqLfzq89ZqKJnrRW58Y6m+qb91fx5tt
DKrqVEXPBLcC0faXK+iMINGIbXqv8l1hd69f/SzSveI49yMgJBPCS5mtckcJqCm7
oxMafu3zGhaR7TYUM6CaqP3Sk2nLv6Sy9vNsFt4eAQKBgQD1TM/2nMV2HhVOl6Gm
hqCSGCxb6M+bv92tlkvuijpU0Bx5JjHTQ/dk8+0L0h/x+jPMo1+yrYyXNmE4kzyY
2s4jcDcBch5d8bSKksPv29sKYkMhEv0O31fcGVFhOyHvBm92EtA+l2vDVn0WSo7r
SAjsD3QSAdEr/pOqrUjInJfvMQKBgQCFmgjkVuMHgg5fjM+xQnPtLpJBRbe+gBdj
09jCj5D0mN5WpqvjO2cV40i2vYqaWz3/BgWcmlT4Crf2MtYxmR0rWsSQQsnk34EU
vej5kmkT8Pq4HRMskH2f/kNu55yHjY4TvMn13Gl9UWIb+g5oYdMbpb6B9jol9gm8
Op1wiopfpQKBgAbTvHYApv5CmBU34yffV1i5k4J7WEvday4JoNNixXzWzfQRPBHF
Mn18zHwnvPvfGtH3OhKfAeqzeME6V9VpQZN67Az+QBodQAkbTJjAZbhEQ9oHzUM8
tBVMHxe1rZwZccC3hVQ4oqctIQ4dxRyHRLhNNc3KfyfaTgHSENSEhzYBAoGAS4j8
MAVD1JHeiH03S9PzcQzcmdTN/wGyt7klm1LKNNBdHIadNhr2vHRFPzRIsd6WXaJM
9+51zctZmPPDEEWuLT3jVmC8fw8yjsSUfM4fZKvhRMkDdzW2IQgDnieK40TQKC6b
zMqyRa0GmCS3kqKEVeROonHRDHdfp7FIJEHf3BUCgYAjzIH744n31iTa/WhLXoIx
tR8rvTgdW6tn0YKGKy2RvgkABdDdjFc1oGBOSgNRopn1mL7cVtScMOenPTqKCEgO
yzVVOgE0ON1YmF/t3phOcJYIC9dy1CMHOjnG3deWxu2z3NAidF2TcAf8G/LtKOY2
t6uWCaHlDg2r/WDkbpxsgA==
-----END RSA PRIVATE KEY-----
Then I see exceptions from KeyPair saying it's an invalid private key, I checked the source code of JSch, the exception is due to an indexoutofbounds while the data's being parsed. The stacktrace:
com.jcraft.jsch.JSchException: invalid privatekey: [B@5f2e5f2e
at com.jcraft.jsch.KeyPair.load(KeyPair.java:809)
at com.ibm.maestro.common.utils.Test.main(Test.java:149)
I'm guessing I can fix this issue by adding/changing some parms while generating the key pair, any clue? Your help will be highly appreciated!
回答1:
The Sun JCA provider will return an DER-encoded unencrypted PKCS #8 structure, rather than an RSAPrivateKey object when you call PrivateKey.getEncoded()
.
You can use BouncyCastle to give you the key in the format you require:
import java.io.StringWriter;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.SecureRandom;
import org.bouncycastle.openssl.PEMWriter;
public class JSCH {
public static void main(String[] args) throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048, new SecureRandom());
PrivateKey privateKey = keyPairGenerator.genKeyPair().getPrivate();
StringWriter writer = new StringWriter();
try (PEMWriter pemWriter = new PEMWriter(writer)) {
pemWriter.writeObject(privateKey);
}
String privateKeyStr = writer.toString();
System.out.println(privateKeyStr);
com.jcraft.jsch.KeyPair
.load(null, privateKeyStr.getBytes("US-ASCII"), null);
}
}
There may be a more elegant way to get the encoded key as a byte string. It feels ugly to write it as a string and call getBytes()
, but perhaps you can look into this.
Example output:
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA3r29olF+Kul+aHsB28i9x8RiH6OEgIDoqcN4Ph0+bCYBi9lk
E/TVtLXxNxXvvcsK5DyQLZAWj/W0QmvmItndkzcWFojIoS3XT7kFPeC49hPe6g/W
ihM7eS5W3wTzAoljimyMjFUkw9ahShRrL+Dl6ZeqMW5bTwUXgcIFSKNw4iFQJFFO
5G8a1ObAV5iNA1ve5IFntKjCc5WIA4byilBCLcoXCeQNSPwyGVc1Okz22FTAQFzk
9eQthuF3AIAhHcDgf1yxx6RTTMMMSWzIva6xZvTHCKov3CwTLioH1Ri72UT9GAoq
O4hS/CL4Q4m09X6KGicXR86CpQ8TiXD4A+HwkQIDAQABAoIBAQCLYmrvz1VHnzPm
R8ti8NypzN+mctnw3Do8OcDeBcjRPntLO2+f+V9eJVjcItMSjqOzLZ7/lCI6VgRG
aGTsPC+m9xrQYSpDin8pOVvpW94Cx26ARAb6Aoz+CRx9lQhI9xaeQc015/YIwx/N
TrfAj1jwc2Miaa+j5EjQf0x1Jyn1pr41vgC5z2zD+FyNfVOu7Q4rmiEIi3B+QHWg
33YhtJrP2nWEmka6pn0NiYlS3IZRA6tL7DUC62iTfs7vs5M6OCsg9w7Vfq5YGwr3
cm9n+VencsupB4A6b13XZPWhyaImGO7+5TQy4xX9/mT99GoC6L73RX5O4Ehhg++m
NpB8Bt5tAoGBAO+rR0dleFeH4aHtMeLlatjZhSIWcRzXqW/bkeaq4SrhF7h4GC9J
Spih1fjWMznrfcsHxgJyYtZ3OBPMp7DhUZR9WbeqOwpD5Qd0Kr3LovKiX6HTeNKQ
QyPvca0n3z6a72XGqbKonoXhUJ2OKv8pl7nVaBxO9r/YloTLZ5SOMpmHAoGBAO3r
LU6zxBdUzaJ28tuNx2TCJJyLCDSrnZFgyTA+xexk1wpJXOJxmCVBTl5tajYwhjTc
9OMOVGr8qgcblcDOSCy4khZrgStHfjzZBQA8zesR/vNO+nzGxzfzIMSNey7OKtAB
LoKMEe1O1FuxTCiQZveekzZlT3EKDgU809UDvksnAoGANGXF154fiUNz2Or6lRiD
G5WyvZkacavUp1fhtgR15eIARZw77VqgrG31UcnCuU762YCBkddgNHMsF2gO4WTh
aQ1eqADXl47wa4jCL2xt244USlTpfV98zkZzG+AztoQ5Ao9EWoLy5WI1Nbz3OYHm
YgJ+GHJLD/ZSMgYmRxwvg9ECgYBVDs0l4/Lo/HJ/8NKmV6u/hAEezj3ixrAQd2+2
BdswxmRy0wOYGVBxkUV5UNi2AucYIx6Rxl+72BTZca06PwVip6HizhBh7q9dBaFa
EmLz9X0Wc1fuIAq9H/jJDGPLuf1oW+PK3FTUaGhXV62ImweU42Zx/gpGuXeFu9dn
wmzX5QKBgHgbQHqcf36bvwE/zr9jLCOPSkVZpFPYNt6/uUT/Vb4vDPME2/wk1SoU
wV2I3Vj9bLsnkpsP6fOsX3QqGFwlnnpboF/IS9rObTkDZXsKfLJhT5x6xA6USnWC
ZPY8jO4b1RXf3v1mHpkx21dKmY2YvNetzp6OaK8DzPwFM8KUh5GG
-----END RSA PRIVATE KEY-----
回答2:
You can use PEMWriter to convert your private key to PEM format that will be accepted by JSch
The following example converts a key returned from KeyStore (JKS)
Key privateKey = KeyStore.getKey(privateKeyAlias, keyStorePassword);//get key from JKS
StringWriter stringWriter = new StringWriter();
PEMWriter pemWriter = new PEMWriter(stringWriter);
pemWriter.writeObject(privateKey);
pemWriter.close();
byte[] privateKeyPEM = stringWriter.toString().getBytes();
来源:https://stackoverflow.com/questions/14276246/jsch-getting-invalid-privatekey-while-trying-to-load-an-rsa-private-key-by-ke