Ejemplo n.º 1
0
        private void PrepareEncryptionDictRev2345(string ownerPassword, string userPassword,
                                                  PdfEncryption encryptionDictionary, int permissionInt, Document document,
                                                  int revision, int length)
        {
            var idArray = document.File.ID;

            //check if the document has an id yet.  If it does not then generate one
            if (idArray == null || idArray.BaseDataObject.Count < 2)
            {
                DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
                using (var md = MD5.Create())
                {
                    BigInteger time = new BigInteger((DateTime.UtcNow - Jan1st1970).TotalMilliseconds.ToString());
                    md.Update(time.ToByteArray());
                    md.Update(Charset.ISO88591.GetBytes(ownerPassword));
                    md.Update(Charset.ISO88591.GetBytes(userPassword));
                    md.Update(Charset.ISO88591.GetBytes(document.Information.ToString()));

                    var       finBlock = Charset.ISO88591.GetBytes(this.ToString());
                    PdfString idString = new PdfString(md.Digest(finBlock));

                    idArray           = new FileIdentifier();
                    idArray.BaseID    = idString;
                    idArray.VersionID = idString;
                    document.File.ID  = idArray;
                }
            }

            PdfString id = idArray.BaseID;

            byte[] ownerBytes = ComputeOwnerPassword(
                Charset.ISO88591.GetBytes(ownerPassword),
                Charset.ISO88591.GetBytes(userPassword), revision, length);

            byte[] userBytes = ComputeUserPassword(
                Charset.ISO88591.GetBytes(userPassword),
                ownerBytes, permissionInt, id.GetBuffer(), revision, length, true);

            encryptionKey = ComputeEncryptedKey(Charset.ISO88591.GetBytes(userPassword), ownerBytes,
                                                null, null, null, permissionInt, id.GetBuffer(), revision, length, true, false);

            encryptionDictionary.OwnerKey = ownerBytes;
            encryptionDictionary.UserKey  = userBytes;

            if (revision == 4)
            {
                PrepareEncryptionDictAES(encryptionDictionary, PdfName.AESV2);
            }
        }
Ejemplo n.º 2
0
 /**
  * This will encrypt a string.
  *
  * @param string the string to encrypt.
  * @param objNum The object number.
  * @param genNum The object generation number.
  *
  * @throws IOException If an error occurs writing the new string.
  */
 public void EncryptString(PdfString pdfString, long objNum, int genNum)
 {
     using (var data = new MemoryStream(pdfString.GetBuffer()))
         using (var buffer = new MemoryStream())
         {
             if (EncryptData(objNum, genNum, data, buffer, false /* encrypt */))
             {
                 pdfString.SetBuffer(buffer.GetBuffer());
             }
         }
 }
Ejemplo n.º 3
0
 private byte[] GetDocumentIDBytes(PdfArray documentIDArray)
 {
     //some documents may not have document id, see
     //test\encryption\encrypted_doc_no_id.pdf
     byte[] documentIDBytes;
     if (documentIDArray != null && documentIDArray.Count >= 1)
     {
         PdfString id = (PdfString)documentIDArray.Resolve(0);
         documentIDBytes = id.GetBuffer();
     }
     else
     {
         documentIDBytes = new byte[0];
     }
     return(documentIDBytes);
 }
