Как DER закодировать открытый ключ ECDH в BouncyCastle Java

#java #bouncycastle

#java #bouncycastle

Вопрос:

Итак, я знаю, как кодировать / декодировать открытый ключ в библиотеке BouncyCastle C # в массив байтов:

Закодировать:

 PublicKey = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(p1.Public).GetDerEncoded();
  

Декодировать:

 ECPublicKeyParameters pubKey = (ECPublicKeyParameters)PublicKeyFactory.CreateKey(OtherPublicKey);
  

Кажется, я не могу понять, как это сделать в Java-версии библиотеки BouncyCastle, поскольку, похоже, в Java-версии библиотеки нет объекта SubjectPublicKeyInfoFactory. Однако, похоже, в Java есть класс PublicKeyFactory, поэтому похоже, что я могу просто использовать тот же код, но я не знаю, как DER закодировать открытый ключ в библиотеке Java. Кто-нибудь может помочь?? Спасибо!

——РЕДАКТИРОВАТЬ———————————————————

Хорошо, итак, вот что у меня есть на данный момент в C#:

Создайте экземпляр ECDH:

 public static ECDHBasicAgreement CreateECDHInstance(out byte[] PublicKey)
    {
        IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("ECDH");

        FpCurve curve = new FpCurve(
            new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
            new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
            new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b

        ECDomainParameters ecSpec = new ECDomainParameters(
            curve,
            curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
            new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n
            BigInteger.One); // h

        g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom()));

        AsymmetricCipherKeyPair aKeyPair = g.GenerateKeyPair();
        ECDHBasicAgreement aKeyAgreeBasic = new ECDHBasicAgreement();
        aKeyAgreeBasic.Init(aKeyPair.Private);

        PublicKey = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(aKeyPair.Public).GetDerEncoded();

        return aKeyAgreeBasic;
    }
  

