itextsharp 使用签名哈希签名 pdf

2023-12-29

我正在尝试通过签名服务签署 pdf。此服务需要发送十六进制编码的 SHA256 摘要,作为回报,我收到十六进制编码的签名值。除此之外,我还收到签名证书、中间证书、OCSP 响应和 TimeStampToken。但是,我已经在尝试使用签名值对 pdf 进行签名时陷入困境。

我读过布鲁诺的白皮书,过度浏览互联网,并尝试了许多不同的方法,但签名总是显示为无效。

我的最新尝试:

首先,准备pdf

PdfReader reader = new PdfReader(src);
FileStream os = new FileStream(dest, FileMode.Create);
PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0');
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.Certificate = signingCertificate;
IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
MakeSignature.SignExternalContainer(appearance, external, 8192);

string hashAlgorithm = "SHA-256";
PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, false);
PdfSignatureAppearance appearance2 = stamper.SignatureAppearance;
Stream stream = appearance2.GetRangeStream();
byte[] hash = DigestAlgorithms.Digest(stream, hashAlgorithm);
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);

哈希 byte[] sh 并转换为字符串,如下所示

private static String sha256_hash(Byte[] value)
{
    using (SHA256 hash = SHA256.Create())
    {
         return String.Concat(hash.ComputeHash(value).Select(item => item.ToString("x2"))).ToUpper();
    }
}

并发送至签名服务。然后我将收到的十六进制编码的签名值转换为字节

private static byte[] StringToByteArray(string hex)
{
    return Enumerable.Range(0, hex.Length).Where(x => x % 2 == 0).Select(x => Convert.ToByte(hex.Substring(x, 2), 16)).ToArray();
}

最后,创建签名

private void CreateSignature(string src, string dest, byte[] sig) 
{
    PdfReader reader = new PdfReader(src); // src is now prepared pdf
    FileStream os = new FileStream(dest, FileMode.Create);
    IExternalSignatureContainer external = new MyExternalSignatureContainer(sig);
    MakeSignature.SignDeferred(reader, "Signature1", os, external);

    reader.Close();
    os.Close();
}
private class MyExternalSignatureContainer : IExternalSignatureContainer
{
    protected byte[] sig;
    public MyExternalSignatureContainer(byte[] sig)
    {
        this.sig = sig;
    }
    public byte[] Sign(Stream s)
    {
        return sig;
    }
    public void ModifySigningDictionary(PdfDictionary signDic) { }
}

我究竟做错了什么?非常感谢您的帮助。谢谢!

编辑:当前状态

感谢 mkl 的帮助并遵循 Bruno 的延迟签名示例,我已经克服了无效签名消息。显然我没有从签名服务收到完整的链,而只是收到一个中间证书,这导致了无效的消息。不幸的是,签名仍然存在缺陷。

我这样构建链:

List<X509Certificate> certificateChain = new List<X509Certificate>
{
     signingCertificate,
     intermediateCertificate
}; 

在 MyExternalSignatureContainer 的 Sign 方法中,我现在构造并返回签名容器:

public byte[] Sign(Stream s)
{
    string hashAlgorithm = "SHA-256";
    PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, false);

    byte[] ocspResponse = Convert.FromBase64String("Base64 encoded DER representation of the OCSP response received from signing service");
    byte[] hash = DigestAlgorithms.Digest(s, hashAlgorithm);
    byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, ocspResponse, null, CryptoStandard.CMS);

    string messageDigest = Sha256_hash(sh);
    // messageDigest sent to signing service
    byte[] signatureAsByte = StringToByteArray("Hex encoded SignatureValue received from signing service");

    sgn.SetExternalDigest(signatureAsByte, null, "RSA");

    ITSAClient tsaClient = new MyITSAClient();

    return sgn.GetEncodedPKCS7(hash, tsaClient, ocspResponse, null, CryptoStandard.CMS); 
}

public class MyITSAClient : ITSAClient
{
    public int GetTokenSizeEstimate()
    {
        return 0;
    }

    public IDigest GetMessageDigest()
    {
        return new Sha256Digest();
    }

