I'm trying to convert a .pub
file's contents to a PublicKey
and then convert the PublicKey
back into a String
in order to determine if the conversion is working and does not change the key in the process.
id_rsa.pub:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0zszKhcZTC8xJidUszmRn4Tr/FxPs04wpCzEstebfTW7Bvqgtt+OdvxoNyYM0LAEnxEF4XhAWcsX7VJJqstZLpDqlKDXFr2d0aVIjksCpZt+ftVRwYHRoERhEOP/UmPFb5rKIkhQbED2kTWg11mW9soc6BhwB3THn/Cyo3t1u2vWjEySgPhKeA3Xzh+5eqV7CUD8V6S7OAT7T9ijf7sRV0R8rwHgTLWJ8+dETnY3L3N0fEaNuaayeNblHqrL53/1+tsBBUF3bAS+1GE6oniSeM/yhtfzf2x+O5MDlVVMbOCC/v+FnfIIEKLA+v1xDSAha7C5cHh82TxToWXsbjqGD me@mail
Converter.java
public static final synchronized PublicKey base64ToPublicKey(final String algorithm, final String base64) throws GeneralSecurityException, IOException {
BASE64Decoder decoder = new BASE64Decoder();
byte[] sigBytes2 = decoder.decodeBuffer(base64);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(sigBytes2);
KeyFactory keyFact = KeyFactory.getInstance(algorithm, "BC");
return keyFact.generatePublic(x509KeySpec);
}
public static final synchronized String publicKeyToBase64(final PublicKey publicKey) throws GeneralSecurityException, IOException {
byte[] publicKeyBytes = publicKey.getEncoded();
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(publicKeyBytes);
}
When I run:
PublicKey test1 = base64ToPublicKey("RSA", "AAAAB3NzaC1yc2EAAAADAQABAAABAQC0zszKhcZTC8xJidUszmRn4Tr/FxPs04wpCzEstebfTW7Bvqgtt+OdvxoNyYM0LAEnxEF4XhAWcsX7VJJqstZLpDqlKDXFr2d0aVIjksCpZt+ftVRwYHRoERhEOP/UmPFb5rKIkhQbED2kTWg11mW9soc6BhwB3THn/Cyo3t1u2vWjEySgPhKeA3Xzh+5eqV7CUD8V6S7OAT7T9ijf7sRV0R8rwHgTLWJ8+dETnY3L3N0fEaNuaayeNblHqrL53/1+tsBBUF3bAS+1GE6oniSeM/yhtfzf2x+O5MDlVVMbOCC/v+FnfIIEKLA+v1xDSAha7C5cHh82TxToWXsbjqGD");
I get back:
java.security.spec.InvalidKeySpecException: java.io.IOException: unexpected end-of-contents marker
at org.bouncycastle.jce.provider.JDKKeyFactory.engineGeneratePublic(Unknown Source)
at org.bouncycastle.jce.provider.JDKKeyFactory$RSA.engineGeneratePublic(Unknown Source)
at java.security.KeyFactory.generatePublic(KeyFactory.java:328)
at base64ToPublicKey(Converter.java:216)
at main(Converter.java:283)
OpenSSH public key files (
id_*.pub
also the entries inknown_hosts
andauthorized_keys
) for SSH2 use an OpenSSH-specific variant of an SSH-specific format, see rfc4716 which is in turn based on the SSH2 wire format (as linked) rfc4253 6.6, which is not the 'X.509' format Java crypto uses. (OpenSSH file formats for SSH1 were different, but SSH1 is long broken and should not be used.)To convert this in Java see convert openSSH rsa key to javax.crypto.Cipher compatible format .
It's easier to avoid the problem.
Bypass 1: If you have reasonably recent OpenSSH (6.0 is okay, not sure for earlier), use
to convert to 'X.509' (really SubjectPublicKeyInfo aka SPKI) in PEM form. (Yes they do use the name PKCS8 to mean SPKI; it's crazy.) Then read this in Java by discarding the BEGIN and END lines, decode everything in between (less the line breaks) from base64 to
byte[]
, and put that inX509EncodedKeySpec
as you have now. Or if you have OpenSSL you can convert to DER formand then read the DER file with no change at all into an
X509EncodedKeySpec
.Bypass 2: if you have the private key, and it is NOT OpenSSH's 'new' format (optional since 6.5 (edit) and default since 7.8), and you have OpenSSL, get the public key in SPKI (Java-friendly) format with one of