Это создает и возвращает объект ECDHBasicAgreement идеально и выводит открытый ключ в форме массива байтов, закодированного der. Вот что у меня есть в Java:

 public void testECDH() throws Exception
{
    AsymmetricCipherKeyPairGenerator g = new ECKeyPairGenerator();

    Fp curve = new Fp(
        new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
        new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
        new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b

    ECDomainParameters ecSpec = new ECDomainParameters(
        curve,
        curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
        new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n
        BigInteger.ONE); // h

    g.init(new ECKeyGenerationParameters(ecSpec, new SecureRandom()));

    AsymmetricCipherKeyPair aKeyPair = g.generateKeyPair();
    ECDHBasicAgreement aKeyAgreeBasic = new ECDHBasicAgreement();
    aKeyAgreeBasic.init(aKeyPair.getPrivate());

    // The part that doesn't work
    //byte[] publickey = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(aKeyPair.getPublic()).GetDerEncoded();
}
  

В Java, похоже, не существует класса SubjectPublicKeyInfoFactory или эквивалента, который мог бы использовать aKeyPair.getPublic() и иметь возможность генерировать массив байтов в DER-кодировке. Кто-нибудь может, пожалуйста, помочь!??!!? Я почти в своем уме! Спасибо!!!!

———-ПРАВКА 2 ————————————————————————-

Хорошо, итак, вот где я сейчас:

 public void test2() throws Exception
{
    ECKeyPairGenerator g = new ECKeyPairGenerator();

    Fp curve = new Fp(
            new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
            new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
            new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b

    ECDomainParameters ecP = new ECDomainParameters(
            curve,
            curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
            new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n
            BigInteger.ONE); // h

    g.init(new ECKeyGenerationParameters(ecP, new SecureRandom()));

    // Generate key pair
    AsymmetricCipherKeyPair aKeys = g.generateKeyPair();

    JCEECPublicKey jpub = new JCEECPublicKey("EC", (ECPublicKeyParameters)aKeys.getPublic());
    JCEECPrivateKey jpriv = new JCEECPrivateKey("EC", (ECPrivateKeyParameters)aKeys.getPrivate());

    KeyPair aKeyPair = new KeyPair(jpub, jpriv);

    ECDHBasicAgreement aKeyAgree = new ECDHBasicAgreement();

    aKeyAgree.init(aKeys.getPrivate());

    byte[] encoded = aKeyPair.getPublic().getEncoded();
    // The part that breaks now (Exception DERNull)
    ECPublicKeyParameters decoded = decodeECPublicKeyParameters(encoded);
}

public static ECPublicKeyParameters decodeECPublicKeyParameters(byte[] pkByte) throws IOException {
    return (ECPublicKeyParameters) PublicKeyFactory.createKey(pkByte);
    }
  

Итак, я смог получить открытые / закрытые ключи в объекты ключей JCEEC и смог их закодировать. Когда я пытаюсь их декодировать, я получаю исключение DERNull. Я провел несколько других тестов и сгенерировал ключи, используя обычный собственный java KeyPairGenerator, и смог кодировать / декодировать ключи, поэтому я знаю, что этот метод действительно работает. Я думаю, что чего-то не хватает, когда я конвертирую асимметричные ключи шифрования в ключи JCEEC. Я заметил, что в конструкции JCEECPublicKey есть еще один параметр, третий параметр ECKeySpec. Единственная проблема в том, что я не совсем уверен, как извлечь ECKeySpec из кода, который у меня есть до сих пор (или если это вообще проблема для начала). Есть другие предложения? Спасибо!!!

Ответ №1:

Вы пробовали использовать класс Bouncycastle SubjectPublicKeyInfo? Что-то вроде:

 byte [] derEncoded;
//... 
SubjectPublicKeyInfo pkInfo = new SubjectPublicKeyInfo((ASN1Sequence)ASN1Object.fromByteArray(derEncoded))
  

Редактировать:

Есть простой, хотя и несколько неудовлетворительный способ. Вы можете использовать класс JCEPublicKey, и у него есть метод getEncoded(), который выдает (я думаю) правильный ответ.

РЕДАКТИРОВАТЬ 2:

Я учусь по ходу дела 🙂 Оказывается, вы должны определить эллиптическую кривую в параметрах алгоритма, что имеет смысл. Вот небольшое изменение, которое делает это.

     g.init(new ECKeyGenerationParameters(ecP, new SecureRandom()));

    // Generate key pair
    AsymmetricCipherKeyPair aKeys = g.generateKeyPair();

    ECParameterSpec ecSpec = new ECParameterSpec(ecP.getCurve(), ecP.getG(), ecP.getN());
    JCEECPublicKey jpub = new JCEECPublicKey("EC",
            (ECPublicKeyParameters) aKeys.getPublic(), ecSpec);
    JCEECPrivateKey jpriv = new JCEECPrivateKey("EC",
            (ECPrivateKeyParameters) aKeys.getPrivate(), jpub,  ecSpec);
  

Комментарии:

1. Спасибо за ответ, ГрегС. Да, это полезно, но я пытаюсь выяснить, как взять объект publickey и der закодировать его в массив байтов. Этот код примет массив байтов и декодирует его в объект открытого ключа.

2. @hobeau я знаю, я тоже не вижу, как это сделать. Я все еще ищу. Вы всегда можете сделать это «вручную», что довольно некрасиво.

3. Хорошо, итак, Java BouncyCastle имеет класс SubjectPublicKeyInfo, а объект имеет getDEREncoded() , однако я понятия не имею, как получить мою KeyPair.getPublic(), который является параметром шифрования, в объект SubjectPublicKeyInfo. Есть идеи по этому поводу?

4. Привет, ГрегС, большое спасибо, что поддерживаете связь со мной и за всю помощь до сих пор. Я попробовал ваш код, и, похоже, он сработал, однако, когда я попытался декодировать его с помощью: return (ECPublicKeyParameters) PublicKeyFactory.CreateKey (pkByte); он вернулся с полным исключением. Я посмотрел на PublicKeyFactory.CreateKey, и похоже, что он пытается декодировать закодированный ключ с помощью ASN1Object.fromByteArray для создания объекта SubjectPublicKeyInfo и каким-то образом не удается. Есть идеи о том, как преобразовать объект JCEECPublicKey в объект SubjectPublicKeyInfo?

5. Грег,, я серьезно должен тебе пиво. Большое вам спасибо, вы спасли мне жизнь.