    public byte[] GetTimeStampToken(byte[] imprint)
    {
        string hashedImprint = HexEncode(imprint);
        // Hex encoded Imprint sent to signing service

        return Convert.FromBase64String("Base64 encoded DER representation of TimeStampToken received from signing service");
    }
}

仍然收到这些消息:

  1. “签名者的身份未知,因为它尚未包含在可信身份列表中,并且没有人或其父身份 证书是可信身份”
  2. “签名带有时间戳,但无法验证时间戳”

再次非常感谢您的进一步帮助!


“我究竟做错了什么?”

问题是,一方面,您开始使用PdfPKCS7实例

PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, false);

以及计算出的文档摘要hash检索签名属性

byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);

送他们签字。

到目前为止,一切都很好。

但随后您忽略了开始构建的 CMS 容器,而是注入裸签名字节你从你的服务中得到进入 PDF.

这不起作用,因为您的签名字节不直接对文档进行签名,而是对这些签名属性进行签名(因此,间接对文档进行签名,因为文档哈希是签名属性之一)。因此,通过忽略正在构建的 CMS 容器,您删除了实际签名的数据......

此外,子过滤器ADBE_PKCS7_DETACHED您使用承诺嵌入的签名是完整的 CMS 签名容器,而不是一些裸露的签名字节,因此格式也是错误的。

该怎么做呢?

您必须将它们设置为外部摘要,而不是将您从服务中获得的裸签名字节按原样注入到 PDF 中。PdfPKCS7您最初开始构建签名容器的实例:

sgn.SetExternalDigest(sig, null, ENCRYPTION_ALGO);

(ENCRYPTION_ALGO必须是签名算法的加密部分,我假设在你的情况下"RSA".)

然后就可以检索生成的CMS签名容器:

byte[] encodedSig = sgn.GetEncodedPKCS7(hash, null, null, null, CryptoStandard.CMS);

现在这是要注入到文档中的签名容器MyExternalSignatureContainer:

IExternalSignatureContainer external = new MyExternalSignatureContainer(encodedSig);
MakeSignature.SignDeferred(reader, "Signature1", os, external);

遗留问题

更正您的代码后,Adobe Reader 仍会警告您的签名:

  1. “签名者的身份未知,因为它尚未包含在可信身份列表中,并且没有一个或其父证书是可信身份”

此警告是预期且正确的!

签名者身份未知因为您的签名服务仅使用演示证书,而不是用于生产用途的证书:

如您所见,证书是由“GlobalSign Non-Public HVCA Demo”颁发的,并且非公开演示发行人出于显而易见的原因一定不能被信任(除非您出于测试目的手动将它们添加到您的信任存储中)。

  1. “签名带有时间戳,但无法验证时间戳”

Adobe 不批准您的时间戳有两个原因:

一方面,就像上面一样,时间戳证书是非公开的演示证书(“DSS Non-Public Demo TSA Responder”)。因此,验证者没有理由相信你的时间戳。

但另一方面,您的时间戳代码中存在实际错误,您应用了哈希算法两次!在你的MyITSAClient你有的课

public byte[] GetTimeStampToken(byte[] imprint)
{
    string hashedImprint = Sha256_hash(imprint);
    // hashedImprint sent to signing service

    return Convert.FromBase64String("Base64 encoded DER representation of TimeStampToken received from signing service");
}

The imprint你的参数GetTimeStampToken实现已经经过哈希处理,因此您必须对这些字节进行十六进制编码并发送它们以进行时间戳处理。但你应用你的方法Sha256_hash首先对这个新的哈希值进行哈希处理,然后进行十六进制编码。

因此,而不是应用Sha256_hash仅十六进制编码imprint!

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

