我有一个签名的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规范ISO 32000-1:2008的数字签名。
相应的可视化包含手写签名的位图图像。
相应的签名字典包含软件的专有信息,该软件将所有签名数据添加到PDF。这些专有信息很可能包含OP注释中提到的生物识别数据。
根据创建这些多级签名的软件制造商的说法,手写签名似乎是身份的主要证明。数字化仅用于保护文档免于更改;它不一定反映手动签名者的身份,而是反映创建手动签名的设备的所有者的身份(“请在此处签名,您会收到包裹”):
功能
手写签名捕获-签名板上,支付终端,iPad或Android设备上的可识别法医的签名。
签名验证-将手写签名与预先注册的个人资料进行比较。
控制签名过程中的所有步骤-包括放置签名字段,填写表单,添加注释,添加附件等等。
保护文档的完整性-通过使用数字签名将其密封。
(xyzmo English website start page)
关于使用iText提取所有这些信息...
使用AcroFields
类的与签名相关的方法,可以很容易地提取和验证数字签名的属性,如OP所观察到的那样。
手写签名的位图图像也可以很容易地提取出来。签名表单字段字典的外观流仅将附加到该流的位图绘制为资源。
也可以提取包含专有信息的数据容器,因为它只是签名字典中另一个密钥的值。
但是,不幸的是,该数据容器的内容被打包到一个XML片段中,该片段本身称为EncryptedSignatureDataContainer。这个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
确实是一种快速和肮脏的技巧。进行了许多假设,省略了null
-检查,...