Как проверить подпись в openssl, состоящую из значений ECDSA [r, s]? - PullRequest
0 голосов
/ 28 сентября 2018

Я использую Bouncy Castle / Java для генерации подписи, так как он дает 2 больших целых числа со значениями R, S.Теперь необходимо проверить, что с помощью команд OpenSSL.

public static String[] generateSignature(String message) {
    final ECDSASigner ecdsaSigner = new ECDSASigner();

    try {

        // Get private key

        BCECPrivateKey ecPrivateKey = (BCECPrivateKey) JKSUtil.getPrivateKey();
        if(ecPrivateKey != null) {
            // Get parameter spec from private key
            ECParameterSpec ecSpec = ecPrivateKey.getParameters();

            // Create ECDomain object
            ECDomainParameters params = new ECDomainParameters(ecSpec.getCurve(), ecSpec.getG(), // G
                    ecSpec.getN()); // n

            // Create private key parameters
            ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(ecPrivateKey.getD(), // d
                    params);

            ecdsaSigner.init(true, priKey);

            // Create digest message (hash) for the actual message. 
            SHA256Digest keyDigest = new SHA256Digest();
            keyDigest.update(message.getBytes(), 0, message.getBytes().length);
            byte[] digestMessage = new byte[keyDigest.getDigestSize()];
            keyDigest.doFinal(digestMessage, 0);
            BigInteger[] sig = ecdsaSigner.generateSignature(digestMessage);

            // Convert signature to base64
            String[] base64Sig = new String[2];
            base64Sig[0] = new String(Base64.encodeBase64(sig[0].toByteArray()));
            base64Sig[1] = new String(Base64.encodeBase64(sig[1].toByteArray()));
            String signature = base64Sig[0]+"|"+base64Sig[1];

            System.out.println(signature);

            return base64Sig;
        }
    } catch (Exception e) {

    }

    return null;
}

Например: мое сообщение, которое я хочу подписать, является "Name is RS", при запуске вышеуказанной утилиты мне возвращаются значения R и S с разделителем '|'закодирован в base64 как

ALk8VQP5XLmCIe0Kh3IE74fS55huvzv0jw==|Hj+UsStEbDYOqX98EszSET2ULE3D9kCV

Теперь на стороне openssl:

openssl enc  -base64 -d -in signature.txt -out signatureToVerify.bin -A
openssl dgst -sha256 -verify eckey.pub -signature signatureToVerify.bin message.txt

Не удалось проверить, и я застрял - продолжайте получать ошибку как «Ошибка проверки» на стороне openssl.

1 Ответ

0 голосов
/ 28 сентября 2018

OpenSSL требует подписи X9.62.Он состоит из кодировки DER двух целочисленных значений R и S. Если вы посмотрите на исходный код Bouncy Castle для класса провайдера SignatureSpi, вы найдете:

ASN1EncodableVector v = new ASN1EncodableVector();
v.add(new ASN1Integer(r));
v.add(new ASN1Integer(s));
byte[] derEncodedSignature = new DERSequence(v).getEncoded(ASN1Encoding.DER);

, что вам следует использоватьзакодировать подпись с помощью Bouncy Castle.Здесь r и s должны быть значениями BigInteger, которые вы получаете в массиве результатов из двух элементов.

Как вы уже догадались, вы также можете использовать класс Java JCA Signature, которыйбудет производить ту же кодировку подписи.При необходимости или желании вы можете использовать реализацию BouncyCastle в качестве основного поставщика, зарегистрировавшись / указав поставщика.Забавно, что библиотека Bouncy Castle теперь имеет довольно быструю реализацию EC, которая превосходит реализацию, предоставляемую Oracle, даже если она в нативном коде.


Вывод binary напрямую совместим свход для подписи OpenSSL.Чтобы создать текстовую строку, можно закодировать байтовый массив в строку из 64 строк (предпочтительно без окончания строки, например, Base64.encode(derEncodedsignature)), которая затем должна быть декодирована как openssl enc -base64 -A -d -in signature.txt -out signatureToVerify.bin

...