itextsharp 使用签名哈希签名 pdf 的相关文章

  • 使用 ImageMagick 和/或 GhostScript 将多页 PDF 转换为多个 JPG

    我正在尝试将多页 PDF 文件转换为一堆 JPEG PDF 中的每一页一个 我花了几个小时寻找如何做到这一点 最终我发现我需要安装 Ghostscript 所以我就这么做了 来自这个网站 http downloads ghostscript
  • 为什么即使我的哈希码值相同,“==”也会返回 false

    我写了一个像这样的课程 public class HashCodeImpl public int hashCode return 1 public static void main String args TODO Auto generat
  • 使用 PHP 创建图表并导出为 PDF

    我正在寻找有关使用 PHP 创建图表的建议 我还希望能够将这些图表导出到 PDF 文档 我目前正在使用谷歌图表 但我不喜欢将我的所有信息发送到谷歌的想法 我更喜欢自己的托管解决方案 我见过很多 Flash 解决方案 但我不知道有什么方法可以
  • 在 Perl 中使用数据引用的正确方法

    我有一组想要处理的数据 为了简化我的代码 最好通过指向原始数据的引用数组来访问我的数据的某些子集 比解释更好的是 我写下了这个例子 它还没有工作 最后 我想更新原始数据 而不必更新所有子集 用 Perl 可以做这样的事情吗 usr bin
  • 获取express.js中间件请求中“#”后的url

    我需要获取服务器中间件上的 url 使用express js 我用req url但是当 url 开头时 some urlreq url 返回 与req path 有没有办法获取url之后 在express js中 No URL 中以 符号永
  • 将文本叠加在图像背景上并转换为 PDF

    使用 NET 我想以编程方式创建一个 PDF 它仅包含一个背景图像 其上有两个具有不同字体和位置的标签 我已阅读过有关现有 PDF 库的信息 但不知道 如果适用 哪一个对于如此简单的任务来说最简单 有人愿意指导我吗 P D 我不想使用生成的
  • 在 Flutter 中显示 iOS 的 PDF 内联文件

    我正在 flutter 中专门为 iOS 开发一个应用程序 现阶段 我需要向其中添加 PDF 文件 问题是 flutter 没有原生的方式来显示 PDF 文件 据我研究 由此tread https github com flutter fl
  • 哈希上的多次迭代:这不会减少熵吗?

    我看到在很多地方 包括堆栈 都推荐了这种技术 而且我无法摆脱这种技术会减少熵 毕竟 您正在再次对已经被散列过并且有碰撞机会的东西进行散列 碰撞机会大于碰撞机会会不会导致更多的碰撞机会 经过研究 似乎我错了 但为什么呢 既然您标记了 md5
  • jasper 报告 pdf 导出中忽略半透明(半透明)背景色

    问 为什么保存为 PDF 时 Alpha 信息会丢失 Jaspersoft studio 不允许我用 Alpha 指定颜色 因此 我尝试聪明地在着色元素上指定键 并更改代码中的颜色 如下所示 JasperReport jasperRepor
  • 在chrome中将pdf渲染为iframe

    我正在尝试将 pdf 托管在隐藏的 iframe 中 但在 Chrome 中呈现较小的问题时遇到问题 我必须刷新页面才能正确加载 JSfiddle 在这里https jsfiddle net 464xo40f https jsfiddle
  • 在 JSPdf 中嵌入二进制文件

    我在用着JsPDF https www npmjs com package jspdf将 html 内容导出到下载的 PDF 考虑以下示例 该示例获取一些 HTML 内容并将其输出到下载的 PDF 文件 使用JsPdf import Rea
  • PDF 附件 NodeMailer

    预先感谢您的回复 我编写了一些使用nodemailer 0 7 1的代码 它发送电子邮件并将pdf附加到电子邮件中 但是 pdf 附件在编码时会自行损坏或截断或发生其他情况 我之所以说这是附件之前的文件 即我本地的文件 是512kb 而电子
  • Swift UIImage 转换为 PDF

    在我的应用程序中 必须从 iPad Gallery 出售 UIImage 并将其转换为 PDF 并保存在服务器端 我可以选择图像并将其发送到服务器端 但后端说 pdf 为空 空数据 我还在控制台中看到警告 错误 发现扩展时遇到 发现 错误
  • 将jsp表导出到excel、word、pdf

    任何人都可以建议我任何库 jar 文件 我可以使用它们将我的表导出到 excel pdf word 请告诉我是否有任何可以在 jsp 中创建报告的库 还应该提到的是 您只需输出 HTML 表格并将响应类型设置为即可将表格导出到 Excela
  • 如何执行 ImageMagick 仅将多页 PDF 的第一页转换为 JPEG?

    我如何执行 ImageMagick 的convert如果我想要 JPEG仅从第一页开始多页 PDF 如果您使用的是convert命令行您可以使用以下参数执行它 convert source pdf 0 output jpeg 请注意 Ima
  • c# AudioFingerprinting 和局部敏感哈希

    我之前发现过类似的帖子 但没有真正回答这个问题 在我的指纹识别中 我生成了一个包含 5 个整数的记录集 例如 33 42 88 121 194 这些对应于特定音乐样本的最高幅度的频率 例如 对于 30ms 的音频样本 我有以下频率的桶 0
  • 设置 8 1/2" x 12" itext 页面尺寸 [重复]

    这个问题在这里已经有答案了 我正在使用 itext PDF 我需要将 PDF 文档大小设置为德国标准 Fanfold 8 1 2 x 12 我不知道如何在 Itext 文档中设置英寸 Now I can set paper size as
  • 从 php/linux 获取 pdf 的布局模式(横向或纵向)

    给定一个 PDF 如何使用 PHP lib 或 Linux 命令行工具获取 PDF 的布局模式 或相对宽度 高度 Using http www tecnick com public code cp dpage php aiocp dp tc
  • FileReader 读取 PDF 时丢失数据

    我的限制是只能以 JSON 格式将数据发送到服务器 并且我需要将 PDF 文件与 JSON 中的其他表单数据一起发送 我虽然可以用 base64 从中创建一个字符串 如下所示这个解决方案 https stackoverflow com a
  • md5 哈希冲突。

    如果从 1 数到 X 其中 X 是第一个与前一个数字发生 md5 冲突的数字 那么 X 是哪个数字 我想知道如果我使用 md5 作为序列号 在发生冲突之前我可以期望能够枚举多少个单元 Theoretically you can expect

