/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package com.example.usbtoken; import java.io.File; import java.io.FileOutputStream; import java.io.PrintWriter; import java.nio.file.Files; import java.nio.file.Paths; import java.security.KeyStore; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.util.Objects; import com.itextpdf.kernel.geom.Rectangle; import com.itextpdf.kernel.pdf.PdfReader; import com.itextpdf.kernel.pdf.StampingProperties; import com.itextpdf.signatures.BouncyCastleDigest; import com.itextpdf.signatures.DigestAlgorithms; import com.itextpdf.signatures.IExternalDigest; import com.itextpdf.signatures.IExternalSignature; import com.itextpdf.signatures.PdfSignatureAppearance; import com.itextpdf.signatures.PdfSigner; import com.itextpdf.signatures.PrivateKeySignature; import com.itextpdf.text.Image; import com.itextpdf.text.pdf.PdfStamper; import com.itextpdf.text.pdf.security.ExternalDigest; import com.itextpdf.text.pdf.security.ExternalSignature; import com.itextpdf.text.pdf.security.MakeSignature; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.UUID; import sun.security.pkcs11.SunPKCS11; /** * * @author TuoiCM */ public class UsbTokenMSCAPI { private static final String DEFAULT_SIGNATURE_ALGORITHM = "SHA1withRSA"; public UsbTokenMSCAPI(String tokenLibraryPath) { Objects.nonNull(tokenLibraryPath); if (Files.notExists(Paths.get(tokenLibraryPath))) { throw new RuntimeException("The library file is not found, check if the path is correct"); } } private SunPKCS11 buildProvider(String tokenLibraryPath) { try { File tmpConfigFile = File.createTempFile("pkcs11-", "conf"); tmpConfigFile.deleteOnExit(); try (PrintWriter configWriter = new PrintWriter(new FileOutputStream(tmpConfigFile), true)) { configWriter.println("name=ePass2003"); configWriter.println("library=" + tokenLibraryPath); // configWriter.println("slotListIndex=" + 0); // configWriter.println("slot=" + 1); } return new SunPKCS11(tmpConfigFile.getAbsolutePath()); } catch (Exception e) { throw new RuntimeException("Ups, something went wrong... ", e); } } /** * Retrieve the public key from the usb token. * * @return PublicKey * @param tokenPassword * */ public PublicKey publicKey() { try { KeyStore keyStore = retrieveKeyStore(); return keyStore.getCertificate(keyStore.aliases().nextElement()).getPublicKey(); } catch (Exception e) { throw new RuntimeException("Ups, something went wrong... ", e); } } /** * Digital Sign a text string. * * @return a signature hash value * @param signatureAlgorithm valid values: * https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#Signature * */ public byte[] signText(String textToSign, String tokenPassword, String signatureAlgorithm) { Objects.nonNull(textToSign); Objects.nonNull(tokenPassword); Objects.nonNull(signatureAlgorithm); try { KeyStore keyStore = retrieveKeyStore(); PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyStore.aliases().nextElement(), null); Signature signature = Signature.getInstance(signatureAlgorithm); signature.initSign(privateKey); byte[] toBeSigned = textToSign.getBytes(); signature.update(toBeSigned); return signature.sign(); } catch (Exception e) { throw new RuntimeException("Ups, something went wrong... ", e); } } /** * Digital Sign a text string using SHA1withRSA signature algorithm * * @return a signature hash value * @param signatureAlgorithm valid values: * https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#Signature * */ public byte[] signText(String textToSign, String tokenPassword) { return this.signText(textToSign, tokenPassword, DEFAULT_SIGNATURE_ALGORITHM); } /** * Digital Sign a PDF. It use itext7. * * @param src source path of the Pdf to be signed. * @param dest destination path of the signed Pdf. * @param tokenPassword * @param reason Reason to sign, it will be displayed in a signature box * inside de pdf. * @param location it will be displayed in a signature box inside de pdf. * */ public void signPdf(String src, String dest, String reason, String location) { try { KeyStore keyStore = retrieveKeyStore(); // String alias = keyStore.aliases().nextElement(); Enumeration enumeration = keyStore.aliases(); List listAlias = new ArrayList<>(); String alias = null; while (enumeration.hasMoreElements()) { alias = enumeration.nextElement(); System.out.println("alias name: " + alias); listAlias.add(alias); } PrivateKey privateKey = (PrivateKey) keyStore.getKey(listAlias.get(0), null); // Creating the reader and the signer PdfReader reader = new PdfReader(src); PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties().useAppendMode()); // Creating the appearance PdfSignatureAppearance appearance = signer.getSignatureAppearance().setReason(reason).setLocation(location) .setReuseAppearance(false); Rectangle rect = new Rectangle(36, 648, 200, 100); appearance.setPageRect(rect).setPageNumber(1); signer.setFieldName("sig"); // Creating the signature IExternalSignature pks = new PrivateKeySignature(privateKey, DigestAlgorithms.SHA256, "SunMSCAPI"); IExternalDigest digest = new BouncyCastleDigest(); signer.signDetached(digest, pks, keyStore.getCertificateChain(listAlias.get(0)), null, null, null, 0, PdfSigner.CryptoStandard.CMS); } catch (Exception e) { throw new RuntimeException("Ups, something went wrong... ", e); } } private KeyStore retrieveKeyStore() throws Exception { //Solution MS-CAPI KeyStore keyStore = KeyStore.getInstance("Windows-MY", "SunMSCAPI"); keyStore.load(null, null); return keyStore; } //Multiple signPdf Usb Token MS-CAPI public void multipleSignPdfUsbTokenMSCAPI(File file, String dest, int llx, int lly, int urx, int ury, String checkUsbToken, int indexAlias) { System.out.println("Start multipleSignPdfUsbToken"); String fileName = ""; MakeSignature.CryptoStandard subfilter = MakeSignature.CryptoStandard.CMS; try { //Create KeyStore KeyStore keyStore = this.retrieveKeyStore(); Enumeration enumeration = keyStore.aliases(); List listAlias = new ArrayList<>(); String alias = null; PrivateKey privateKeyCheck = null; while (enumeration.hasMoreElements()) { alias = enumeration.nextElement(); privateKeyCheck = (PrivateKey) keyStore.getKey(alias, null); //Check If Private not null => add Alias if (privateKeyCheck != null) { listAlias.add(alias); } } PrivateKey privateKey = (PrivateKey) keyStore.getKey(listAlias.get(indexAlias), null); //Check PDF File Sign com.itextpdf.text.pdf.PdfReader pdfReader = new com.itextpdf.text.pdf.PdfReader(file.getAbsolutePath()); File outputFile = new File(dest); //Create signature seal PdfStamper pdfStamper; pdfStamper = PdfStamper.createSignature(pdfReader, null, '\0', outputFile, true); //** com.itextpdf.text.pdf.PdfSignatureAppearance sap = pdfStamper.getSignatureAppearance(); sap.setReason("Test SignPDF"); sap.setLocation("VN"); sap.setCertificationLevel(com.itextpdf.text.pdf.PdfSignatureAppearance.NOT_CERTIFIED); //The position of the stamp on the page (lower left of page 1) com.itextpdf.text.Rectangle rectangle = new com.itextpdf.text.Rectangle(llx, lly, urx, ury); UUID uuid = UUID.randomUUID(); String uuidAsString = uuid.toString(); fileName = file.getName().equals(dest.substring(file.getName().length())) ? "EDIT_" + uuidAsString : "NEW_" + uuidAsString; sap.setVisibleSignature(rectangle, 1, fileName); // Set the rendering mode for this signature. sap.setRenderingMode(com.itextpdf.text.pdf.PdfSignatureAppearance.RenderingMode.GRAPHIC_AND_DESCRIPTION); // Set the Image object to render when the rendering mode is set to RenderingMode.GRAPHIC // or RenderingMode.GRAPHIC_AND_DESCRIPTION. String img = "D:\\ProjectKyPDF\\signature-523237_960_720.jpg"; sap.setSignatureGraphic(Image.getInstance(img)); sap.setImageScale(200); //Sgin //Provider //Creating the signature ExternalSignature pks = new com.itextpdf.text.pdf.security.PrivateKeySignature(privateKey, DigestAlgorithms.SHA256, "SunMSCAPI"); ExternalDigest digest = new com.itextpdf.text.pdf.security.BouncyCastleDigest(); MakeSignature.signDetached(sap, digest, pks, keyStore.getCertificateChain(listAlias.get(indexAlias)), null, null, null, 0, subfilter); System.out.println("DONE multipleSignPdfUsbToken!!!"); } catch (Exception e) { throw new RuntimeException("Ups, something went wrong... ", e); } } }