- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
Client=我的应用,Server=MSSP(手机签名服务提供商)
服务器仅对散列值进行签名。
要签名的数据:
*要签名的数据的 Base64 编码 SHA-1 摘要。 (28 个字符)
*要签名的数据的 Base64 编码 SHA-256 摘要。 (44 个字符)
*要签名的数据的 Base64 编码 SHA-384 摘要。 (64 个字符)
*要签名的数据的 Base64 编码 SHA-512 摘要。 (88 个字符)
*Base64 编码 DER 编码 PKCS#1 DigestInfo 进行签名。
我想要 pdf 的外部签名。我写了下面的代码。但是用 adobe 打开文档时出现错误。
错误:
文档签名后被修改或损坏
注意:我使用的是MSSP(Mobile Signature Service Provider)架构。对于 SHA256 算法,DataToBeSigned.length 应为 44。
我的操作代码:
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfDate;
import com.itextpdf.text.pdf.PdfDictionary;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignature;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfString;
import com.itextpdf.text.pdf.security.DigestAlgorithms;
import com.itextpdf.text.pdf.security.ExternalDigest;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
import com.itextpdf.text.pdf.security.PdfPKCS7;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.HashMap;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
*
* @author murat.demir
*/
public class PdfSignOperation {
private byte[] content = null;
private X509Certificate x509Certificate;
private PdfReader reader = null;
private ByteArrayOutputStream baos = null;
private PdfStamper stamper = null;
private PdfSignatureAppearance sap = null;
private PdfSignature dic = null;
private HashMap<PdfName, Integer> exc = null;
private ExternalDigest externalDigest = null;
private PdfPKCS7 sgn = null;
private InputStream data = null;
private byte hash[] = null;
private Calendar cal = null;
private byte[] sh = null;
private byte[] encodedSig = null;
private byte[] paddedSig = null;
private PdfDictionary dic2 = null;
private X509Certificate[] chain = null;
static {
Security.addProvider(new BouncyCastleProvider());
}
public PdfSignOperation(byte[] content, X509Certificate cert) {
this.content = content;
this.x509Certificate = cert;
}
public byte[] getHash() throws Exception {
reader = new PdfReader(new ByteArrayInputStream(content));
baos = new ByteArrayOutputStream();
stamper = PdfStamper.createSignature(reader, baos, '\0');
sap = stamper.getSignatureAppearance();
sap.setReason("Test");
sap.setLocation("On a server!");
sap.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
sap.setCertificate(x509Certificate);
dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
dic.setReason(sap.getReason());
dic.setLocation(sap.getLocation());
dic.setContact(sap.getContact());
dic.setDate(new PdfDate(sap.getSignDate()));
sap.setCryptoDictionary(dic);
exc = new HashMap<PdfName, Integer>();
exc.put(PdfName.CONTENTS, new Integer(8192 * 2 + 2));
sap.preClose(exc);
externalDigest = new ExternalDigest() {
@Override
public MessageDigest getMessageDigest(String hashAlgorithm)
throws GeneralSecurityException {
return DigestAlgorithms.getMessageDigest(hashAlgorithm, null);
}
};
chain = new X509Certificate[1];
chain[0] = x509Certificate;
sgn = new PdfPKCS7(null, chain, "SHA256", null, externalDigest, false);
data = sap.getRangeStream();
cal = Calendar.getInstance();
hash = DigestAlgorithms.digest(data, externalDigest.getMessageDigest("SHA256"));
sh = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
sh = DigestAlgorithms.digest(new ByteArrayInputStream(sh), externalDigest.getMessageDigest("SHA256"));
return sh;
}
public String complateToSignature(byte[] signedHash) throws Exception {
sgn.setExternalDigest(signedHash, null, "RSA");
encodedSig = sgn.getEncodedPKCS7(hash, cal, null, null, null, CryptoStandard.CMS);
paddedSig = new byte[8192];
System.arraycopy(encodedSig, 0, paddedSig, 0, encodedSig.length);
dic2 = new PdfDictionary();
dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
sap.close(dic2);
return Base64.encodeBytes(baos.toByteArray());
}
}
我的测试代码:
public static void main(String[] args) throws Exception {
TokenService.refreshAllTokens();
String alias = "alias";
String pin = "1234";
TokenService.setAliasPin(alias, pin);
File pdf = new File("E:/sample.pdf");
FileInputStream is = new FileInputStream(pdf);
byte[] content = new byte[is.available()];
is.read(content);
X509Certificate certificate = null;
for (CertInfo certInfo : TokenService.getCertificates().values()) {
if (certInfo.cert != null) {
certificate = certInfo.cert;
}
}
PdfSignOperation operation = new PdfSignOperation(content, certificate);
byte[] hash = operation.getHash();
//simule control for mobile signature.
String encodeData = Base64.encodeBytes(hash);
if (encodeData.length() != 44) {
throw new Exception("Sign to data must be 44 characters");
}
// This function is local in the test run function (Simulated MSSP mobile signature)
// return a signed message digest
byte[] signedData = TokenService.sign(encodeData, alias);
//Combine signed hash value with pdf.
System.out.println(operation.complateToSignature(signedData));
}
更新:
我尝试使用旧库版本并成功进行签名操作。我的新代码:
InputStream data = sap.getRangeStream();
X509Certificate[] chain = new X509Certificate[1];
chain[0] = userCert;
PdfPKCS7 sgn = new PdfPKCS7(null, chain, null, algorithm, null, false);
MessageDigest digest = MessageDigest.getInstance("SHA256", "BC");
byte[] buf = new byte[8192];
int n;
while ((n = data.read(buf, 0, buf.length)) > 0) {
digest.update(buf, 0, n);
}
byte hash[] = digest.digest();
logger.info("PDF hash created");
Calendar cal = Calendar.getInstance();
byte[] ocsp = null;
byte sh[] = sgn.getAuthenticatedAttributeBytes(hash, cal, ocsp);
sh = MessageDigest.getInstance("SHA256", "BC").digest(sh);
final String encode = Utils.base64Encode(sh);
SignatureService service = new SignatureService();
logger.info("PDF hash sended to sign for web service");
MobileSignResponse signResponse = service.mobileSign(mobilePhone, signText, encode, timeout, algorithm, username, password, "profile2#sha256", signWsdl);
if (!signResponse.getStatusCode().equals("0")) {
throw new Exception("Signing fails.\n" + signResponse.getStatusMessage());
}
byte[] signedHashValue = Utils.base64Decode(signResponse.getSignature());
sgn.setExternalDigest(signedHashValue, null, "RSA");
byte[] paddedSig = new byte[csize];
byte[] encodedSig = sgn.getEncodedPKCS7(hash, cal, null, ocsp);
System.arraycopy(encodedSig, 0, paddedSig, 0, encodedSig.length);
if (csize + 2 < encodedSig.length) {
throw new Exception("Not enough space for signature");
}
PdfDictionary dic2 = new PdfDictionary();
dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
sap.close(dic2);
logger.info("Signing successful");
最佳答案
在 getHash
中构建已签名的 PDF(只有实际签名区域填充了 '00' 而不是签名字节),计算字节范围的哈希值并返回此哈希值。
在您的 main
中,您按原样对返回的散列进行签名。
然后在 complateToSignature
中将其插入到准备好的 PdfPKCS7
结构中。
但是这是不正确的:在 PKCS7/CMS 签名中签名的散列不是文档的散列(除非你有最原始形式的 PKCS7 容器)而是签名的散列属性(文档的散列只是这些属性之一的值),也称为经过身份验证的属性。
因此,您必须使用您计算的文档哈希生成签名属性,然后(哈希和)签署此结构。
看看 iText 的 MakeSignature.signDetached
并并行计算:
String hashAlgorithm = externalSignature.getHashAlgorithm();
PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, null, externalDigest, false);
InputStream data = sap.getRangeStream();
byte hash[] = DigestAlgorithms.digest(data, externalDigest.getMessageDigest(hashAlgorithm));
Calendar cal = Calendar.getInstance();
byte[] ocsp = null;
if (chain.length >= 2 && ocspClient != null) {
ocsp = ocspClient.getEncoded((X509Certificate) chain[0], (X509Certificate) chain[1], null);
}
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, cal, ocsp, crlBytes, sigtype);
byte[] extSignature = externalSignature.sign(sh);
sgn.setExternalDigest(extSignature, null, externalSignature.getEncryptionAlgorithm());
PS:尝试将该代码转移到您的用例时,请注意使用的 ExternalSignature
方法 sign
之间的主要区别这里和你的 TokenService
方法 sign
:
ExternalSignature.sign
记录为:
/**
* Signs it using the encryption algorithm in combination with
* the digest algorithm.
* @param message the message you want to be hashed and signed
* @return a signed message digest
* @throws GeneralSecurityException
*/
public byte[] sign(byte[] message) throws GeneralSecurityException;
所以这个方法同时进行哈希和签名。
但是,对于您的方法 TokenService.sign
,如果您
use the sha256 algorithm, sign to data must be 44 characters
因此您转发给该方法的数据似乎必须已经过哈希处理(base64 编码的 SHA-256 哈希值需要 44 个字符)。
因此,您必须计算 sh
的散列并将此散列转发给 TokenService.sign
而不是原始签名属性。
关于java - PDF 外部签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23384348/
我得到了这个printHashKey函数,它运行良好。 fun printHashKey() { try { val info : PackageInfo = packageM
如何使用正确的签名 key 为我的 Android 应用包签名? 最佳答案 我尝试在此处和 this question 中使用多个答案, 但不知何故我收到了这个错误,因为我的 android/app/
我的 gradle 文件中有这个: android { signingConfigs { mySigningConfig { keyAlias 'the
请至少选择一个签名版本以在 Android Studio 2.3 中使用 现在在 Android Studio 中生成一个签名的 APK 时,它显示了两个选项(复选框),即 1. V1(Jar 签名)
我想表示一些标量值(例如整数或字符串)通过它的实际值或一些 NA 值,然后存储它们在集合中(例如列表)。目的是处理缺失值。 为此,我实现了一个签名 module type Scalar = sig
为什么这不完全有效? sum :: (Num a, Num b) => a -> b -> c sum a b = a + b 当然,错误消息与签名有关,但我仍然不明白原因。 Couldn't mat
谢谢帮助,我的问题是关于从下面的代码中收到的 ax 值? mov al,22h mov cl,0fdh imul cl 真机结果:ff9a 我的预期:00:9a(通过二进制相乘) 第一个数字是 22h
我有一个注释: import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.
我从对物体的思考中得出了一个术语。当我们扩展一个类时,扩展类将具有与父类相同的签名,因此术语 IS-A 来自...示例 class Foo{ } class Foo2 extends Foo{ } c
我需要在有符号整数和它们作为字节序列的内部表示之间进行转换。在 C 中,我使用的函数如下: unsigned char hibyte(unsigned short i) {return i>>8;}
我正在尝试使用给定的 RSA 参数对一些数据进行签名。 我给出了模数、指数、D、DP、DQ、P、Q 和 InverseQ。什么库或方法最容易使用来计算此签名。在 C# 中,一旦您提供参数,它们就会有一
这些签名之间有什么区别? T * f(T & identifier); T & f(T & identifier); T f(T & identifier); void f(T * identifie
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: Where and why do I have to put the “template” and “typ
我有一个签名,我需要在签名旁边添加图片。但我不确定 css 的确切程度和内容。目前它显示在文字下方,我应该把图片放在哪里?在相同的 tr 或 td 中?
查看 LinkedHashMap 的 JDK 源代码,我注意到这个类被声明为: public class LinkedHashMap extends HashMap im
背景:我继承了一个基于 linux 的嵌入式系统,其中包含一个 SMTP 代理和一些我不得不忍受的古怪限制。它位于 SMTP 客户端和服务器之间。当 SMTP 客户端连接时,代理会打开与服务器的连接,
这是 C++17 形式的规则 ([basic.lval]/8),但它在其他标准中看起来很相似(在 C++98 中是“lvalue”而不是“glvalue”): 8 If a program attem
我有一个注释: import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.
我即将开展一个项目,希望使用电子签名板使用 C# 捕获客户的签名、在设备上显示文本等。 现在,在我开始做进一步的研究之前,我想向你们征求一些意见/建议,我应该使用哪些设备.. 我现在的要求非常笼统:我
呢喃自己在心中开始扩张地盘,仿佛制式地广播了三次。 漾起的涟绮,用谈不上精腻的手段。 拒绝天亮,却又贪恋着贪恋多情的日光。 川流不息的画面是他们,而我的落幕停在右脚,它渴望着下台,而我只剩自言
我是一名优秀的程序员,十分优秀!