如何在由ECDSA [r,s]值组成的openssl中验证签名?

时间:2018-09-27 21:13:01

标签: java openssl cryptography bouncycastle ecdsa

我正在使用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 :(得分:1)

OpenSSL需要X9.62签名。它由两个整数R和S的DER编码组成。如果查看提供者类SignatureSpi的Bouncy Castle源代码,您会发现:

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

这是您应该使用Bouncy Castle编码签名的方式。这里的rs应该是在两个元素结果数组中获得的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解码