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:27:33 UTC

svn commit: r1878053 - in /pdfbox/branches/issue45: ./ examples/src/test/java/org/apache/pdfbox/examples/pdmodel/ examples/src/test/resources/org/apache/pdfbox/examples/signature/ pdfbox/ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/

Author: lehmi
Date: Sat May 23 10:27:33 2020
New Revision: 1878053

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

Added:
    pdfbox/branches/issue45/examples/src/test/resources/org/apache/pdfbox/examples/signature/sign_me_protected.pdf
      - copied unchanged from r1878051, pdfbox/branches/2.0/examples/src/test/resources/org/apache/pdfbox/examples/signature/sign_me_protected.pdf
Modified:
    pdfbox/branches/issue45/   (props changed)
    pdfbox/branches/issue45/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java
    pdfbox/branches/issue45/pdfbox/   (props changed)
    pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java

Propchange: pdfbox/branches/issue45/
------------------------------------------------------------------------------
  Merged /pdfbox/branches/2.0:r1878051

Modified: pdfbox/branches/issue45/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java?rev=1878053&r1=1878052&r2=1878053&view=diff
==============================================================================
--- pdfbox/branches/issue45/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java (original)
+++ pdfbox/branches/issue45/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java Sat May 23 10:27:33 2020
@@ -29,12 +29,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.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -51,6 +54,7 @@ import org.apache.pdfbox.pdmodel.PDDocum
 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.digitalsignature.ExternalSigningSupport;
 import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
 import org.apache.pdfbox.pdmodel.interactive.form.PDField;
 import org.apache.pdfbox.rendering.PDFRenderer;
@@ -67,6 +71,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;
@@ -594,3 +599,68 @@ public class TestCreateSignature
         doc.close();
     }
 }
+
+    @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(keystorePath), password.toCharArray());
+
+        CreateSignature signing = new CreateSignature(keystore, password.toCharArray());
+        signing.setExternalSigning(true);
+
+        File inFile = new File(inDir + "sign_me_protected.pdf");
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+        PDDocument doc = null;
+        try
+        {
+            doc = PDDocument.load(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);
+        }
+    }
+}
+

Propchange: pdfbox/branches/issue45/pdfbox/
------------------------------------------------------------------------------
  Merged /pdfbox/branches/2.0/pdfbox:r1878051
  Merged /pdfbox/trunk/pdfbox:r1878049

Modified: pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java?rev=1878053&r1=1878052&r2=1878053&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/SecurityHandler.java Sat May 23 10:27:33 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.
@@ -105,6 +108,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.
@@ -348,7 +361,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);
         }
@@ -356,9 +369,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.
      *