You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2020/05/23 10:09:04 UTC

svn commit: r1878049 - in /pdfbox/trunk: examples/src/test/java/org/apache/pdfbox/examples/pdmodel/ examples/src/test/resources/org/apache/pdfbox/examples/signature/ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/

Author: lehmi
Date: Sat May 23 10:09:04 2020
New Revision: 1878049

URL: http://svn.apache.org/viewvc?rev=1878049&view=rev
Log:
PDFBOX-4784, closes #83: add optional usage of an external SecureRandom for AES encryption as proposed by Aleksandr Beliakov

Added:
    pdfbox/trunk/examples/src/test/resources/org/apache/pdfbox/examples/signature/sign_me_protected.pdf   (with props)
Modified:
    pdfbox/trunk/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java

Modified: pdfbox/trunk/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java?rev=1878049&r1=1878048&r2=1878049&view=diff
==============================================================================
--- pdfbox/trunk/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java (original)
+++ pdfbox/trunk/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java Sat May 23 10:09:04 2020
@@ -32,12 +32,15 @@ import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
 import java.security.UnrecoverableKeyException;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.text.MessageFormat;
 import java.util.Arrays;
+import java.util.Calendar;
 import java.util.Collection;
+import java.util.Date;
 import java.util.List;
 
 import org.apache.pdfbox.Loader;
@@ -53,6 +56,7 @@ import org.apache.pdfbox.pdmodel.PDPage;
 import org.apache.pdfbox.pdmodel.PDPageContentStream;
 import org.apache.pdfbox.pdmodel.encryption.SecurityProvider;
 import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.ExternalSigningSupport;
 import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
 import org.apache.pdfbox.pdmodel.interactive.form.PDField;
 import org.apache.pdfbox.rendering.PDFRenderer;
@@ -69,6 +73,7 @@ import org.bouncycastle.cms.CMSSignedDat
 import org.bouncycastle.cms.SignerInformation;
 import org.bouncycastle.cms.SignerInformationVerifier;
 import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
+import org.bouncycastle.crypto.prng.FixedSecureRandom;
 import org.bouncycastle.operator.OperatorCreationException;
 import org.bouncycastle.tsp.TSPException;
 import org.bouncycastle.tsp.TSPValidationException;
@@ -556,4 +561,67 @@ public class TestCreateSignature
             Assert.assertArrayEquals(expectedData.getData(), actualData.getData());
         }
     }
+
+    @Test
+    public void testPDFBox4784() throws Exception
+    {
+
+        Date signingTime = new Date();
+
+        byte[] defaultSignedOne = signEncrypted(null, signingTime);
+        byte[] defaultSignedTwo = signEncrypted(null, signingTime);
+        Assert.assertFalse(Arrays.equals(defaultSignedOne, defaultSignedTwo));
+
+        // a dummy value for FixedSecureRandom is used (for real use-cases a secure value should be provided)
+        byte[] fixedRandomSignedOne = signEncrypted(new FixedSecureRandom(new byte[128]),
+                signingTime);
+        byte[] fixedRandomSignedTwo = signEncrypted(new FixedSecureRandom(new byte[128]),
+                signingTime);
+        Assert.assertTrue(Arrays.equals(fixedRandomSignedOne, fixedRandomSignedTwo));
+
+    }
+
+    private byte[] signEncrypted(SecureRandom secureRandom, Date signingTime) throws Exception
+    {
+        KeyStore keystore = KeyStore.getInstance("PKCS12");
+        keystore.load(new FileInputStream(KEYSTORE_PATH), PASSWORD.toCharArray());
+
+        CreateSignature signing = new CreateSignature(keystore, PASSWORD.toCharArray());
+        signing.setExternalSigning(true);
+
+        File inFile = new File(IN_DIR + "sign_me_protected.pdf");
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+        PDDocument doc = null;
+        try
+        {
+            doc = Loader.loadPDF(inFile, " ");
+
+            if (secureRandom != null)
+            {
+                doc.getEncryption().getSecurityHandler().setCustomSecureRandom(secureRandom);
+            }
+
+            PDSignature signature = new PDSignature();
+            signature.setName("Example User");
+            Calendar cal = Calendar.getInstance();
+            cal.setTime(signingTime);
+            signature.setSignDate(cal);
+
+            doc.addSignature(signature);
+            doc.setDocumentId(12345l);
+            ExternalSigningSupport externalSigning = doc.saveIncrementalForExternalSigning(baos);
+            // invoke external signature service
+            byte[] cmsSignature = signing.sign(externalSigning.getContent());
+            // set signature bytes received from the service
+            externalSigning.setSignature(cmsSignature);
+
+            return baos.toByteArray();
+        }
+        finally
+        {
+            IOUtils.closeQuietly(doc);
+            IOUtils.closeQuietly(baos);
+        }
+    }
 }

Added: pdfbox/trunk/examples/src/test/resources/org/apache/pdfbox/examples/signature/sign_me_protected.pdf
URL: http://svn.apache.org/viewvc/pdfbox/trunk/examples/src/test/resources/org/apache/pdfbox/examples/signature/sign_me_protected.pdf?rev=1878049&view=auto
==============================================================================
Binary file - no diff available.

Propchange: pdfbox/trunk/examples/src/test/resources/org/apache/pdfbox/examples/signature/sign_me_protected.pdf
------------------------------------------------------------------------------
    svn:mime-type = application/pdf

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java?rev=1878049&r1=1878048&r2=1878049&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java Sat May 23 10:09:04 2020
@@ -78,6 +78,9 @@ public abstract class SecurityHandler
     /** indicates if the Metadata have to be decrypted of not. */
     private boolean decryptMetadata;
 
+    /** Can be used to allow stateless AES encryption */
+    private SecureRandom customSecureRandom;
+
     // PDFBOX-4453, PDFBOX-4477: Originally this was just a Set. This failed in rare cases
     // when a decrypted string was identical to an encrypted string.
     // Because COSString.equals() checks the contents, decryption was then skipped.
@@ -134,6 +137,16 @@ public abstract class SecurityHandler
     }
 
     /**
+     * Set the custom SecureRandom.
+     * 
+     * @param secureRandom the custom SecureRandom for AES encryption
+     */
+    public void setCustomSecureRandom(SecureRandom customSecureRandom)
+    {
+        this.customSecureRandom = customSecureRandom;
+    }
+
+    /**
      * Prepare the document for encryption.
      *
      * @param doc The document that will be encrypted.
@@ -372,7 +385,7 @@ public abstract class SecurityHandler
         else
         {
             // generate random IV and write to stream
-            SecureRandom rnd = new SecureRandom();
+            SecureRandom rnd = getSecureRandom();
             rnd.nextBytes(iv);
             output.write(iv);
         }
@@ -380,9 +393,23 @@ public abstract class SecurityHandler
     }
 
     /**
+     * Returns a SecureRandom If customSecureRandom is not defined, instantiate a new SecureRandom
+     * 
+     * @return SecureRandom
+     */
+    private SecureRandom getSecureRandom()
+    {
+        if (customSecureRandom != null)
+        {
+            return customSecureRandom;
+        }
+        return new SecureRandom();
+    }
+
+    /**
      * This will dispatch to the correct method.
      *
-     * @param obj The object to decrypt.
+     * @param obj    The object to decrypt.
      * @param objNum The object number.
      * @param genNum The object generation Number.
      *