Using openssh public key (ecdsa-sha2-nistp256) with Java Security

前端 未结 2 1377
心在旅途
心在旅途 2021-01-25 10:25

Is there a Java library/example to read an openssh format ecdsa public key to a JCE PublicKey in Java? I want to use EC for JWT .

The format I\'m trying to

2条回答
  •  Happy的楠姐
    2021-01-25 11:09

    I've found a way to do this using Bouncycastle (but would like to find a JCE way).

    Adapting the code from Using public key from authorized_keys with Java security, and refering to RFC 5656, section 3.1, the following block added to decodePublicKey will parse the single BigInt value Q, which is "the public key encoded from an elliptic curve point":

    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)
    
            // The string [identifier] is the identifier of the elliptic curve
            // domain parameters.  The format of this string is specified in
            // Section 6.1 (https://tools.ietf.org/html/rfc5656#section-6.1).
            // Information on the REQUIRED and RECOMMENDED sets of
            // elliptic curve domain parameters for use with this algorithm can be
            // found in Section 10 (https://tools.ietf.org/html/rfc5656#section-10).
            String identifier = decodeType();
            if (!type.endsWith(identifier)) {
                throw new IllegalArgumentException("Invalid identifier " + identifier + " for key type " + type + ".");
            }
    
            // Q is the public key encoded from an elliptic curve point into an
            // octet string as defined in Section 2.3.3 of [SEC1];
            // (https://tools.ietf.org/html/rfc5656#ref-SEC1)
            // point compression MAY be used.
            BigInteger q = decodeBigInt();
    
            ECPublicKey keyBC = getKeyBC(q, identifier);
            return keyBC;
        }
    

    The solution I've found for getting from Q to an ECPublicKey is the following, using the Bouncycastle API (credit to Generate ECPublicKey from ECPrivateKey for providing the starting point):

    ECPublicKey getKeyBC(BigInteger q, String identifier) {
        // https://stackoverflow.com/questions/42639620/generate-ecpublickey-from-ecprivatekey
        try {
            // This only works with the Bouncycastle library:
            Security.addProvider(new BouncyCastleProvider());
            // http://www.bouncycastle.org/wiki/pages/viewpage.action?pageId=362269#SupportedCurves(ECDSAandECGOST)-NIST(aliasesforSECcurves)
            String name = identifier.replace("nist", "sec") + "r1";
            KeyFactory keyFactory = KeyFactory.getInstance("ECDSA", "BC");
            ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(name);
            ECPoint point = ecSpec.getCurve().decodePoint(q.toByteArray());
            ECPublicKeySpec pubSpec = new ECPublicKeySpec(point, ecSpec);
            ECPublicKey publicKey = (ECPublicKey) keyFactory.generatePublic(pubSpec);
            return publicKey;
        } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException e) {
            throw new RuntimeException(e);
        }
    }
    

    That gets you from an openssh format elliptic curve public key (ssh-keygen -t ecdsa -b [256|384|521]) to a JCE ECPublicKey.

提交回复
热议问题