How to programmatically sign a binary MS office document with Java?

后端 未结 1 681
感动是毒
感动是毒 2021-01-29 10:07

How can we digitally sign a legacy binary MS-Office document (doc, xls, ppt) in Apache POI, or any other open source library?

The Open XML formats are covered at How to

相关标签:
1条回答
  • 2021-01-29 11:03

    I was able to sign .doc file by creating detached xml signature, then adding it under root directory using POIFSFileSystem, example is below :

    public class OfficeDocumentSigner2 {
    
    
        public static void main(String[] args) {
            signClassicOfficeDocuments();
        }
    
        private static String sign() {
    
            // First, create a DOM XMLSignatureFactory that will be used to
            // generate the XMLSignature and marshal it to DOM.
            XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
            OutputStream os = null;
            String signedDoc = "C:\\Users\\Desktop\\digitalSign\\signdoc_signed.xml";
            try {
                // Create a Reference to an external URI that will be digested
                // using the SHA1 digest algorithm
    
                Reference ref = fac.newReference(officeFilePath, fac.newDigestMethod(DigestMethod.SHA1, null));
                // Create the SignedInfo
                SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS, (C14NMethodParameterSpec) null), fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
                        Collections.singletonList(ref));
    
                // Create the Document that will hold the resulting XMLSignature --> detached
                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                dbf.setNamespaceAware(true); // must be set
                Document doc = dbf.newDocumentBuilder().newDocument();
    
                // certificate info
                File file = new File("C:\\Users\\Desktop\\digitalSign\\test101\\KeyStore.jks");
                // extracting private key and certificate
                String alias = "certAlias";
                X509Certificate x509 = null;
                // loading the keystore
                KeyStore keystore = KeyStore.getInstance("JKS");
                FileInputStream fis = new FileInputStream(file);
                keystore.load(fis, password);
                fis.close();
                x509 = (X509Certificate) keystore.getCertificate(alias);
                KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) keystore.getEntry(alias, new KeyStore.PasswordProtection(password));
    
                // Create the KeyInfo containing the X509Data.
                // ref : http://www.oracle.com/technetwork/articles/javase/dig-signature-api-140772.html
                KeyInfoFactory kif = fac.getKeyInfoFactory();
                List x509Content = new ArrayList();
                x509Content.add(x509.getSubjectX500Principal().getName());
                x509Content.add(x509);
                X509Data xd = kif.newX509Data(x509Content);
                KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));
    
                // Create a DOMSignContext and specify the DSA PrivateKey and
                // location of the resulting XMLSignature's parent element
                DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), doc);
                dsc.setBaseURI(baseURI);
                // Create the XMLSignature (but don't sign it yet)
                XMLSignature signature = fac.newXMLSignature(si, ki);
    
                // Marshal, generate (and sign) the enveloped signature
                signature.sign(dsc);
    
                // Output the resulting document.
    
                os = new FileOutputStream(signedDoc);
                TransformerFactory tf = TransformerFactory.newInstance();
                Transformer trans = tf.newTransformer();
                trans.transform(new DOMSource(doc), new StreamResult(os));
    
    
            } catch (Exception e) {
                e.printStackTrace();
            }
            return signedDoc;
        }
    
        public static void signClassicOfficeDocuments() {
    
            InputStream is;
            try {
                //sign document
                String signaturePath = sign();
                InputStream signatureAsIS = new FileInputStream(signaturePath);
    
                is = new FileInputStream(fileName);
                POIFSFileSystem poifs = new POIFSFileSystem(is);
                DirectoryEntry dirEntry =  poifs.createDirectory("_xmlsignatures"); // create a new DirectoryEntry in the root directory
                dirEntry.createDocument("9149", signatureAsIS);
    
                String destPath = "C://Users//Desktop//digitalSign//test_11_24_signedByMe.doc";
                OutputStream os = new FileOutputStream(destPath);
                poifs.writeFilesystem(os);
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    
    
    }
    
    0 讨论(0)
提交回复
热议问题