我需要对代码从itext5到itext8进行一些更改.这是一个两步签名,创建散列和在CA API签名,然后嵌入回pdf.一切正常,使用一些参考文献here.但是,它在验证文档时返回错误.我已经使用相同的PdfPkcs7实现了,但它仍然返回错误.签名的pdf可以从here下载.请帮我解释一下已经花了几个晚上的时间了.我使用的是iText 8.0.2.
public class PDF_prepareHash {
//global variable
static Logger logger = LogManager.getLogger(PDF_prepareHash.class.getName());
static Timestamp timestamp = new Timestamp(System.currentTimeMillis());
static Instant instant = timestamp.toInstant();
static String txId=Long.toString(instant.toEpochMilli());
static String ORI="D:\\pdf"+File.separator+"files"+File.separator+txId+".pdf";
static String TEMP="D:\\pdf"+File.separator+"files"+File.separator+txId+"-TEMP.pdf";
static String DEST="D:\\pdf"+File.separator+"files"+File.separator+txId+"-SIGNED.pdf";
public static PdfPKCS7 sgn;
//variable for get sign hash
private static String signature=null;
//function for prepare hash
public static String prepareHash(String certx509,SignatureDetails sd,String name, String userId)
{
JSONObject obj = new JSONObject();
try{
BouncyCastleProvider providerBC = new BouncyCastleProvider();
Security.addProvider(providerBC);
String x509b64 = certx509;
String certString="-----BEGIN CERTIFICATE-----\n" +x509b64+"\n-----END CERTIFICATE-----";
byte[] certinByte= certString.getBytes();
X509Certificate x509 = fromByteArrayToX509Certificate(certinByte);
Certificate cert = loadCertificate(certinByte);
Certificate[] chain = new Certificate[1];
chain[0] = cert;
FileBase64Converter fileB64 = new FileBase64Converter();
fileB64.base64ToFile(sd.getPdfb64(), ORI);
PDF_prepareHash app = new PDF_prepareHash();
String json_hh = emptySignature_hash(chain, sd.getVisibility(), sd.getPage(), sd.getX1(), sd.getY1(), sd.getX2(), sd.getY2(), name, userId);
if(!json_hh.isEmpty()){
obj.put("StatusCode", "000");
obj.put("StatusMsg", "Successfully prepare hash");
obj.put("Data", json_hh);
logger.info("prepareHash: Status Code: 000");
logger.info("prepareHash: Status Msg: Successfully prepare hash");
return obj.toString();
}
}catch(GeneralSecurityException e){
logger.fatal("GeneralSecurityException");
logger.fatal("GeneralSecurityException: " + e.getMessage());
}catch(JSONException e){
logger.fatal("JSONException");
logger.fatal("JSONException: " + e.getMessage());
}
return null;
}
public static String emptySignature_hash(Certificate[] chain, Boolean visibility, Integer page, Integer x1, Integer y1, Integer x2, Integer y2,String name,String userId)
{
try {
JSONObject obj = new JSONObject();
PdfReader reader = new PdfReader(ORI);
FileOutputStream os = new FileOutputStream(TEMP);
PdfSigner signer = new PdfSigner(reader, os, new StampingProperties());
String timeStamp = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss z").format(new Timestamp(System.currentTimeMillis()));
Rectangle rect = new Rectangle(36, 748, 200, 100);
PdfSignatureAppearance sap = signer.getSignatureAppearance();
sap
.setLayer2Text("Digitally signed by\n"+name+", "+userId+"\nDate: "+timeStamp)
.setReuseAppearance(false)
.setPageRect(rect)
.setPageNumber(page)
.setCertificate(chain[0]);
signer.setFieldName("signature"); // this field already exists
BouncyCastleDigest digest = new BouncyCastleDigest();
sgn = new PdfPKCS7(null, chain, Digest算法rithms.SHA256, null, digest,false);
//IExternalSignatureContainer like BlankContainer
PreSignatureContainer external = new PreSignatureContainer(PdfName.Adobe_PPKLite,PdfName.Adbe_pkcs7_detached) {};
signer.signExternalContainer( external, 8192);
byte[] hash=external.getHash();
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash,PdfSigner.CryptoStandard.CMS, null, null);
MessageDigest messageDigest = MessageDigest.getInstance("SHA256");
messageDigest.update(sh);
byte[] hash_byte = messageDigest.digest();
obj.put("digest", Base64.getEncoder().encodeToString(hash));
obj.put("hash", Base64.getEncoder().encodeToString(hash_byte));
os.close();
reader.close();
return obj.toString();
} catch (IOException ex) {
logger.fatal("IOException");
logger.fatal("IOException: " + ex.getMessage());
} catch (InvalidKeyException ex) {
logger.fatal("InvalidKeyException");
logger.fatal("InvalidKeyException: " + ex.getMessage());
} catch (NoSuchProviderException ex) {
logger.fatal("NoSuchProviderException");
logger.fatal("NoSuchProviderException: " + ex.getMessage());
} catch (NoSuch算法rithmException ex) {
logger.fatal("NoSuch算法rithmException");
logger.fatal("NoSuch算法rithmException: " + ex.getMessage());
} catch (GeneralSecurityException ex) {
logger.fatal("GeneralSecurityException");
logger.fatal("GeneralSecurityException: " + ex.getMessage());
}
return null;
}
//function for get sign hash
public static String serveSigning(String userId, String hash,String digest,String x509b64)
{
JSONObject obj = new JSONObject();
Scanner myObj = new Scanner(System.in); // Create a Scanner object
System.out.println("Enter signature");
String casignature = myObj.nextLine(); // Read user input
signature=casignature;
byte[] extSignature = Base64.getDecoder().decode(signature);
Certificate[] chain = null;
try {
String certString="-----BEGIN CERTIFICATE-----\n" +x509b64+"\n-----END CERTIFICATE-----";
byte[] certinByte= certString.getBytes();
X509Certificate x509 = fromByteArrayToX509Certificate(certinByte);
Certificate cert = loadCertificate(certinByte);
chain = new Certificate[1];
chain[0] = cert;
} catch (CertificateException e) {
logger.fatal("IOException");
logger.fatal("IOException: " + e.getMessage());
return null;
}
//embed signature
String extSignature_b64 = Base64.getEncoder().encodeToString(extSignature);
PDF_prepareHash.createSignature(digest, extSignature_b64, chain);
obj.put("StatusCode", "000");
obj.put("StatusMsg", "Embed signature succesfully ");
logger.info("[GetSignHash] Successfully embed prepared hash");
return obj.toString();
}
//function for embed signature
public static void createSignature(String hash, String extSignature, Certificate[] chain)
{
try {
// BouncyCastleDigest digest = new BouncyCastleDigest();
// PdfPKCS7 sgn = new PdfPKCS7(null, chain, Digest算法rithms.SHA256, null, digest, false);
sgn.setExternalSignatureValue(Base64.getDecoder().decode(extSignature), null, "ECDSA");
ITSAClient tsc = null;
Security.addProvider(new BouncyCastleProvider());
String TSA_URL="http://timestamp.entrust.net/TSS/RFC3161sha2TS";
String TSA_ACCNT=null;
String TSA_PASSW=null;
try {
tsc = new TSAClientBouncyCastle(TSA_URL, TSA_ACCNT, TSA_PASSW);
} catch(Exception e) {
logger.error("Error timestamping services: "+e.toString());
}
byte[] hh_sign = sgn.getEncodedPKCS7(Base64.getDecoder().decode(hash), PdfSigner.CryptoStandard.CMS, tsc, null, null);
PdfReader reader = new PdfReader(TEMP);
FileOutputStream os = new FileOutputStream(DEST);
PdfSigner signer = new PdfSigner(reader, os, new StampingProperties());
MyExternalSignatureContainer external = new MyExternalSignatureContainer(hh_sign,chain);
PdfSigner.signDeferred(signer.getDocument(), "signature", os, external);
//close pdf files
os.close();
reader.close();
} catch(IOException ex) {
logger.fatal("IOException");
logger.fatal("IOException: " + ex.getMessage());
} catch (GeneralSecurityException ex) {
logger.fatal("GeneralSecurityException");
logger.fatal("GeneralSecurityException: " + ex.getMessage());
}
}
//global function
public static X509Certificate fromByteArrayToX509Certificate(byte[] bytes) throws CertificateException
{
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
InputStream in = new ByteArrayInputStream(bytes);
X509Certificate x509cert = (X509Certificate)certFactory.generateCertificate(in);
return x509cert;
}
public static Certificate loadCertificate(byte[] bytes) throws CertificateException
{
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream in = new ByteArrayInputStream(bytes);
Certificate c=null;
try {
c =(Certificate)cf.generateCertificate(in);
//c.checkValidity();
}
catch (CertificateException ex) {
logger.error("[PDF_prepareHash.java] Certificate loadCertificate: "+ex.getMessage());
}
finally {
try {
in.close();
} catch (IOException ex) {
logger.error("[PDF_prepareHash.java] Certificate loadCertificate: "+ex.getMessage());
}
}
try {
in.close();
} catch (IOException ex) {
logger.error("[PDF_prepareHash.java] Certificate loadCertificate: "+ex.getMessage());
}
return c;
}
}