小编典典

在Java Security中使用openssh公钥(ecdsa-sha2-nistp256)

java

是否有一个Java库/示例可以读取PublicKeyJava中的JCE的openssh格式ecdsa公钥?我想将EC用于JWT

我尝试读取的格式是按照authorized_keys或Github
API(例如https://api.github.com/users/davidcarboni/keys)进行的:
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBK8hPtB72/sfYgNw1WTska2DNOJFx+QhUxuV6OLINSD2ty+6gxcM8yZrvMqWdMePGRb2cGh8L/0bGOk+64IQ/pM=

我已经找到了这个答案,这对于RSA和DSS来说是很好的:
在Java安全中使用authorized_keys中的公钥,并讨论ECDSA的openssh格式:https :
//security.stackexchange.com/questions/129910/ecdsa-为什么ssh-
keygen和java生成的公共密钥具有不同的大小

但是,我迷失了尝试将RSS / DSA代码改编为ECDSA的方法-
我不确定如何设置ECPublicKeySpec。它需要ECPointEllipticCurveECParameterSpecECField。openssh格式仅包含两个整数,这对于有意义ECPoint,但我不知道如何设置其余整数。

我一直在闲逛一堆库,包括jschsshjssh-
tools
和不错的老Bouncycastle。我最近的是:

com.jcraft.jsch.KeyPair load = com.jcraft.jsch.KeyPair.load(jsch, null, bytes[openSshKey]);

可以很好地加载密钥,但不能让我进入JCE- PublicKey只是一种byte[] getPublicKeyBlob()方法。

我是否缺少明显的东西?


阅读 981

收藏
2020-11-26

共1个答案

小编典典

为了完整起见,这是我使用的代码。它是几乎纯的JCE,在帮助器方法中散布了Bouncycastle(这会更新Java安全中的“使用authorized_keys中的公共密钥”中的示例代码):

...
        } else if (type.startsWith("ecdsa-sha2-") &&
                (type.endsWith("nistp256") || type.endsWith("nistp384") || type.endsWith("nistp521"))) {
            // Based on RFC 5656, section 3.1 (https://tools.ietf.org/html/rfc5656#section-3.1)
            String identifier = decodeType();
            BigInteger q = decodeBigInt();
            ECPoint ecPoint = getECPoint(q, identifier);
            ECParameterSpec ecParameterSpec = getECParameterSpec(identifier);
            ECPublicKeySpec spec = new ECPublicKeySpec(ecPoint, ecParameterSpec);
            return KeyFactory.getInstance("EC").generatePublic(spec);
        } ...

/**
 * Provides a means to get from a parsed Q value to the X and Y point values.
 * that can be used to create and ECPoint compatible with ECPublicKeySpec.
 *
 * @param q          According to RFC 5656:
 *                   "Q is the public key encoded from an elliptic curve point into an octet string"
 * @param identifier According to RFC 5656:
 *                   "The string [identifier] is the identifier of the elliptic curve domain parameters."
 * @return An ECPoint suitable for creating a JCE ECPublicKeySpec.
 */
ECPoint getECPoint(BigInteger q, String identifier) {
    String name = identifier.replace("nist", "sec") + "r1";
    ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(name);
    org.bouncycastle.math.ec.ECPoint point = ecSpec.getCurve().decodePoint(q.toByteArray());
    BigInteger x = point.getAffineXCoord().toBigInteger();
    BigInteger y = point.getAffineYCoord().toBigInteger();
    System.out.println("BC x = " + x);
    System.out.println("BC y = " + y);
    return new ECPoint(x, y);
}

/**
 * Gets the curve parameters for the given key type identifier.
 *
 * @param identifier According to RFC 5656:
 *                   "The string [identifier] is the identifier of the elliptic curve domain parameters."
 * @return An ECParameterSpec suitable for creating a JCE ECPublicKeySpec.
 */
ECParameterSpec getECParameterSpec(String identifier) {
    try {
        // http://www.bouncycastle.org/wiki/pages/viewpage.action?pageId=362269#SupportedCurves(ECDSAandECGOST)-NIST(aliasesforSECcurves)
        String name = identifier.replace("nist", "sec") + "r1";
        AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
        parameters.init(new ECGenParameterSpec(name));
        return parameters.getParameterSpec(ECParameterSpec.class);
    } catch (InvalidParameterSpecException | NoSuchAlgorithmException e) {
        throw new IllegalArgumentException("Unable to get parameter spec for identifier " + identifier, e);
    }
}
2020-11-26