随机推荐

  • .NET DDD 示例 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 您使用哪些 Python 重构工具? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我有很多类想要重命名 其中一些名称很小 并且该名称在其他类名称中重复使用 我不希望更改该名称 其中大部分
  • GitHub Action:如何在 docker 容器内运行命令

    今天刚开始学习CI CD 今天不知道 docker 之前是什么 我能够通过我的 Unity 项目在 CircleCI 上运行 CD 所有运行命令都发生在 docker 容器内 version 2 1 executors unity dock
  • 修复 HTML 视频元素的黑色矩形

    我正在实施 WebRTC 视频聊天 我想实现以下案例 默认情况下 视频元素通过 CSS 具有背景图像 如果没有视频输入 则用户会看到他 或对话者 的头像 No video expected result No video actual re
  • 如何设置 Angular Timepicker 的最短时间和最长时间?

    有没有办法为 Angular 的引导时间选择器设置最短时间和最长时间 使用 Angular 的 Datepicker 设置支持最小和最大日期 我想知道 Timepicker 是否允许类似的功能 查看中的设置Timepicker 的 Angu
  • 如何在 EF Code First 中创建/更新 LastModified 字段

    我想添加一个列 用于在将记录保存到磁盘时存储当前的日期时间 实现这一目标的最佳方法是什么 我知道这不是一个非常复杂的问题 但我想知道 EF 是否有任何最佳实践或任何功能可以简化任务 例如 有没有什么方法可以将该字段的逻辑包含在表类中 以便在
  • Java EE DAO / DTO(数据传输对象)设计模式

    目前 我正在为我的工作项目使用 struts2 框架 在设计我的 DAO 类时 我心中有一个改进设计模式的问题 在我的搜索功能上 我有3种搜索 使用一个参数和另一个参数进行搜索 使用多个参数进行搜索 不带参数搜索 我的问题是 做DAO方法最
  • 如何查询 Sphinx 精确匹配的短语?

    Sphinx 似乎正在逐字搜索文档 我不知道如何在文档中搜索确切的短语 我试过SPH MATCH ALL SPH MATCH PHRASE但所有人都逐字搜索文档 我在我的 PHP 应用程序中使用它 如何查询 Sphinx 以匹配精确的字符串
  • 如何制作“空”RSS 提要

    我对 RSS 提要不太熟悉 但我可以使用 PHP 动态创建提要 而且效果很好 我的问题是 有时提要没有任何项目 我将提要项目的期限限制为 60 天 有时在这段时间内什么也没有发生 我期望发生的是我根本不会有任何
  • 如何在同一台服务器上托管两个公开端口 80 的 Docker 容器

    我有 2 个网站 客户端需要在端口 80 上连接到 每个网站都在自己的容器中运行 我想在同一台 Docker 主机上运行这两个容器 据我所知 80端口只能在主机上暴露一次 存在哪些具有最小开销 管理的解决方案 允许我在同一主机上简单地运行两
  • 从实体框架类获取默认sql值

    我使用的是 T4 模板 对中提出的模板稍加修改this https stackoverflow com a 15936878 1641172答案是从我的 EF POCO 生成打字稿接口 EF Core POCO 首先生成数据库 并且某些数据
  • React TestUtils,如何模拟文档mouseMove?

    我想用TestUtils Simulate mouseMove on the document 我有一个组件Dragger这增加了一个mouseMove事件侦听器document 这是一个不完整的版本 Dragger js use stri
  • 从 readr::read_csv 中读取的数据中删除属性

    readr read csv添加编辑数据时不会更新的属性 例如 library tidyverse df lt read csv A B C na 1 x nb 1 y nc 1 z Remove columns with only one
  • LiveCharts WPF 中单独着色的数据点

    我正在使用 Live Charts WPF 来绘制一些图表 为了使每个栏具有不同的颜色 我添加了多个系列 但它没有显示x axis所有系列的标签 为什么 senderChart Series new SeriesCollection int
  • 如何在 Java 中将布尔数组转换为二进制数组,反之亦然?

    在 Java 中将布尔数组输出到文件 以及从文件输入 的最有效方法是什么 我打算使用一个字符串 每个字符要么是 t 要么是 f 然后我想 为什么不减少八倍的空间呢 NOTE 我实际上不知道哪个答案是更好的方法 我只是选择了彼得的 因为我理解
  • 使用 Clips 专家系统中的 Python 函数

    使用 PyClips 我尝试在 Clips 中构建规则 从 Python 解释器动态检索数据 为此 我注册了一个外部函数 如下所示手册 http pyclips sourceforge net manual pyclips overview
  • 在 Razor 视图中渲染 Telerik MVC Grid 时出现问题

    我在 内容 页面中有以下标记 如果没有 Render 调用 则不会呈现任何内容 而使用 Render 调用时 网格将呈现为整个页面中的第一个元素 而不是在我的视图定义的 内容 部分内 using Telerik Web Mvc UI mod
  • 从 BroadcastReceiver 调用活动方法。是否可以?

    我陷入了开发应用程序的困境 因为我需要在触发 BroadcastReceiver 时调用我的活动的方法 我希望 BroadcastReceiver 能够检测到网络连接何时断开并调用我已经编写的活动方法 我一直在搜索 发现以前有更多人问过这个
  • Android 作为 SIP 转 GSM 网关

    很快我就可以使用 SIP 转 GSM 网关 因为我需要从德国向捷克共和国的手机拨打电话 因此 我考虑实施一个 现在 问题是 这样的解决方案是否已经存在 价格合理 是否可以使用可用的 Android API SDK 或 NDK 将 语音 流重
  • itextsharp 使用签名哈希签名 pdf

    我正在尝试通过签名服务签署 pdf 此服务需要发送十六进制编码的 SHA256 摘要 作为回报 我收到十六进制编码的签名值 除此之外 我还收到签名证书 中间证书 OCSP 响应和 TimeStampToken 但是 我已经在尝试使用签名值对