How to find the matching curve name from an ECPublicKey

后端 未结 2 871
轻奢々
轻奢々 2021-01-22 02:13

Currently i\'m updating my x.509 certificate library to support ECC. Most of the builders that are implemented take a publicKey and derive the algorithm and such from the key. I

相关标签:
2条回答
  • 2021-01-22 02:51

    I think i've found a valid solution using the EC5Util class for the jre type specifications. All of the double class instances with the same name make it a bit messy, however the functions are now accessible and useable.

    public static final String deriveCurveName(org.bouncycastle.jce.spec.ECParameterSpec ecParameterSpec) throws GeneralSecurityException{
        for (@SuppressWarnings("rawtypes")
               Enumeration names = ECNamedCurveTable.getNames(); names.hasMoreElements();){
            final String name = (String)names.nextElement();
    
            final X9ECParameters params = ECNamedCurveTable.getByName(name);
    
            if (params.getN().equals(ecParameterSpec.getN())
                && params.getH().equals(ecParameterSpec.getH())
                && params.getCurve().equals(ecParameterSpec.getCurve())
                && params.getG().equals(ecParameterSpec.getG())){
                return name;
            }
        }
    
        throw new GeneralSecurityException("Could not find name for curve");
    }
    
    public static final String deriveCurveName(PublicKey publicKey) throws GeneralSecurityException{
        if(publicKey instanceof java.security.interfaces.ECPublicKey){
            final java.security.interfaces.ECPublicKey pk = (java.security.interfaces.ECPublicKey) publicKey;
            final ECParameterSpec params = pk.getParams();
            return deriveCurveName(EC5Util.convertSpec(params, false));
        } else if(publicKey instanceof org.bouncycastle.jce.interfaces.ECPublicKey){
            final org.bouncycastle.jce.interfaces.ECPublicKey pk = (org.bouncycastle.jce.interfaces.ECPublicKey) publicKey;
            return deriveCurveName(pk.getParameters());
        } else throw new IllegalArgumentException("Can only be used with instances of ECPublicKey (either jce or bc implementation)");
    }
    
    public static final String deriveCurveName(PrivateKey privateKey) throws GeneralSecurityException{
        if(privateKey instanceof java.security.interfaces.ECPrivateKey){
            final java.security.interfaces.ECPrivateKey pk = (java.security.interfaces.ECPrivateKey) privateKey;
            final ECParameterSpec params = pk.getParams();
            return deriveCurveName(EC5Util.convertSpec(params, false));
        } else if(privateKey instanceof org.bouncycastle.jce.interfaces.ECPrivateKey){
            final org.bouncycastle.jce.interfaces.ECPrivateKey pk = (org.bouncycastle.jce.interfaces.ECPrivateKey) privateKey;
            return deriveCurveName(pk.getParameters());
        } else throw new IllegalArgumentException("Can only be used with instances of ECPrivateKey (either jce or bc implementation)");
    }
    
    0 讨论(0)
  • 2021-01-22 03:04

    From your description it appears what you really need is the OID, not the name. If so, that's easier, since the curve OID is present in the "X.509" encoding of an EC public key, which is actually the SubjectPublicKeyInfo structure from X.509 (replicated in PKIX, see rfc5280 #4.1 and rfc3279 #2.3.5 but skip the parts about explicit parameters, everybody uses the namedCurve=OID option) which is the encoding for JCA public keys, for both Sun/Oracle/OpenJDK and BC implementations (and all algorithms not just ECC). BC additionally provides good support to parse this structure:

    import org.bouncycastle.asn1.ASN1ObjectIdentifier;
    import org.bouncycastle.asn1.ASN1Sequence;
    import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
    import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
    import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
    
        KeyPairGenerator gen = KeyPairGenerator.getInstance("EC");
        gen.initialize(new ECGenParameterSpec("secp256r1"));
        ECPublicKey jcekey = (ECPublicKey) gen.generateKeyPair().getPublic();
        //KeyFactory fact = KeyFactory.getInstance("EC", "BC");
        //org.bouncycastle.jce.interfaces.ECPublicKey bckey = (org.bouncycastle.jce.interfaces.ECPublicKey)fact.generatePublic(new X509EncodedKeySpec(jcekey.getEncoded()));
    
        // with Bouncy
        byte[] enc = jcekey.getEncoded(); //enc = bckey.getEncoded();
        SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(ASN1Sequence.getInstance(enc));
        AlgorithmIdentifier algid = spki.getAlgorithm();
        if( algid.getAlgorithm().equals(X9ObjectIdentifiers.id_ecPublicKey)){
            ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) algid.getParameters();
            System.out.println (oid.toString()); // curve OID, use as needed
        }else System.out.println ("not EC?");
    

    and for completeness even without Bouncy it's not hard if you don't use the largest curves and you're willing to cheat (which Java increasingly discourages):

    import sun.security.util.DerInputStream;
    import sun.security.util.ObjectIdentifier;
    
        final ObjectIdentifier x9_id_ec = new ObjectIdentifier("1.2.840.10045.2.1");
        int off = (4+2)+enc[(4+1)];
        if( enc[0]==0x30 && enc[1]>0 && enc[2]==0x30 && enc[4]==6 
            && new ObjectIdentifier(new DerInputStream(enc,4,off-4)).equals((Object)x9_id_ec)
            && enc[off] == 6 ){
            byte[] oidenc = Arrays.copyOfRange(enc,off,off+2+enc[off+1]);
            // that's the DER-encoded OID of the curve
            ObjectIdentifier oid = new ObjectIdentifier(new DerInputStream(oidenc));
            System.out.println (oid.toString()); // and the display form
        }else System.out.println ("not EC or too big?");
    

    I'd also note if you're building a certificate, PublicKey.getEncoded() is already the entire subjectPublicKeyInfo field, which is the only place you need to put the curve OID and except for self-signed the only place you put this key's algorithm OID.

    0 讨论(0)
提交回复
热议问题