由 PKCS#7 加密消息保护的 API

2024-03-10

我当前正在尝试调用一个 API,该 API 要求我将 XML 数据放入 PKCS#7 格式。
该数据被发布到 API 端点。
响应还采用 PKCS#7 加密消息的形式(MIME 类型为 application/pkcs7-mime)。
他们提供的一些注释: 加密消息不包含任何认证链。不使用数据压缩。不使用数据加密。加密消息采用 OpenSSL PEM 格式。

我已获得两张证书。一个是我创建了请求并拥有私钥,另一个是由服务提供商提供给我的。
我已成功安装这些证书,并且可以与该服务进行通信。

我似乎已成功将数据发送到此 API 服务。
现在我正在尝试理解从该 API 收到的响应。
这个响应看起来像这样

-----BEGIN PKCS7-----
WISGCSqGSIb3DQEHSqCSWISCSQExCzSJBgUrDgWCGgUSWISGCSqGSIb3DQEHSSCS
AfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsd
WISGCSqGSIb3DQEHSqCSWISCSQExCzSJBgUrDgWCGgUSWISGCSqGSIb3DQEHSSCS
AfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsd
WISGCSqGSIb3DQEHSqCSWISCSQExCzSJBgUrDgWCGgUSWISGCSqGSIb3DQEHSSCS
AfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsd
WISGCSqGSIb3DQEHSqCSWISCSQExCzSJBgUrDgWCGgUSWISGCSqGSIb3DQEHSSCS
AfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsd
WISGCSqGSIb3DQEHSqCSWISCSQExCzSJBgUrDgWCGgUSWISGCSqGSIb3DQEHSSCS
AfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsd
WISGCSqGSIb3DQEHSqCSWISCSQExCzSJBgUrDgWCGgUSWISGCSqGSIb3DQEHSSCS
AfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsd
WISGCSqGSIb3DQEHSqCSWISCSQExCzSJBgUrDgWCGgUSWISGCSqGSIb3DQEHSSCS
AfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsd
WISGCSqGSIb3DQEHSqCSWISCSQExCzSJBgUrDgWCGgUSWISGCSqGSIb3DQEHSSCS
AfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsd
-----END PKCS7-----

(我把内容搞乱了,以防里面有敏感的东西)

有了这个回应,我需要

  1. 验证数字签名以确保响应是由提供商发送的
  2. 从此响应中获取 Xml 格式的消息

我主要使用的是充气城堡 http://www.bouncycastle.org/csharp/图书馆和 MSSignedCms 类 http://msdn.microsoft.com/en-us/library/system.security.cryptography.pkcs.signedcms%28v=vs.85%29.aspx
总而言之,我绝对一事无成。

请有人指导我在这里做什么,因为我已经在这里呆了大约 5 天,但进展缓慢。

以下是我到目前为止正在做的一些事情:

提出请求

使用 HttpWebRequest 和 HttpWebResponse 我使用我提供的证书将数据发布到服务