Ejemplo n.º 4
0
        /**
         * This will decrypt a string.
         *
         * @param string the string to decrypt.
         * @param objNum The object number.
         * @param genNum The object generation number.
         *
         * @throws IOException If an error occurs writing the new string.
         */
        private void DecryptString(PdfString pdfString, long objNum, long genNum)
        {
            // String encrypted with identity filter
            if (PdfName.Identity.Equals(stringFilterName))
            {
                return;
            }

            using (var data = new MemoryStream(pdfString.GetBuffer()))
                using (var outputStream = new MemoryStream())
                {
                    try
                    {
                        if (EncryptData(objNum, genNum, data, outputStream, true /* decrypt */))
                        {
                            pdfString.SetBuffer(outputStream.ToArray());
                        }
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine($"error: Failed to decrypt PdfString of Length {pdfString.GetBuffer().Length} in object {objNum}: {ex.Message}", ex);
                    }
                }
        }
        /**
         * Prepares everything to decrypt the document.
         *
         * @param encryption encryption dictionary, can be retrieved via
         * {@link Document#getEncryption()}
         * @param documentIDArray document id which is returned via
         * {@link org.apache.pdfbox.cos.COSDocument#getDocumentID()} (not used by
         * this handler)
         * @param decryptionMaterial Information used to decrypt the document.
         *
         * @throws IOException If there is an error accessing data. If verbose mode
         * is enabled, the exception message will provide more details why the
         * match wasn't successful.
         */
        public override void PrepareForDecryption(PdfEncryption encryption, PdfArray documentIDArray, DecryptionMaterial decryptionMaterial)
        {
            if (!(decryptionMaterial is PublicKeyDecryptionMaterial))
            {
                throw new IOException(
                          "Provided decryption material is not compatible with the document");
            }

            SetDecryptMetadata(encryption.IsEncryptMetaData);
            if (encryption.Length != 0)
            {
                this.keyLength = encryption.Length;
            }

            PublicKeyDecryptionMaterial material = (PublicKeyDecryptionMaterial)decryptionMaterial;

            try
            {
                bool foundRecipient = false;
                //Org.BouncyCastle.X509.Extension.
                X509Certificate      certificate  = material.Certificate;
                X509CertificateEntry materialCert = null;
                if (certificate != null)
                {
                    materialCert = new X509CertificateEntry(certificate);
                }

                // the decrypted content of the enveloped data that match
                // the certificate in the decryption material provided
                byte[] envelopedData = null;

                // the bytes of each recipient in the recipients array
                PdfArray array = (PdfArray)encryption.BaseDataObject.Resolve(PdfName.Recipients);
                if (array == null)
                {
                    PdfCryptFilterDictionary defaultCryptFilterDictionary = encryption.DefaultCryptFilterDictionary;
                    array = (PdfArray)defaultCryptFilterDictionary.BaseDataObject.Resolve(PdfName.Recipients);
                }
                byte[][] recipientFieldsBytes = new byte[array.Count][];
                //TODO encryption.getRecipientsLength() and getRecipientStringAt() should be deprecated

                int           recipientFieldsLength = 0;
                StringBuilder extraInfo             = new StringBuilder();
                for (int i = 0; i < array.Count; i++)
                {
                    PdfString recipientFieldString = (PdfString)array.Resolve(i);
                    byte[]    recipientBytes       = recipientFieldString.GetBuffer();

                    CmsEnvelopedData data   = new CmsEnvelopedData(recipientBytes);
                    var recipCertificatesIt = data.GetRecipientInfos().GetRecipients();
                    int j = 0;
                    foreach (RecipientInformation ri in recipCertificatesIt)
                    {
                        // Impl: if a matching certificate was previously found it is an error,
                        // here we just don't care about it
                        RecipientID rid = ri.RecipientID;
                        if (!foundRecipient && rid.Match(materialCert))
                        {
                            foundRecipient = true;
                            var privateKey = material.PrivateKey;
                            // might need to call setContentProvider() if we use PKI token, see
                            // http://bouncy-castle.1462172.n4.nabble.com/CMSException-exception-unwrapping-key-key-invalid-unknown-key-type-passed-to-RSA-td4658109.html
                            //DotNetUtilities.GetKeyPair(ri.AlgorithmIdentifier)
                            envelopedData = ri.GetContent(privateKey.Key);
                            break;
                        }
                        j++;
                        if (certificate != null)
                        {
                            extraInfo.Append('\n');
                            extraInfo.Append(j);
                            extraInfo.Append(": ");
                            if (ri is KeyTransRecipientInformation)
                            {
                                appendCertInfo(extraInfo, (KeyTransRecipientInformation)ri, certificate, materialCert);
                            }
                        }
                    }
                    recipientFieldsBytes[i] = recipientBytes;
                    recipientFieldsLength  += recipientBytes.Length;
                }
                if (!foundRecipient || envelopedData == null)
                {
                    throw new IOException("The certificate matches none of " + array.Count
                                          + " recipient entries" + extraInfo.ToString());
                }
                if (envelopedData.Length != 24)
                {
                    throw new IOException("The enveloped data does not contain 24 bytes");
                }
                // now envelopedData contains:
                // - the 20 bytes seed
                // - the 4 bytes of permission for the current user

                byte[] accessBytes = new byte[4];
                Array.Copy(envelopedData, 20, accessBytes, 0, 4);

                AccessPermission currentAccessPermission = new AccessPermission(accessBytes);
                currentAccessPermission.IsReadOnly = true;
                CurrentAccessPermission            = currentAccessPermission;

                // what we will put in the SHA1 = the seed + each byte contained in the recipients array
                byte[] sha1Input = new byte[recipientFieldsLength + 20];

                // put the seed in the sha1 input
                Array.Copy(envelopedData, 0, sha1Input, 0, 20);

                // put each bytes of the recipients array in the sha1 input
                int sha1InputOffset = 20;
                foreach (byte[] recipientFieldsByte in recipientFieldsBytes)
                {
                    Array.Copy(recipientFieldsByte, 0, sha1Input, sha1InputOffset, recipientFieldsByte.Length);
                    sha1InputOffset += recipientFieldsByte.Length;
                }

                byte[] mdResult;
                if (encryption.Version == 4 || encryption.Version == 5)
                {
                    mdResult = SHA256.Create().Digest(sha1Input);

                    // detect whether AES encryption is used. This assumes that the encryption algo is
                    // stored in the PDCryptFilterDictionary
                    // However, crypt filters are used only when V is 4 or 5.
                    PdfCryptFilterDictionary defaultCryptFilterDictionary = encryption.DefaultCryptFilterDictionary;
                    if (defaultCryptFilterDictionary != null)
                    {
                        PdfName cryptFilterMethod = defaultCryptFilterDictionary.CryptFilterMethod;
                        IsAES = PdfName.AESV2.Equals(cryptFilterMethod) || PdfName.AESV3.Equals(cryptFilterMethod);
                    }
                }
                else
                {
                    mdResult = SHA1.Create().Digest(sha1Input);
                }

                // we have the encryption key ...
                encryptionKey = new byte[this.keyLength / 8];
                Array.Copy(mdResult, 0, encryptionKey, 0, this.keyLength / 8);
            }
            catch (Exception e)
            {
                throw new IOException("", e);
            }
        }