Как преобразовать общедоступную кодовую точку EC и имя кривой в PublicKey?

У меня есть два массива байтов длиной 32 байта, представляющие значения X и Y для открытого ключа EC. Я знаю, что кривая называется кривой "prime256v1".

Как я могу превратить это в объект Java PublicKey?

Похоже, что JCE не предоставляет никаких средств для использования именованных кривых.

Bouncycastle пример кода не компилируется ни с одной версией bouncycastle, которую я могу найти.

ВТФ?


person nsayer    schedule 25.03.2014    source источник


Ответы (2)


Оказывается, на самом деле есть еще один способ сделать это. Очевидно, класс AlgorithmParameters можно использовать для преобразования ECGenParameterSpec с именованной кривой в объект ECParameterSpec, который можно использовать с KeyFactory для создания объекта PublicKey:

            ECPoint pubPoint = new ECPoint(new BigInteger(1, x),new BigInteger(1, y));
            AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC", "SunEC");
            parameters.init(new ECGenParameterSpec("secp256r1"));
            ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class);
            ECPublicKeySpec pubSpec = new ECPublicKeySpec(pubPoint, ecParameters);
            KeyFactory kf = KeyFactory.getInstance("EC");
            return (ECPublicKey)kf.generatePublic(pubSpec);
person nsayer    schedule 30.03.2015

Я не вижу способа в JCE использовать именованную кривую непосредственно для ключа, но ее можно использовать для генерации ключа, а затем из этого ключа можно извлечь параметры:

    // generate bogus keypair(!) with named-curve params
    KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
    ECGenParameterSpec gps = new ECGenParameterSpec ("secp256r1"); // NIST P-256 
    kpg.initialize(gps); 
    KeyPair apair = kpg.generateKeyPair(); 
    ECPublicKey apub  = (ECPublicKey)apair.getPublic();
    ECParameterSpec aspec = apub.getParams();
    // could serialize aspec for later use (in compatible JRE)
    //
    // for test only reuse bogus pubkey, for real substitute values 
    ECPoint apoint = apub.getW();
    BigInteger x = apoint.getAffineX(), y = apoint.getAffineY();
    // construct point plus params to pubkey
    ECPoint bpoint = new ECPoint (x,y); 
    ECPublicKeySpec bpubs = new ECPublicKeySpec (bpoint, aspec);
    KeyFactory kfa = KeyFactory.getInstance ("EC");
    ECPublicKey bpub = (ECPublicKey) kfa.generatePublic(bpubs);
    //
    // for test sign with original key, verify with reconstructed key
    Signature sig = Signature.getInstance ("SHA256withECDSA");
    byte [] data = "test".getBytes();
    sig.initSign(apair.getPrivate());
    sig.update (data);
    byte[] dsig = sig.sign();
    sig.initVerify(bpub);
    sig.update(data);
    System.out.println (sig.verify(dsig));

Вы получаете параметры, но, по-видимому, больше не связаны с OID, что может иметь значение. В частности, это может рассматриваться как «произвольное» или «явное» в TLS и не работать, даже если стороны TLS поддерживают ту же самую кривую по имени.

Обратите внимание, что openssl использует имя prime256v1, но не все. Java (вс.) использует secp256r1 или OID. Если вы на самом деле получаете этот публичный ключ от openssl, обратите внимание, что JCE может напрямую читать формат X.509 SubjectPublicKeyInfo, который openssl вызывает PUBKEY, включая именованную форму (OID).

person dave_thompson_085    schedule 26.03.2014
comment
Если форма getEncoded() результирующего открытого ключа не является формой, имеющей OID кривой, то это не сработает для меня. Мне нужно использовать полученный PublicKey в запросе сертификата. BouncyCastle может это сделать, и я не возражаю против использования BouncyCastle. Просто я не могу понять, как это сделать, потому что, насколько я могу судить, их пример кода — b0rk3d. - person nsayer; 26.03.2014
comment
На самом деле, неважно. Я попробовал это, и это действительно приводит к тому, что getEncoded() показывает правильные вещи при вводе в openssl asn1parse. Ура! - person nsayer; 26.03.2014
comment
Предполагая, что вы имеете в виду JCE (не Bouncy), вы правы. Я отладил, и sun.security.ec.ECNamedCurve сохраняет имя/OID кривой и кодирует его, даже если он недоступен в API. - person dave_thompson_085; 28.03.2014
comment
ECParameterSpec сам по себе не сериализуем. - person Maarten Bodewes; 25.08.2014
comment
Ты прав. Вы все равно могли бы сделать это с отражением — я уверен, не пытаясь, потому что вы можете сделать все с отражением — но это кувалда. Продолжая отладку, я нахожу static public sun.security.ec.NamedCurve.getECParameterSpec (String name_or_OID_as_string) -- это не задокументированный класс, но поскольку всей этой функции нет (пока?) в задокументированном API, это кажется наименее плохим обходным путем. - person dave_thompson_085; 27.08.2014