Подпись EDDSA с Luna HSM с использованием Java

Я пытаюсь реализовать подпись EDDSA с Luna HSM (Gemalto)

Signature signature = null;
signature = Signature.getInstance("EDDSA", "LunaProvider");
PrivateKey privateKey = getPrivateByAlias(privateKeyLabel);
signature.initSign(privateKey);
signature.update(payload);
byte[] byteArray = signature.sign();

Но после подписания размер byteArray будет равен 71, а размер подписи EDDSA равен 64 согласно спецификации. Я не уверен, что мне здесь не хватает. Я не мог найти ни одного документа в Интернете.


person Mayuran    schedule 14.03.2020    source источник


Ответы (2)


Это именно тот размер, который можно ожидать от подписи, совместимой с X9.63, которая состоит из кодировки DER двух целых чисел с обратным порядком байтов со знаком. Если вы хотите иметь 64-байтовую подпись, вам следует преобразовать 2 целых числа внутри, используя следующее объяснение. Реализацию I2OSP и OS2IP на Java можно найти здесь.

Итак, шаги следующие:

  1. разобрать подпись ASN.1;
  2. преобразовать в значения BigInteger с помощью конструктора new BigInteger(byte[]);
  3. используйте I2OSP для создания значений r и s в виде байтового массива (размер вывода 32 октета);
  4. объедините r и s, чтобы создать 64-байтовую подпись.
person Maarten Bodewes    schedule 14.03.2020
comment
Спасибо за ответ, это мне очень помогает, сейчас я пытаюсь преобразовать формат DER в ASN.1 с помощью BouncyCastle. Я отправлю код, как только мне это удастся - person Mayuran; 15.03.2020
comment
Я пробовал следующее, но кажется, что проверка все еще не выполняется. - person Mayuran; 16.03.2020

Я пробовал следующее, но проверка не удалась (код обновлен, и теперь он работает)

        Signature signature = Signature.getInstance("SHA512withEDDSA", "LunaProvider");
        signature.setParameter(new LunaEDDSAParameterSpec(false));
        signature.initSign(privateKey);
        signature.update(payload);
        byte[] byteArray = signature.sign();

        ASN1InputStream decoder = new ASN1InputStream(byteArray);
        DERSequence seq = (DERSequence) decoder.readObject();
        DERInteger r = (DERInteger) seq.getObjectAt(0);
        DERInteger s = (DERInteger) seq.getObjectAt(1);
        LOGGER.info("R: {}", r.getValue());
        LOGGER.info("S: {}", s.getValue());
        decoder.close();

        byte[] rByte = i2osp(r.getValue(), 32);
        byte[] sByte = i2osp(s.getValue(), 32);

        byte[] concat = Bytes.concat(rByte, sByte);

        return concat;

Не уверен, что это правильный способ сделать

Проверка с использованием звездной библиотеки java

        PublicKey publicKey = getPublicByAlias(publicKeyLabel);
        LunaPublicKeyEC lunaPublicKeyEC = (LunaPublicKeyEC) publicKey;
        byte[] pubKeySub = Arrays.copyOfRange(lunaPublicKeyEC.getP(), 2, lunaPublicKeyEC.getP().length);
        org.stellar.sdk.KeyPair keyPair = org.stellar.sdk.KeyPair.fromPublicKey(pubKeySub);
        boolean verified = keyPair.verify(payload, signatureByte);
person Mayuran    schedule 16.03.2020
comment
Ir выглядит нормально, как проверить подпись? - person Maarten Bodewes; 16.03.2020
comment
@MaartenBodewes Большое спасибо, мне удалось это сделать, я публикую обновленный код для справки другим. Причина заключалась в том, что по умолчанию LunaEDDSAParameterSpec устанавливал для прехэша значение true, но я установил его в false, тогда я смог получить то же значение, что и ожидалось звездной (криптовалютной) проверкой. Я не уверен, что используется по умолчанию для EDDSA. - person Mayuran; 16.03.2020
comment
@MaartenBodewes, я использую звездную библиотеку java для проверки подписи, также обновил код выше с проверкой - person Mayuran; 16.03.2020
comment
Код обновлен, и теперь он работает, значит ли это, что проблема решена? - person Maarten Bodewes; 16.03.2020