Exemplo n.º 1
0
        private void PrepareEncryptionDictAES(PdfEncryption encryptionDictionary, PdfName aesVName)
        {
            var cryptFilterDictionary = new PdfCryptFilterDictionary(encryptionDictionary.File);

            cryptFilterDictionary.CryptFilterMethod       = aesVName;
            cryptFilterDictionary.Length                  = keyLength;
            encryptionDictionary.StdCryptFilterDictionary = cryptFilterDictionary;
            encryptionDictionary.StreamFilterName         = PdfName.StdCF;
            encryptionDictionary.StringFilterName         = PdfName.StdCF;
            IsAES = true;
        }
        private void PrepareEncryptionDictAES(PdfEncryption encryptionDictionary, PdfName aesVName, byte[][] recipients)
        {
            PdfCryptFilterDictionary cryptFilterDictionary = new PdfCryptFilterDictionary(encryptionDictionary.File);

            cryptFilterDictionary.CryptFilterMethod = aesVName;
            cryptFilterDictionary.Length            = keyLength;
            PdfArray array = new PdfArray();

            foreach (byte[] recipient in recipients)
            {
                array.Add(new PdfString(recipient));
            }
            cryptFilterDictionary.BaseDataObject[PdfName.Recipients] = array;
            //array.setDirect(true);
            encryptionDictionary.DefaultCryptFilterDictionary = cryptFilterDictionary;
            encryptionDictionary.StreamFilterName             = PdfName.DefaultCryptFilter;
            encryptionDictionary.StringFilterName             = PdfName.DefaultCryptFilter;
            //cryptFilterDictionary.getCOSObject().setDirect(true);
            IsAES = true;
        }
        /**
         * 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);
            }
        }