如何将 ECDSA 公钥转换为 OpenSSH 格式以便与 ssh 一起使用?
/**
* SSH helper functions.
*/
public class SshKeys
{
/**
* Creates a new instance.
*/
public SshKeys()
{
}
/**
* Returns the OpenSSH representation of a public key.
*
* @param publicKey the public key
* @param comment the comment to append to the end of the key
* @return the PEM representation of the public key
*/
public String toOpenSshPublicKey(PublicKey publicKey, String comment)
{
return switch (publicKey)
{
case ECPublicKey ecPublicKey -> toOpenSshPublicKey(ecPublicKey, comment);
default -> throw new ClassCastException(publicKey.getClass().getName());
};
}
/**
* @param publicKey the public key
* @param comment the comment to append to the end of the key
* @return the OpenSSH representation of the key
* @throws NullPointerException if any of the arguments are null
*/
public String toOpenSshPublicKey(ECPublicKey publicKey, String comment)
{
requireThat(comment, "comment").isNotNull();
AsymmetricKeyParameter param = getAsymmetricKeyParameter(publicKey);
// Encode the public key in OpenSSH format
byte[] encodedPublicKey;
try
{
encodedPublicKey = OpenSSHPublicKeyUtil.encodePublicKey(param);
}
catch (IOException e)
{
// The exception is declared but never actually thrown by the method
throw new AssertionError(e);
}
// Determine the SSH key type based on the curve name
String sshKeyType = getSshKeyType(publicKey);
return sshKeyType + " " + Base64.getEncoder().encodeToString(encodedPublicKey) + " " + comment;
}
/**
* @param publicKey a public key
* @return the asymmetric key parameters of the key
* @throws NullPointerException if {@code publicKey} is null
*/
private AsymmetricKeyParameter getAsymmetricKeyParameter(ECPublicKey publicKey)
{
// Retrieve the curve parameters from the named curve
X9ECParameters ecParams = ECNamedCurveTable.getByName(getCurveName(publicKey));
ECCurve curve = ecParams.getCurve();
ECPoint g = ecParams.getG();
BigInteger n = ecParams.getN();
BigInteger h = ecParams.getH();
// Convert java.security.spec.ECPoint to BouncyCastle ECPoint
java.security.spec.ECPoint w = publicKey.getW();
ECPoint q = curve.createPoint(w.getAffineX(), w.getAffineY());
ECDomainParameters domainParams = new ECDomainParameters(curve, g, n, h);
return new ECPublicKeyParameters(q, domainParams);
}
/**
* @param publicKey a public key
* @return the name of the elliptic curve used in the public key
* @throws NullPointerException if {@code publicKey} is null
*/
private String getCurveName(ECPublicKey publicKey)
{
ECNamedCurveSpec params = (ECNamedCurveSpec) publicKey.getParams();
return params.getName();
}
/**
* @param publicKey a public key
* @return the SSH type of the public key
* @throws NullPointerException if {@code publicKey} is null
*/
private String getSshKeyType(ECPublicKey publicKey)
{
String curveName = getCurveName(publicKey);
// SSH key prefix: https://datatracker.ietf.org/doc/html/rfc5656#section-6.2
return "ecdsa-sha2-" + switch (curveName)
{
// Mapping from curve type to SSH key type: https://datatracker.ietf.org/doc/html/rfc5656#section-10.1
// Equivalent curves: https://www.rfc-editor.org/rfc/rfc4492.html#page-32
case "secp256r1", "prime256v1" -> "nistp256";
case "secp384r1" -> "nistp384";
case "secp521r1" -> "nistp521";
default -> throw new IllegalArgumentException("Invalid curve type: " + publicKey);
};
}
}