var store = new X509Store(StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2 cert = store.Certificates.Find(X509FindType.FindByThumbprint, "ACLKJCLKJCLKJCLKJCLKJCLKJCLKJCLKJCLKJCLK", false)[0];

HttpWebRequest request = null;
var uri = new Uri(endPointUri);
request = (HttpWebRequest) WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/pkcs7-mime";
request.ContentLength = requestString.Length;
request.ClientCertificates.Add(cert);

using (Stream writeStream = request.GetRequestStream())
{
    var encoding = new UTF8Encoding();
    byte[] bytes = encoding.GetBytes(requestString);
    writeStream.Write(bytes, 0, bytes.Length);
}
string result = null;
using (var response = (HttpWebResponse) request.GetResponse())
{
    using (Stream responseStream = response.GetResponseStream())
    {
        if (responseStream != null)
        {
            using (var readStream = new StreamReader(responseStream, Encoding.UTF8))
            {
                result = readStream.ReadToEnd();
            }
        }
    }
}

return result;

在这里我收到了上面的“BEGIN PKCS7”消息。
现在我想弄清楚该怎么办

MS 签名 CMS 类方法

SignedCms signedCms = new SignedCms();
signedCms.Decode(Encoding.Default.GetBytes(resultString));
try
{
    signedCms.CheckSignature(new X509Certificate2Collection(cert1), true);
}
catch (System.Security.Cryptography.CryptographicException e)
{
    _Log.Error(e.Message)
}

这会引发“ASN1 bad tag value met”的“signedCms.Decode”异常。

BouncyCastle ISigner

这里的文档是不存在的。
因此,首先我将响应保存到文件并使用 TextReader 对象尝试使用 BouncyCastle 进行测试

using (TextReader reader = File.OpenText(@"c:\temp\resultString.txt"))
{
    PemReader pemRd = new PemReader(reader);
    ContentInfo d = (ContentInfo)pemRd.ReadObject();
    Console.WriteLine(d.ContentType.ToString());
}

这将返回结果:“1.2.840.113549.1.7.2”
据我所知,这意味着它的“Pkcs7 签名数据”
哇哦,有些东西看起来起作用了。
但是从这里开始,我如何验证,以及如何从中提取任何信息

我的验证尝试

using (TextReader reader = File.OpenText(@"c:\temp\resultString.txt"))
{
    PemReader pemRd = new PemReader(reader);
    var signature = new CmsSignedData(pemRd.ReadObject());
}

失败 - 签名为空

var store = new X509Store(StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2 cert = store.Certificates.Find(X509FindType.FindByThumbprint, "ACLKJCLKJCLKJCLKJCLKJCLKJCLKJCLKJCLKJCLK", false)[0]; //tried with both certs
ISigner signer = SignerUtilities.GetSigner("RSA");
var bouncyx509 = DotNetUtilities.FromX509Certificate(cert1);
signer.Init(true, DotNetUtilities.FromX509Certificate(cert1).GetPublicKey());

失败 - 需要私钥来创建签名者

结束语

我希望我已经提供了足够的信息来获得一些帮助。
也许我正朝着完全错误的方向前进。

我的问题是:

  1. 如何验证数字签名?
  2. 如何从此响应中获取 Xml 格式的消息?

解决方案

感谢gtrig,我终于找到了解决方案。
使用 MS SignedCms 对象,我必须首先删除消息中的页眉和页脚,然后删除 Convert.FromBase64String

工作方案

SignedCms signedCms = new SignedCms();
resultString = resultString.Replace("\n", "").Replace("-----BEGIN PKCS7-----", "").Replace("-----END PKCS7-----", "");
signedCms.Decode(Convert.FromBase64String(resultString));

现在signedCms.ContentInfo.Content包含我期望的响应Xml消息


这是一个不完整的答案,但它可能会让你更进一步。

如果您有权访问 openssl,请尝试此操作command http://www.openssl.org/docs/apps/pkcs7.html查看是否可以读取数据:

openssl pkcs7 -in resultString.txt -text

之后在您的代码中尝试此操作(与您的代码唯一的区别是“Content”而不是“ContentType”:

Console.WriteLine(d.Content.ToString());

signedCms.Decode() 采用字节数组,这可能是 DER 格式的消息,而不是您在响应中收到的 PEM 格式的消息。为了将其放入字节数组中,您必须删除页眉和页脚(开始/结束)行并将其余部分传递给此方法:

Convert.FromBase64String()

或者,您可以使用 openssl 将文件转换为 DER 格式,然后直接从文件中读取字节。

openssl pkcs7 -in resultString.txt -outform DER -out result.der

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

由 PKCS#7 加密消息保护的 API 的相关文章

  • 如何让 Swagger 插件在自托管服务堆栈中工作

    我已经用 github 上提供的示例重新提出了这个问题 并为任何想要自己运行代码的人提供了一个下拉框下载链接 Swagger 无法在自托管 ServiceStack 服务上工作 https stackoverflow com questio
  • 为什么 Google 测试会出现段错误?

    我是 Google Test 的新手 正在尝试提供的示例 我的问题是 当我引入失败并设置GTEST BREAK ON FAILURE 1 或使用命令行选项 GTest 将出现段错误 我正在考虑这个例子 https code google c
  • 使用接口有什么好处?

    使用接口有什么用 我听说它用来代替多重继承 并且还可以用它来完成数据隐藏 还有其他优点吗 哪些地方使用了接口 程序员如何识别需要该接口 有什么区别explicit interface implementation and implicit
  • 如何使用 LINQ2SQL 连接两个不同上下文的表?

    我的应用程序中有 2 个数据上下文 不同的数据库 并且需要能够通过上下文 B 中的表的右连接来查询上下文 A 中的表 我该如何在 LINQ2SQL 中执行此操作 Why 我们正在使用 SaaS 产品来跟踪我们的时间 项目等 并希望向该产品发
  • 将 Word 文档另存为图像

    我正在使用下面的代码将 Word 文档转换为图像文件 但是图片显得太大 内容不适合 有没有办法渲染图片或将图片保存到合适的尺寸 private void btnConvert Click object sender EventArgs e
  • 在 C 中初始化变量

    我知道有时如果你不初始化int 如果打印整数 您将得到一个随机数 但将所有内容初始化为零似乎有点愚蠢 我问这个问题是因为我正在评论我的 C 项目 而且我对缩进非常直接 并且它可以完全编译 90 90 谢谢 Stackoverflow 但我想
  • 是否有实用的理由使用“if (0 == p)”而不是“if (!p)”?

    我倾向于使用逻辑非运算符来编写 if 语句 if p some code 我周围的一些人倾向于使用显式比较 因此代码如下所示 if FOO p some code 其中 FOO 是其中之一false FALSE 0 0 0 NULL etc
  • 标准化 UTF-8 到底是什么?

    The 重症监护室项目 http userguide icu project org transforms normalization 现在也有一个PHP库 http us php net manual en class normalize
  • 使用自定义堆的类似 malloc 的函数

    如果我希望使用自定义预分配堆构造类似 malloc 的功能 那么 C 中最好的方法是什么 我的具体问题是 我有一个可映射 类似内存 的设备 已将其放入我的地址空间中 但我需要获得一种更灵活的方式来使用该内存来存储将随着时间的推移分配和释放的
  • C#:帮助理解 UML 类图中的 <>

    我目前正在做一个项目 我们必须从 UML 图编写代码 我了解 UML 类图的剖析 但我无法理解什么 lt
  • C# HashSet 只读解决方法

    这是示例代码 static class Store private static List
  • C# 中的合并运算符?

    我想我记得看到过类似的东西 三元运算符 http msdn microsoft com en us library ty67wk28 28VS 80 29 aspx在 C 中 它只有两部分 如果变量值不为空 则返回变量值 如果为空 则返回默
  • 为什么 std::strstream 被弃用?

    我最近发现std strstream已被弃用 取而代之的是std stringstream 我已经有一段时间没有使用它了 但它做了我当时需要做的事情 所以很惊讶听到它的弃用 我的问题是为什么做出这个决定 有什么好处std stringstr
  • 使用管道时,如果子进程数量大于处理器数量,进程是否会被阻塞?

    当子进程数量很大时 我的程序停止运行 我不知道问题是什么 但我猜子进程在运行时以某种方式被阻止 下面是该程序的主要工作流程 void function int process num int i initial variables for
  • 动态添加 ASP.Net 控件

    我有一个存储过程 它根据数据库中存储的记录数返回多行 现在我想有一种方法来创建 div 带有包含该行值的控件的标记 如果从数据库返回 10 行 则 10 div 必须创建标签 我有下面的代码来从数据库中获取结果 但我不知道如何从这里继续 S
  • 为什么 gcc 抱怨“错误:模板参数 '0' 的类型 'intT' 取决于模板参数”?

    我的编译器是gcc 4 9 0 以下代码无法编译 template
  • 如何在非控制台应用程序中查看 cout 输出?

    输出到调试窗口似乎相当繁琐 我在哪里可以找到cout如果我正在编写非控制台信息 则输出 Like double i a b cout lt lt b lt lt endl I want to check out whether b is z
  • 不同类型指针之间的减法[重复]

    这个问题在这里已经有答案了 我试图找到两个变量之间的内存距离 具体来说 我需要找到 char 数组和 int 之间的距离 char data 5 int a 0 printf p n p n data 5 a long int distan
  • 方法优化 - C#

    我开发了一种方法 允许我通过参数传入表 字符串 列数组 字符串 和值数组 对象 然后使用这些参数创建参数化查询 虽然它工作得很好 但代码的长度以及多个 for 循环散发出一种代码味道 特别是我觉得我用来在列和值之间插入逗号的方法可以用不同的
  • 如何从 ODBC 连接获取可用表的列表?

    在 Excel 中 我可以转到 数据 gt 导入外部数据 gt 导入数据 然后选择要使用的数据源 然后在提供登录信息后 它会给我一个表格列表 我想知道如何使用 C 以编程方式获取该列表 您正在查询什么类型的数据源 SQL 服务器 使用权 看

随机推荐