I want to convert my ssh public key in *.pub file to a PublicKey(java.security.PublicKey).
The reason is that I need to inspect the algorithm of the ssh public key, is there any way to do that?
since I've got the below error.
java.lang.IllegalArgumentException: failed to construct sequence from byte[]: unexpected end-of-contents marker
at org.bouncycastle.asn1.ASN1Sequence.getInstance(Unknown Source)
at org.bouncycastle.asn1.x509.SubjectPublicKeyInfo.getInstance(Unknown Source)
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
public class PublicKeyUtil {
private PublicKeyUtil() {}
// (skip)
public static PublicKey loadPublicKey(String encoded)
throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
byte[] publicBytes = Base64.getDecoder().decode(encoded);
PublicKey publicKey =
new JcaPEMKeyConverter().getPublicKey(SubjectPublicKeyInfo.getInstance(publicBytes)); // I've got an error here, when calling the SubjectPublicKeyInfo.getInstance(publicBytes)
return KeyFactory.getInstance(
publicKey.getAlgorithm(), new org.bouncycastle.jce.provider.BouncyCastleProvider())
.generatePublic(new X509EncodedKeySpec(publicBytes));
}
// (skip)
}
below is my build.gradle
implementation 'org.bouncycastle:bcprov-jdk18on:1.78.1'
implementation 'org.bouncycastle:bcpkix-jdk18on:1.78.1'
This can be achieved with BouncyCastle. First, an AsymmetricKeyParameter
instance must be created. Actually, this is enough to use with BouncyCastle classes, so that PublicKey
is not necessarily required.
However, if PublicKey
is required for any reason (e.g. if the JCA/JCE classes are to be used), it can be created via an OpenSSHPublicKeySpec
instance.
Since you have not specified an algorithm, an RSA key is used in the following example:
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Security;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil;
import org.bouncycastle.jcajce.spec.OpenSSHPublicKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
...
Security.addProvider(new BouncyCastleProvider());
String ssh_rsa = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDgKfP2Vvx9HwhzvKFE4Yo5NdIec1KF+awxRtj+ArN83nBLErJ1FIS5hcTrJaUjAimoLfK2kigF4QWyfgjvTBzv8djCXEsjIhavbUyATaFEtq2JzrPFf2gLkgOkPhIH7ZNXx+YhHlMa44lFeyQNGqhOqaloWKuaeNw421FYx/cemuyv//OrdCLNgEms7kqDyc9V9JUkhsjElhHHIQA/SsI4eNrxNsUbLtQJQaThTm4o9iWSAjqy4sqJj//EmBwV2C4seHIuWztZTx5TF7LxD1nlxCcxONrea4LGxMK28ngujpzimEJb7ORmjvxmO62LpyZ9HuIwwKAhPsnVuTUElUD9 whatever";
AsymmetricKeyParameter asymmetricKeyParameter = OpenSSHPublicKeyUtil.parsePublicKey(Base64.getDecoder().decode(ssh_rsa.split(" ")[1]));
OpenSSHPublicKeySpec openSSHPublicKeySpec = new OpenSSHPublicKeySpec(OpenSSHPublicKeyUtil.encodePublicKey(asymmetricKeyParameter));
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(openSSHPublicKeySpec);
...
Please note that in the second step, the algorithm must be specified. Depending on the algorithm, e.g. Ed25519
or ECDSA
must be used instead of RSA
(the algorithm can be determined from the prefix, e.g. for Ed25519 the prefix is ssh-ed25519
or for ECDSA something like ecdsa-sha2-nistp256
).