【问题标题】:Extract images of signatures contained in a pdf file with iTextSharp library使用 iTextSharp 库提取 pdf 文件中包含的签名图像
【发布时间】:2013-06-26 11:13:47
【问题描述】:

我有一个签名的 PDF 文件。通过这个使用 iTextSharp 库的函数,我找到了证书 p7m 签名:

        private void GetSignature(string FileName)
    {
        AcroFields acroFields = new PdfReader(FileName).AcroFields;
        List<string> names = acroFields.GetSignatureNames();

        foreach (var name in names)
        {
            PdfDictionary dict = acroFields.GetSignatureDictionary(name);
            PdfString contents = (PdfString)PdfReader.GetPdfObject(dict.Get(PdfName.CONTENTS));

            byte[] PKCS7 = contents.GetOriginalBytes();
            ByteArrayToFile(@"c:\signature\" + name + ".p7m", PKCS7);

        }
    }

现在...如何提取与签名关联的图像(位图)?可能吗? 谢谢,路易吉

【问题讨论】:

  • 如果你确定它只是一张位图,提取它并不太难。但在野外,非位图图形和文本通常也是可视化的一部分。那将要求将 PDF 部分渲染为图像,而这尚未在 itext 中实现。
  • 这不是一个简单的图像...否则我会提取的。基本上,签名由证书、图片和生物特征数据包(速度、压力和加速度)组成。
  • 请提供示例文件。数字签名中不需要生物特征数据,因为这里的身份验证使用证书和非对称加密。
  • 啊,用 xyzmo 软件创建的签名...他们过去使用完全自己的 PDF 对象进行签名。从您提供的样本来看,他们现在至少已经开始使用标准签名作为其签名技术的基础。它们仍然在 /Sig 字典中引用为 /xyzmo_signature 的添加对象中包含自己的信息。我认为您将不得不询问 xyzmo 人员如何解释他们添加到签名中的自定义数据,特别是因为它的大部分内容都在 XML EncryptedSignatureDataContainer 片段中......

标签: c# pdf itextsharp digital-signature


【解决方案1】:

在您的示例文档中,签名一词适用于三个方面:

  1. 它包含符合 PDF 规范ISO 32000-1:2008 的数字签名。
  2. 相应的可视化包含手写签名的位图图像。
  3. 各自的签名字典包含软件的专有信息,该软件将所有签名数据添加到 PDF。这些专有信息很可能包含 OP 的 cmets 中提到的生物特征数据。

根据创建这些多级签名的软件制造商的说法,手写签名似乎是主要的身份证明。数字版仅用于保护文档免受更改;它确实不一定反映了手动签名的人的身份,而不是创建该手动签名的设备的所有者(“请在此处签名以表明您收到了包裹”):

函数

手写签名捕获 - 签名板、支付终端、iPad 或 Android 设备上的法医可识别签名。

签名验证 - 将手写签名与预先注册的个人资料进行比较。

控制签名过程中的所有步骤 - 包括定位签名字段、填写表格、添加注释、添加附件等等。

保护文档的完整性 - 用数字签名密封它们。

(xyzmo English website start page)

关于使用 iText 提取所有这些信息...

  1. 使用AcroFields 类的签名相关方法,OP 已经观察到,可以轻松提取和验证数字签名的属性。
  2. 手写签名的位图图像也可以相当容易地提取出来。签名表单字段字典的外观流仅将附加到流的位图绘制为资源。
  3. 也可以提取包含专有信息的数据容器,因为它只是签名字典中另一个键的值。
  4. 不幸的是,该数据容器的 内容 被打包到一个自称为 EncryptedSignatureDataContainer 的 XML 片段中。此 XML 片段的有效负载数据是否可以正确解密以及如何解释它是向 xyzmo 人自己请求的信息,我不知道他们是否认为该信息是公开的。

因此,最相关的信息是最难获得的。

PS关于加密生物特征载荷的解密,我在制造商的网站上找到了以下内容:

文档包含已捕获的签名,该签名已加密 (RSA 4096 + AES256)。一个人的签名在被签名板捕获时会立即使用特殊证书的私钥进行加密。该特殊证书由公司使用 xyzmo 套件选择,通常存储在公司外部的安全环境中(银行保险箱、外部公证人等)。因此,xyzmo 本身无权访问此证书。对于签名的加密,xyzmo 套件只需要证书的公钥。只有在解密和从文档中提取签名时,才需要私钥。只有公司授予此证书访问权限的特定人员才能使用作为套件一部分提供的 PenAnalyst 工具解密配置文件。

(xyzmo English website Digital Signature Capture FAQ's)

因此,要解密生物特征数据,您必须有权访问相应的私钥,该私钥通常存储在公司外部的安全环境中(银行保险箱、外部公证人等)。 如果你有那种访问权限,我们可能会继续讨论那些解密数据的格式...... ;)

顺便说一句,如果任何人都可以简单地从签名文档中检索生物特征数据,那么它们很容易被复制到其他文档中以伪造签名。

提取手写签名的位图图像

由于对提取手写签名的位图图像特别感兴趣,这里有一个快速而肮脏的助手来提取签名的图像。正如已经说过的,我在 Java 中做这件事,因为我在那里更自在:

public class XyzmoSignatureDataExtractor
{
    public XyzmoSignatureDataExtractor(PdfReader reader)
    {
        this.reader = reader;
    }

    public PdfImageObject extractImage(String signatureName) throws IOException
    {
        MyImageRenderListener listener = new MyImageRenderListener();

        PdfDictionary sigFieldDic = reader.getAcroFields().getFieldItem(signatureName).getMerged(0);
        PdfDictionary appearancesDic = sigFieldDic.getAsDict(PdfName.AP);
        PdfStream normalAppearance = appearancesDic.getAsStream(PdfName.N);

        PdfDictionary resourcesDic = normalAppearance.getAsDict(PdfName.RESOURCES);
    
        PdfContentStreamProcessor processor = new PdfContentStreamProcessor(listener);
        processor.processContent(ContentByteUtils.getContentBytesFromContentObject(normalAppearance), resourcesDic);        

        return listener.image;
    }

    class MyImageRenderListener implements RenderListener
    {
        public void beginTextBlock() { }

        public void endTextBlock() { }

        public void renderImage(ImageRenderInfo renderInfo)
        {
            try
            {
                image = renderInfo.getImage();
            }
            catch (IOException e)
            {
                throw new RuntimeException("Failure retrieving image", e);
            }
        }

        public void renderText(TextRenderInfo renderInfo) { }

        PdfImageObject image = null;
    }

    final PdfReader reader;
}

你可以这样使用它:

PdfReader reader = new PdfReader(resourceStream);
XyzmoSignatureDataExtractor extractor = new XyzmoSignatureDataExtractor(reader);
AcroFields acroFields = reader.getAcroFields();

for (String name: acroFields.getSignatureNames())
{
    System.out.printf("\nTesting signature '%s'.\n", name);
    PdfImageObject image = extractor.extractImage(name);

    OutputStream os = new FileOutputStream("target/test-outputs/SampleXyzmoSignature-image-" + name + "." + image.getFileType());
    os.write(image.getImageAsBytes());
    os.close();

    PdfDictionary imageDictionary = image.getDictionary();
    PRStream maskStream = (PRStream) imageDictionary.getAsStream(PdfName.SMASK);
    if (maskStream != null)
    {
        PdfImageObject maskImage = new PdfImageObject(maskStream);

        os = new FileOutputStream("target/test-outputs/SampleXyzmoSignature-image-" + name + "-mask." + maskImage.getFileType());
        os.write(maskImage.getImageAsBytes());
        os.close();
    }
}

警告: XyzmoSignatureDataExtractor 类确实是一个快速而肮脏的 hack。做了很多假设,null-checks 被忽略了,...

【讨论】:

  • 非常感谢您的回答。参考第2点,当您谈到:“手写签名的位图图像也可以相当容易地提取。”您能否提供提取单打签名位图的代码。我尝试使用classExtractImages(filename) 方法从pdf 中提取图像,但它不起作用。谢谢。
  • 您的PdfImageExtractor 提取页面内容流中包含或引用的图像。但是,手头的签名图像是从签名注释的正常外观流中引用的。我在答案中添加了一些快速而肮脏的 Java 代码,以展示如何提取此类图像。
  • 非常感谢...它运行良好!你的建议非常有用。一切顺利。
  • 如果您对.Net/iTextSharp 版本感兴趣,@user3492925 将代码移植到this answer
猜你喜欢
  • 1970-01-01
  • 2011-08-22
  • 2019-08-07
  • 1970-01-01
  • 2019-10-10
  • 2013-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多