椭圆曲线数字签名格式

Elliptic curve digital signature formats

有一个基于 Java 库 github/esig/dss 构建的应用程序,目标是向 PDF 文件添加远程签名。 不同的方法创建不同格式的签名。它们之间如何转换?特别是如何将pkcs11格式转换为ASN1格式?

If PKCS11 is used with smart card then sha256 hash 53EDC760B7A66E1F4D8B0C5715725EE447B79C02F7759C52AD3D36EADD29C10A produces signature like 3066023100ba193a7a87666ebd0f923b7368beeb536b88de47834049d3ed3baf70a23635ac9b73f671beef944b36332754a434f9de023100d4984ef9f4ef61eec28f73cee6f5d8f7a391420c8f21fcc018641f5b54f600458f2d2f823e632ab017fa041e58d48a3f using algorithm ECDSA_SHA256

这是正确的 ASN1 结构

$ openssl asn1parse -inform der -in signature.bin
    0:d=0  hl=2 l= 102 cons: SEQUENCE          
    2:d=1  hl=2 l=  49 prim: INTEGER           :BA193A7A87666EBD0F923B7368BEEB536B88DE47834049D3ED3BAF70A23635AC9B73F671BEEF944B36332754A434F9DE
   53:d=1  hl=2 l=  49 prim: INTEGER           :D4984EF9F4EF61EEC28F73CEE6F5D8F7A391420C8F21FCC018641F5B54F600458F2D2F823E632AB017FA041E58D48A3F

然而,使用 pkcs11-tool 从 CLI 创建签名时,签名长度不同,因此格式不同。如何将此格式转换为ASN1 der格式?

$ echo "53EDC760B7A66E1F4D8B0C5715725EE447B79C02F7759C52AD3D36EADD29C10A" |pkcs11-tool -s --slot 1 -p <PIN> |xxd -p -c96
Using signature algorithm ECDSA
3f8c7060430cae99a048618035548bb7449fd9795cad2d8b3b8888fff78593da79cf39a41314a832dd8bae0b5f86c165775fcee045a477809fa8bb3245330abec22443aa8b5bccb775c32238eda1e8ce31a2a84d67b58dc9e3697c3eb8497f43

经过更多研究,我从 BouncyCastle 库中找到了答案。 byte[] 签名是 RS 编码签名,return 值将是 ASN.1 编码签名。

static byte[] concatenatedRSToASN1DER(final byte[] signature, int signLength) {
    int len = signLength / 2;
    int arraySize = len + 1;

    byte[] r = new byte[arraySize];
    byte[] s = new byte[arraySize];
    System.arraycopy(signature, 0, r, 1, len);
    System.arraycopy(signature, len, s, 1, len);
    BigInteger rBigInteger = new BigInteger(r);
    BigInteger sBigInteger = new BigInteger(s);

    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    try {
        DERSequenceGenerator seqGen = new DERSequenceGenerator(bos);

        seqGen.addObject(new ASN1Integer(rBigInteger.toByteArray()));
        seqGen.addObject(new ASN1Integer(sBigInteger.toByteArray()));
        seqGen.close();
        bos.close();
    } catch (IOException e) {
        throw new RuntimeException("Failed to generate ASN.1 DER signature", e);
    }
    return bos.toByteArray();
}