package org.bouncycastle.crypto.util;

import java.io.IOException;
import java.math.BigInteger;

import org.bouncycastle.asn1.x9.ECNamedCurveTable;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.DSAParameters;
import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve;
import org.bouncycastle.util.Strings;


OpenSSHPublicKeyUtil utility classes for parsing OpenSSH public keys.
/** * OpenSSHPublicKeyUtil utility classes for parsing OpenSSH public keys. */
public class OpenSSHPublicKeyUtil { private OpenSSHPublicKeyUtil() { } private static final String RSA = "ssh-rsa"; private static final String ECDSA = "ecdsa"; private static final String ED_25519 = "ssh-ed25519"; private static final String DSS = "ssh-dss";
Parse a public key.

This method accepts the bytes that are Base64 encoded in an OpenSSH public key file.

Params:
  • encoded – The key.
Returns:An AsymmetricKeyParameter instance.
/** * Parse a public key. * <p> * This method accepts the bytes that are Base64 encoded in an OpenSSH public key file. * * @param encoded The key. * @return An AsymmetricKeyParameter instance. */
public static AsymmetricKeyParameter parsePublicKey(byte[] encoded) { SSHBuffer buffer = new SSHBuffer(encoded); return parsePublicKey(buffer); }
Encode a public key from an AsymmetricKeyParameter instance.
Params:
  • cipherParameters – The key to encode.
Throws:
Returns:the key OpenSSH encoded.
/** * Encode a public key from an AsymmetricKeyParameter instance. * * @param cipherParameters The key to encode. * @return the key OpenSSH encoded. * @throws IOException */
public static byte[] encodePublicKey(AsymmetricKeyParameter cipherParameters) throws IOException { BigInteger e; BigInteger n; if (cipherParameters == null) { throw new IllegalArgumentException("cipherParameters was null."); } if (cipherParameters instanceof RSAKeyParameters) { if (cipherParameters.isPrivate()) { throw new IllegalArgumentException("RSAKeyParamaters was for encryption"); } e = ((RSAKeyParameters)cipherParameters).getExponent(); n = ((RSAKeyParameters)cipherParameters).getModulus(); SSHBuilder builder = new SSHBuilder(); builder.writeString(RSA); builder.rawArray(e.toByteArray()); builder.rawArray(n.toByteArray()); return builder.getBytes(); } else if (cipherParameters instanceof ECPublicKeyParameters) { SSHBuilder builder = new SSHBuilder(); String name = null; if (((ECPublicKeyParameters)cipherParameters).getParameters().getCurve() instanceof SecP256R1Curve) { name = "nistp256"; } else { throw new IllegalArgumentException("unable to derive ssh curve name for " + ((ECPublicKeyParameters)cipherParameters).getParameters().getCurve().getClass().getName()); } builder.writeString(ECDSA + "-sha2-" + name); // Magic builder.writeString(name); builder.rawArray(((ECPublicKeyParameters)cipherParameters).getQ().getEncoded(false)); //Uncompressed return builder.getBytes(); } else if (cipherParameters instanceof DSAPublicKeyParameters) { SSHBuilder builder = new SSHBuilder(); builder.writeString(DSS); builder.rawArray(((DSAPublicKeyParameters)cipherParameters).getParameters().getP().toByteArray()); builder.rawArray(((DSAPublicKeyParameters)cipherParameters).getParameters().getQ().toByteArray()); builder.rawArray(((DSAPublicKeyParameters)cipherParameters).getParameters().getG().toByteArray()); builder.rawArray(((DSAPublicKeyParameters)cipherParameters).getY().toByteArray()); return builder.getBytes(); } else if (cipherParameters instanceof Ed25519PublicKeyParameters) { SSHBuilder builder = new SSHBuilder(); builder.writeString(ED_25519); builder.rawArray(((Ed25519PublicKeyParameters)cipherParameters).getEncoded()); return builder.getBytes(); } throw new IllegalArgumentException("unable to convert " + cipherParameters.getClass().getName() + " to private key"); }
Parse a public key from an SSHBuffer instance.
Params:
  • buffer – containing the SSH public key.
Returns:A CipherParameters instance.
/** * Parse a public key from an SSHBuffer instance. * * @param buffer containing the SSH public key. * @return A CipherParameters instance. */
public static AsymmetricKeyParameter parsePublicKey(SSHBuffer buffer) { AsymmetricKeyParameter result = null; String magic = Strings.fromByteArray(buffer.readString()); if (RSA.equals(magic)) { BigInteger e = buffer.positiveBigNum(); BigInteger n = buffer.positiveBigNum(); result = new RSAKeyParameters(false, n, e); } else if (DSS.equals(magic)) { BigInteger p = buffer.positiveBigNum(); BigInteger q = buffer.positiveBigNum(); BigInteger g = buffer.positiveBigNum(); BigInteger pubKey = buffer.positiveBigNum(); result = new DSAPublicKeyParameters(pubKey, new DSAParameters(p, q, g)); } else if (magic.startsWith(ECDSA)) { String curveName = Strings.fromByteArray(buffer.readString()); String nameToFind = curveName; if (curveName.startsWith("nist")) { // // NIST names like P-256 are encoded in SSH as nistp256 // nameToFind = curveName.substring(4); nameToFind = nameToFind.substring(0, 1) + "-" + nameToFind.substring(1); } X9ECParameters x9ECParameters = ECNamedCurveTable.getByName(nameToFind); if (x9ECParameters == null) { throw new IllegalStateException("unable to find curve for " + magic + " using curve name " + nameToFind); } // // Extract name of digest from magic string value; // //String digest = magic.split("-")[1]; ECCurve curve = x9ECParameters.getCurve(); byte[] pointRaw = buffer.readString(); result = new ECPublicKeyParameters(curve.decodePoint(pointRaw), new ECDomainParameters(curve, x9ECParameters.getG(), x9ECParameters.getN(), x9ECParameters.getH(), x9ECParameters.getSeed())); } else if (magic.startsWith(ED_25519)) { result = new Ed25519PublicKeyParameters(buffer.readString(), 0); } if (result == null) { throw new IllegalArgumentException("unable to parse key"); } if (buffer.hasRemaining()) { throw new IllegalArgumentException("uncoded key has trailing data"); } return result; } }