I want to get the public key of the content of an .pub
file. This is an example what the content of a .pub
file looks like(generated with ssh-keygen
):
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDBPL2s+25Ank3zS6iHUoVk0tS63dZM0LzAaniiDon0tdWwq4vcL4+fV8BsAEcpMeijS92JhDDc9FccXlHbdDcmd6c4ITOt9h9xxhIefGsi1FTVJ/EjVtbqF5m0bu7ruIMGvuP1p5s004roHx9y0UdHvD/yNWLISMhy4nio6jLailIj3FS53Emj1WRNsOrpja3LzPXzhuuj6YnD9yfByT7iGZipxkmleaXrknChPClLI9uhcqtAzBLdd0NVTJLOt/3+d1cSNwdBw9e53wJvpEmH+P8UOZd+oV/y7cHIej4jQpBXVvpJR1Yaluh5RuxY90B0hSescUAj4g/3HVPpR/gE7op6i9Ab//0iXF15uWGlGzipI4lA2/wYEtv8swTjmdCTMNcTDw/1huTDEzZjghIKVpskHde/Lj416c7eSByLqsMg2OhlZGChKznpIjhuNRXz93DwqKuIKvJKSnhqaJDxmDGfG7nlQ/eTwGeAZ6VR50yMPiRTIpuYd767+Nsg486z7p0pnKoBlL6ffTbfeolUX2b6Nb9ZIOxJdpCSNTQRKQ50p4Y3S580cUM1Y2EfjlfIQG1JdmTQYB75AZXi/cB2PvScmF0bXRoj7iHg4lCnSUvRprWA0xbwzCW/wjNqw6MyRX42FFlvSRrmfaxGZxKYbmk3TzBv+Fp+CADPqQm3OQ== [email protected]
If I am right this is not the public key, but it is possible to get the public key from this string.
This answer gives answer to my question https://stackoverflow.com/a/19387517/2735398
But the answer doesn't seem to work. I get an exception:
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
When looking at the comments of the answer I am not the only person with the problem...
How can I fix the exception? Or is there another way to get the public key from the string?
Here is my SSH RSA -> RSAPublicKey converter implementation. I've found key format description somewhere in the net, so thanks to the one who provided it.
public class CertificateUtils {
private static final int VALUE_LENGTH = 4;
private static final byte[] INITIAL_PREFIX = new byte[]{0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61};
private static final Pattern SSH_RSA_PATTERN = Pattern.compile("ssh-rsa[\\s]+([A-Za-z0-9/+]+=*)[\\s]+.*");
// SSH-RSA key format
//
// 00 00 00 07 The length in bytes of the next field
// 73 73 68 2d 72 73 61 The key type (ASCII encoding of "ssh-rsa")
// 00 00 00 03 The length in bytes of the public exponent
// 01 00 01 The public exponent (usually 65537, as here)
// 00 00 01 01 The length in bytes of the modulus (here, 257)
// 00 c3 a3... The modulus
public static RSAPublicKey parseSSHPublicKey(String key) throws InvalidKeyException {
Matcher matcher = SSH_RSA_PATTERN.matcher(key.trim());
if (!matcher.matches()) {
throw new InvalidKeyException("Key format is invalid for SSH RSA.");
}
String keyStr = matcher.group(1);
ByteArrayInputStream is = new ByteArrayInputStream(Base64.decodeBase64(keyStr));
byte[] prefix = new byte[INITIAL_PREFIX.length];
try {
if (INITIAL_PREFIX.length != is.read(prefix) || !ArrayUtils.isEquals(INITIAL_PREFIX, prefix)) {
throw new InvalidKeyException("Initial [ssh-rsa] key prefix missed.");
}
BigInteger exponent = getValue(is);
BigInteger modulus = getValue(is);
return (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(modulus, exponent));
} catch (IOException | InvalidKeySpecException | NoSuchAlgorithmException e) {
throw new InvalidKeyException("Failed to read SSH RSA certificate from string", e);
}
}
private static BigInteger getValue(InputStream is) throws IOException {
byte[] lenBuff = new byte[VALUE_LENGTH];
if (VALUE_LENGTH != is.read(lenBuff)) {
throw new InvalidParameterException("Unable to read value length.");
}
int len = ByteBuffer.wrap(lenBuff).getInt();
byte[] valueArray = new byte[len];
if (len != is.read(valueArray)) {
throw new InvalidParameterException("Unable to read value.");
}
return new BigInteger(valueArray);
}
}
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With