c# - 从 ASN.1 CMS 签名 Bouncy CaSTLe 检索签名 R 和 S 元素

标签 c# .net-core bouncycastle

我有一个 ASN.1 编码的分离 CMS ECC 签名 - 我使用在线解码器对其进行检查,并且可以看到签名 R 和 S 值,但我想知道如何实际获取这 2 个值。

SEQUENCE (1 elem)
Offset: 1250
Length: 2+9
(constructed)
Value:
(1 elem)
            OBJECT IDENTIFIER 1.2.840.10045.4.1 ecdsaWithSHA1 (ANSI X9.62 ECDSA algorithm with SHA1)
          OCTET STRING (71 byte) 30450220264E3B44C225A763A8C9134FC227398F8045F2269F43C849234E597230DCDF…
            SEQUENCE (2 elem)
              INTEGER (254 bit) 1732611137397374523048116562457205045056141747896936985930487632655856…
              INTEGER (256 bit) 9776787720086444189183880768608824233892259816463822789589418099639594…

到目前为止我一直在尝试:

var requestSignatureBase64 = "MIAGCSqG ...";
        
var sigBytes = Convert.FromBase64String(requestSignatureBase64);
// var asn1 = Asn1Object.FromByteArray(sigBytes);
// var derSeq = (DerSequence)asn1;

var input = new Asn1InputStream(sigBytes);

var contendInfo = ContentInfo.GetInstance(input.ReadObject());
var sData = SignedData.GetInstance(contendInfo.Content);
var sig = new CmsSignedData(contendInfo);

我很接近吗?谢谢!

我能够在 Watch 中检查似乎接近我需要的内容(但不完全)。

最佳答案

使用 ASN.1 解析器可以最轻松地确定

rs,例如与 BouncyCaSTLe:

using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Utilities.Encoders;
...
byte[] der = Hex.Decode("3044021f4043e112eebe8c92c6aee9132f24af6f73c61353dbd1b1cdde2a5429ba4e290221009caf197c3cf9838e72068097409ee23b6648b1b14d44a38a5825495893dcd629");// 3043021f1acda88726e28dbdfcea74e403e7424ba9cba588777e810e42caa5d274135502207283b90135ef09e5847516a9163f4f6a4d403abb9d7632c77397e37165632619");// 3045022100bb3435689a49cb00a04b64fbd7c886d5c67eb406781b43b4ca18bb778df6d35e02201e54c928da6c4867e2b8aafb7703b00784971ef47837433bdf8a6ecb4cdbebcd");
Asn1Sequence seq = Asn1Sequence.GetInstance(der);
BigInteger[] rsBI = new BigInteger[] {
    DerInteger.GetInstance(seq[0]).PositiveValue,
    DerInteger.GetInstance(seq[1]).PositiveValue
};
Console.WriteLine("r: " + rsBI[0]); // r: 113546697132886645577275908676387668608557658993333016730332161870441106985
Console.WriteLine("s: " + rsBI[1]); // s: 70870178508439211896524481754448149175401343396061029910903220215172053128745

这两个部分也可以表示为无符号字节数组或十六进制编码,而不是 BigInteger:

byte[] rBytes = rsBI[0].ToByteArrayUnsigned();
byte[] sBytes = rsBI[1].ToByteArrayUnsigned();
Console.WriteLine("r (hex): " + Hex.ToHexString(rBytes)); // r (hex): 4043e112eebe8c92c6aee9132f24af6f73c61353dbd1b1cdde2a5429ba4e29
Console.WriteLine("s (hex): " + Hex.ToHexString(sBytes)); // s (hex): 9caf197c3cf9838e72068097409ee23b6648b1b14d44a38a5825495893dcd629

对于 r|s 表示法,rs 必须填充到私钥大小(示例中为 32 字节)因为通常这两个部分也可以小于 key 大小:

using System.Linq;
...
byte[] rBytes32 = new byte[32 - rBytes.Length].Concat(rBytes).ToArray(); 
byte[] sBytes32 = new byte[32 - sBytes.Length].Concat(sBytes).ToArray(); 
byte[] rsBytes64 = rBytes32.Concat(sBytes32).ToArray();
Console.WriteLine("r|s: " + Hex.ToHexString(rsBytes64)); // r|s: 004043e112eebe8c92c6aee9132f24af6f73c61353dbd1b1cdde2a5429ba4e299caf197c3cf9838e72068097409ee23b6648b1b14d44a38a5825495893dcd629

为了简单起见,在最后一个代码片段中应用了 Linq。但同样可以通过复制来实现,例如使用BlockCopy()

从 .NET5 开始,有 AsnReader class(并且原生支持十六进制编码),因此不需要 BC。


编辑:

签名可以按如下方式加载:

var signedDataDer = Convert.FromBase64String("MIAGCSqG...");
var signers = new CmsSignedData(signedDataDer).GetSignerInfos().GetSigners();
IEnumerator signersEnumerator = signers.GetEnumerator();
signersEnumerator.MoveNext();
SignerInformation signerInfo = (SignerInformation)signersEnumerator.Current;
byte[] signatureDer = signerInfo.GetSignature();

现在可以如上所述确定rs

关于c# - 从 ASN.1 CMS 签名 Bouncy CaSTLe 检索签名 R 和 S 元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72097765/

相关文章:

java - bouncycaSTLe 生成 NTRU 失败

c# - 日期对象与日期时间对象

C# 入口点函数

c# - 从 'System.String' 到 'Serilog.Core.IDestructuringPolicy' 的转换无效

asp.net-mvc - ViewData 始终为空

java - Java 和 C# 中使用 Bouncy CaSTLe 进行 RSA 加密的结果之间的差异

c# - 如何将 XComment 添加到与 XElement 相同的行?

c# - 如何避免属性递归

c# - Scaffold-DbContext 在.net core 中抛出错误 "Could not find assembly"

java.io.EOFException : premature end of stream in PartialInputStream - bouncy CaSTLe