2017-10-10 243 views
0

我創建了一個證書使用keytool:簽名與密鑰庫的Java

keytool -genkeypair -alias sara -keyalg RSA -keysize 2048 -keypass 
password -keystore "\Sviluppo\JavaKeyStore\keystore.jks" -storepass 
12345678 -validity 360 -dname "cn=Sara, ou=***, o=***, l=Padova, 
s=Italia, c=IT" 

然後我想簽署此證書的PDF版本,我使用Itextpdf簽署一份PDF格式。 首先,我加載私鑰和證書密鑰庫從:

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 
File fileKeyStore = new File(pathKeyStore); 
FileInputStream fis = new FileInputStream(fileKeyStore); 
keyStore.load(fis, "12345678".toCharArray()); 
final PrivateKey privateKey = (PrivateKey) keyStore.getKey("sara", "password".toCharArray()); 
final Certificate certificate = keyStore.getCertificate(certID); 

然後我打開文件的哈希計算簽名:

PdfReader reader = new PdfReader(new RandomAccessFileOrArray(pdfInputPath), null); 
OutputStream pdfOutputStream = new FileOutputStream(pdfOutputPath); 

PdfStamper stp = PdfStamper.createSignature(reader, pdfOutputStream, '\0', tempPathFile, true) 
PdfSignatureAppearance sap = stp.getSignatureAppearance(); 
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED); 
dic.setDate(dateNow); 
sap.setCryptoDictionary(dic); 
sap.setCrypto(privateKey, keyStore.getCertificateChain("sara"), null, PdfSignatureAppearance.SELF_SIGNED); 

HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>(); 
exc.put(PdfName.CONTENTS, (int) (6144 * 2 + 2)); 
sap.preClose(exc); 

然後計算sap.getRangeStream(),從密鑰庫加載證書的哈希值:

BufferedInputStream bis = new BufferedInputStream(sap.getRangeStream()); 
MessageDigest digest = MessageDigest.getInstance("SHA-256"); 
DigestInputStream dis = new DigestInputStream(bis, digest); 
byte[] buff = new byte[512]; 
while (dis.read(buff) != -1) { 
    ; 
} 
dis.close(); 
dis = null; 
byte[] hashToSign= digest.digest(); 
bis.close(); 

我從證書密鑰庫登錄:

java.security.Signature signature = Signature.getInstance("SHA256withRSA"); 
signature.initSign(privateKey); 
signature.update(hashToSign); 
byte[] hashSigned = signature.sign(); 

末關閉PDF:

byte[] paddedSig = new byte[6144]; 
System.arraycopy(hashSigned, 0, paddedSig, 0, hashSigned.length); 
PdfDictionary pdfDictionary = new PdfDictionary(); 
pdfDictionary.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true)); 
sap.close(pdfDictionary); 

但簽署的PDF是無效的:「有包含在此簽名的格式或信息錯誤

有什麼問題,證書或簽名? 感謝您的幫助 薩拉

+0

爲什麼直接構建哈希以簽名和嵌入數字簽名而不是使用itext支持?有很多可能的失敗點。例如,你不包括認證鏈到pdf – pedrofb

+0

如果我打電話給一個外部服務器(例如阿魯巴CA),我只發送散列,簽署pdf的代碼工作正常。但是,如果我使用keytool生成證書,pdf是不正確的。我還添加了證書鏈: sap.setCrypto((PrivateKey)keyStore.getKey(「sara」,「password」.toCharArray()),keyStore.getCertificate(「sara」)。getCertificateChain(),null,PdfSignatureAppearance.SELF_SIGNED ); 但存在同樣的問題。 – Sara

+0

不要在評論中包含代碼,它很難閱讀。只需編輯你自己的問題。你應該包括所有相關的代碼,包括你如何計算'hashToSign'。但是,如果您的代碼與外部CA一起使用,而不是使用自簽名證書,那麼問題可能就在那裏。檢查您的證書是否正確生成 – pedrofb

回答

0

的事業「有包含在該簽名的格式或信息錯誤,」驗證失敗消息是你的代碼放在一個裸體PKCS1簽名值,其中一個成熟的CMS簽名容器預計:

你,一方面利用SELF_SIGNEDsap.setCrypto這表明你想創建一個adbe.x509.rsa_sha1輔助過濾簽名,而在另一方面,子過濾設置爲adbe.pkcs7.detached在您的PdfSignature構造函數中。

這不符合所有,adbe.x509.rsa_sha1使用裸PKCS1簽名值,而adbe.pkcs7.detached使用CMS簽名的容器。

這應該回答你的問題「有什麼問題,certificare或簽名?」 ......


根據你同時發現在行動一iText的副本,第2版解決方案的註釋。

請注意,雖然iText簽名API已經大幅擴展。如果您正在使用iText 5.5.x,則應該下載並閱讀由Bruno Lowagie(iText Software)撰寫的白皮書Digital Signatures for PDF Documents。2008年(SOTA在其發佈而不是的時間了),數字簽名的PDF文檔重點:

雖然從的iText在行動代碼,第二版,根據ISO 32000-1仍集中在簽名根據PAdES簽名,同時也包含在ISO 32000-2:2017中。