DER 在 Java 中解码 ECDSA 签名

问题描述 投票:0回答:2

我已经用 Java 生成了 ECDSA 签名,我想从中获取 R 和 S 值。据我了解,我生成的签名是 DER 编码的。有人可以向我提供一些 Java 代码(也许使用 Bouncy Castle)来检索 R 和 S 值作为 BigIntegers 吗?

注意:如果有帮助,我通过 JCE 的 Signature 类使用内置提供程序生成签名,并且我的 P_256 EC 密钥对的签名长度通常在 70 到 72 字节之间徘徊。

java asn.1 ecdsa der
2个回答
9
投票

我自己解决了这个问题。如果它对这里的任何人有帮助,那就是我是如何做到的(为了可读性,大多数异常处理已被删除):

import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Security;
import java.security.Signature;
import java.security.spec.ECGenParameterSpec;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class DecodeEcdsaSignature {

    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        byte[] signature = getSignature();      
        ASN1Primitive asn1 = toAsn1Primitive(signature);

        if (asn1 instanceof ASN1Sequence) {
            ASN1Sequence asn1Sequence = (ASN1Sequence) asn1;
            ASN1Encodable[] asn1Encodables = asn1Sequence.toArray();
            for (ASN1Encodable asn1Encodable : asn1Encodables) {
                ASN1Primitive asn1Primitive = asn1Encodable.toASN1Primitive();
                if (asn1Primitive instanceof ASN1Integer) {
                    ASN1Integer asn1Integer = (ASN1Integer) asn1Primitive;
                    BigInteger integer = asn1Integer.getValue();
                    System.out.println(integer.toString());
                }
            }
        }

    }

    private static ASN1Primitive toAsn1Primitive(byte[] data) throws Exception
    {
        try (ByteArrayInputStream inStream = new ByteArrayInputStream(data);
                ASN1InputStream asnInputStream = new ASN1InputStream(inStream);) 
        {
            return asnInputStream.readObject();
        }
    }

    private static byte[] getSignature() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ECDSA");
        ECGenParameterSpec ecParameterSpec = new ECGenParameterSpec("P-256");
        keyPairGenerator.initialize(ecParameterSpec);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        Signature signature = Signature.getInstance("SHA256withECDSA");
        signature.initSign(keyPair.getPrivate());
        signature.update("message to sign".getBytes("UTF-8"));

        return signature.sign();
    }

}

0
投票

使用 BouncyCastle 库,以下是如何从 DER 编码签名 (DER == ASN1) 获取 r 和 s:

import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Sequence;

byte[] asn1EncodedSignature
ASN1Sequence seq = ASN1Sequence.getInstance(asn1EncodedSignature);
BigInteger r = ((ASN1Integer) seq.getObjectAt(0)).getValue();
BigInteger s = ((ASN1Integer) seq.getObjectAt(1)).getValue();

要安装 BouncyCastle,请检查 Maven 存储库

请注意,它适用于 Android,并且您不需要将 BouncyCastle 添加为全局 Provider 或其他任何内容。您可以只使用上面所示的类。

© www.soinside.com 2019 - 2024. All rights reserved.