2012-07-19 84 views
0

我試圖使用智能卡和iText對PDF進行數字簽名。我通過documentation瞭解如何使用iText簽署文檔,並嘗試自己使用他們的一些代碼。下面是我使用的代碼:iText數字簽名PDF而無需輸入PIN兩次

String pkcs11ConfigSettings = 
    "name = SmartCard\nlibrary = C:\\Program Files\\ActivIdentity\\ActivClient\\acpkcs201-ns.dll"; 
AuthProvider p = 
    new SunPKCS11(new ByteArrayInputStream(pkcs11ConfigSettings.getBytes())); 
Security.addProvider(p); 
KeyStore.PasswordProtection pp = 
    new KeyStore.PasswordProtection("".toCharArray()); 
KeyStore.Builder builder = 
    KeyStore.Builder.newInstance("PKCS11",p ,pp); 
KeyStore ks = builder.getKeyStore(); 
Certificate[] cc = ks.getCertificateChain("Digital Signature Key"); 
PrivateKey pk = (PrivateKey)ks.getKey("Digital Signature Key", null); 
OutputStream fos = new FileOutputStream("c:\\2.pdf"); 
PdfReader reader = new PdfReader(new FileInputStream(new File("C:\\1.pdf"))); 
PdfStamper stamper = PdfStamper.createSignature(reader, fos, '\0'); 
PdfSignatureAppearance appearance = stamper.getSignatureAppearance(); 
appearance.setCrypto(pk, cc, null,PdfSignatureAppearance.SELF_SIGNED); 
appearance.setVisibleSignature(new Rectangle(0, 0, 100, 100), 1,null); 
stamper.close(); 

這種方法的問題是,當iText的關閉它確實給C_Sign()調用它調用驅動程序的提示輸入PIN的PDFStamper

所以如果這是一個應用程序,它需要我在簽名之前輸入我的PIN碼,以獲得KeyStorePrivateKey,以及驅動程序的PIN輸入提示時出現。無論如何都要問兩次PIN碼嗎?我對這個東西很陌生,我是否以這種錯誤的方式去做?

回答

2

看來如果我按照authenticated attributes的例子,我可以得到PIN對話框,每次簽署文檔時只彈出一次。這是我最終使用的最終代碼,希望對其他人有幫助。

for(int i=0;i<2;i++) { 
    String pkcs11ConfigSettings = 
       "name = AuthProvider\nlibrary = C:\\Program Files\\ActivIdentity\\ActivClient\\acpkcs201-ns.dll"; 
    AuthProvider p = (SunPKCS11)Security.getProvider("SunPKCS11-AuthProvider"); 
    if(p==null) { 
     p = new SunPKCS11(new ByteArrayInputStream(pkcs11ConfigSettings.getBytes())); 
     p.setCallbackHandler(new CallbackHandler() {  
      @Override 
      public void handle(Callback[] callbacks) throws IOException, 
        UnsupportedCallbackException { 
       for(Callback c : callbacks) 
        if(c instanceof PasswordCallback) { 
         //HACK. if we set password to null it will bring up the drivers PIN dialog. 
         ((PasswordCallback) c).setPassword(null); 
        } 
      } 
     }); 
     Security.addProvider(p); 
    } 
    KeyStore ks = KeyStore.getInstance("PKCS11",p); 
    ks.load(null, null); 
    Certificate[] cc = ks.getCertificateChain("Digital Signature Key"); 
    PrivateKey pk = (PrivateKey)ks.getKey("Digital Signature Key", null); 
    OutputStream fos = new FileOutputStream("c:\\doc" + i + ".pdf"); ; 
    PdfReader reader = new PdfReader(new FileInputStream(new File("C:\\1.pdf"))); 
    PdfStamper stamper = PdfStamper.createSignature(reader, fos, '\0'); 
    PdfSignatureAppearance sap = stamper.getSignatureAppearance(); 
    sap.setVisibleSignature(new Rectangle(100, 100, 200, 200), 1, null); 
    Calendar cal = Calendar.getInstance(); 
    PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED); 
    dic.setDate(new PdfDate(cal)); 
    dic.setName(PdfPKCS7.getSubjectFields((X509Certificate)cc[0]).getField("CN")); 
    sap.setCryptoDictionary(dic); 
    sap.setLayer2Text("Digitally signed by "+ dic.get(PdfName.NAME) +"\n\nDate: " + cal.getTime().toString()); 
    HashMap<PdfName,Object> exc = new HashMap<PdfName,Object>(); 
    exc.put(PdfName.CONTENTS, new Integer(0x2502)); 
    sap.preClose(exc); 
    PdfPKCS7 pk7 = new PdfPKCS7(pk, cc, null, "SHA1", "SunPKCS11-AuthProvider", false); 
    MessageDigest messageDigest = MessageDigest.getInstance("SHA1"); 
    byte buf[] = new byte[8192]; 
    int n; 
    InputStream inp = sap.getRangeStream(); 
    while ((n = inp.read(buf)) > 0) { 
     messageDigest.update(buf, 0, n); 
    } 
    byte hash[] = messageDigest.digest(); 
    byte sh[] = pk7.getAuthenticatedAttributeBytes(hash, cal, null); 
    pk7.update(sh, 0, sh.length); 
    PdfDictionary dic2 = new PdfDictionary(); 
    byte sg[] = pk7.getEncodedPKCS7(hash, cal); 
    byte out[] = new byte[0x2500/2]; 
    System.arraycopy(sg, 0, out, 0, sg.length); 
    dic2.put(PdfName.CONTENTS, new PdfString(out).setHexWriting(true)); 
    sap.close(dic2); 
}