/// <summary>
        /// Convert the file trailer dictionary into a <see cref="DocumentInformation"/> instance.
        /// </summary>
        public static DocumentInformation Create(IPdfTokenScanner pdfTokenScanner, TrailerDictionary trailer, bool isLenientParsing)
        {
            if (!trailer.Info.HasValue)
            {
                return(DocumentInformation.Default);
            }

            var token = DirectObjectFinder.Get <IToken>(trailer.Info.Value, pdfTokenScanner);

            if (token is DictionaryToken infoParsed)
            {
                var title        = GetEntryOrDefault(infoParsed, NameToken.Title);
                var author       = GetEntryOrDefault(infoParsed, NameToken.Author);
                var subject      = GetEntryOrDefault(infoParsed, NameToken.Subject);
                var keywords     = GetEntryOrDefault(infoParsed, NameToken.Keywords);
                var creator      = GetEntryOrDefault(infoParsed, NameToken.Creator);
                var producer     = GetEntryOrDefault(infoParsed, NameToken.Producer);
                var creationDate = GetEntryOrDefault(infoParsed, NameToken.CreationDate);
                var modifiedDate = GetEntryOrDefault(infoParsed, NameToken.ModDate);

                return(new DocumentInformation(infoParsed, title, author, subject,
                                               keywords, creator, producer, creationDate, modifiedDate));
            }

            if (token is StreamToken streamToken)
            {
                var streamDictionary = streamToken.StreamDictionary;
                if (!streamDictionary.TryGet(NameToken.Type, out NameToken typeNameToken) || typeNameToken != "Metadata")
                {
                    throw new PdfDocumentFormatException("Unknown document metadata type was found");
                }

                if (!streamDictionary.TryGet(NameToken.Subtype, out NameToken subtypeToken) || subtypeToken != "XML")
                {
                    throw new PdfDocumentFormatException("Unknown document metadata subtype was found");
                }

                // We are not fully supporting XMP Stream so we let the user fully deserialize the stream
                return(DocumentInformation.Default);
            }

            if (isLenientParsing)
            {
                return(DocumentInformation.Default);
            }

            throw new PdfDocumentFormatException($"Unknown document information token was found {token.GetType().Name}");
        }
        public DocumentInformation Create(IPdfTokenScanner pdfTokenScanner, TrailerDictionary trailer)
        {
            if (!trailer.Info.HasValue)
            {
                return(DocumentInformation.Default);
            }

            var infoParsed = DirectObjectFinder.Get <DictionaryToken>(trailer.Info.Value, pdfTokenScanner);

            var title    = GetEntryOrDefault(infoParsed, NameToken.Title);
            var author   = GetEntryOrDefault(infoParsed, NameToken.Author);
            var subject  = GetEntryOrDefault(infoParsed, NameToken.Subject);
            var keywords = GetEntryOrDefault(infoParsed, NameToken.Keywords);
            var creator  = GetEntryOrDefault(infoParsed, NameToken.Creator);
            var producer = GetEntryOrDefault(infoParsed, NameToken.Producer);

            return(new DocumentInformation(infoParsed, title, author, subject,
                                           keywords, creator, producer));
        }
Exemple #3
0
        public EncryptionHandler(EncryptionDictionary encryptionDictionary, TrailerDictionary trailerDictionary, IReadOnlyList <string> passwords)
        {
            this.encryptionDictionary = encryptionDictionary;

            passwords = passwords ?? new[] { string.Empty };

            if (!passwords.Contains(string.Empty))
            {
                passwords = new List <string>(passwords)
                {
                    string.Empty
                };
            }

            byte[] documentIdBytes;

            if (trailerDictionary.Identifier != null && trailerDictionary.Identifier.Count == 2)
            {
                var token = trailerDictionary.Identifier[0];

                switch (token)
                {
                case HexToken hex:
                    documentIdBytes = hex.Bytes.ToArray();
                    break;

                default:
                    documentIdBytes = OtherEncodings.StringAsLatin1Bytes(token.Data);
                    break;
                }
            }
            else
            {
                documentIdBytes = EmptyArray <byte> .Instance;
            }

            if (encryptionDictionary == null)
            {
                return;
            }

            useAes = false;

            if (encryptionDictionary.EncryptionAlgorithmCode == EncryptionAlgorithmCode.SecurityHandlerInDocument ||
                encryptionDictionary.EncryptionAlgorithmCode == EncryptionAlgorithmCode.SecurityHandlerInDocument256)
            {
                if (!encryptionDictionary.TryGetCryptHandler(out var cryptHandlerLocal))
                {
                    throw new PdfDocumentEncryptedException("Document encrypted with security handler in document but no crypt dictionary found.", encryptionDictionary);
                }

                cryptHandler = cryptHandlerLocal;

                useAes = cryptHandlerLocal?.StreamDictionary?.Name == CryptDictionary.Method.AesV2 ||
                         cryptHandlerLocal?.StreamDictionary?.Name == CryptDictionary.Method.AesV3;
            }

            var charset = OtherEncodings.Iso88591;

            if (encryptionDictionary.Revision == 5 || encryptionDictionary.Revision == 6)
            {
                // ReSharper disable once RedundantAssignment
                charset = Encoding.UTF8;
            }

            var length = encryptionDictionary.EncryptionAlgorithmCode == EncryptionAlgorithmCode.Rc4OrAes40BitKey
                ? 5
                : encryptionDictionary.KeyLength.GetValueOrDefault() / 8;

            var foundPassword = false;

            foreach (var password in passwords)
            {
                var passwordBytes = charset.GetBytes(password);

                var    isUserPassword = false;
                byte[] decryptionPasswordBytes;

                if (IsOwnerPassword(passwordBytes, encryptionDictionary, length, documentIdBytes, out var userPassBytes))
                {
                    if (encryptionDictionary.Revision == 5 || encryptionDictionary.Revision == 6)
                    {
                        decryptionPasswordBytes = passwordBytes;
                    }
                    else
                    {
                        decryptionPasswordBytes = userPassBytes;
                    }
                }
                else if (IsUserPassword(passwordBytes, encryptionDictionary, length, documentIdBytes))
                {
                    decryptionPasswordBytes = passwordBytes;
                    isUserPassword          = true;
                }
                else
                {
                    continue;
                }

                encryptionKey = CalculateEncryptionKey(decryptionPasswordBytes, encryptionDictionary,
                                                       length,
                                                       documentIdBytes,
                                                       isUserPassword);

                foundPassword = true;

                break;
            }

            if (!foundPassword)
            {
                throw new PdfDocumentEncryptedException("The document was encrypted and none of the provided passwords were the user or owner password.",
                                                        encryptionDictionary);
            }
        }
Exemple #4
0
        public EncryptionHandler(EncryptionDictionary encryptionDictionary, TrailerDictionary trailerDictionary, string password)
        {
            this.encryptionDictionary = encryptionDictionary;

            var documentIdBytes = trailerDictionary.Identifier != null && trailerDictionary.Identifier.Count == 2 ?
                                  OtherEncodings.StringAsLatin1Bytes(trailerDictionary.Identifier[0])
                : EmptyArray <byte> .Instance;

            password = password ?? string.Empty;

            if (encryptionDictionary == null)
            {
                return;
            }

            useAes = false;

            if (encryptionDictionary.EncryptionAlgorithmCode == EncryptionAlgorithmCode.SecurityHandlerInDocument ||
                encryptionDictionary.EncryptionAlgorithmCode == EncryptionAlgorithmCode.SecurityHandlerInDocument256)
            {
                if (!encryptionDictionary.TryGetCryptHandler(out var cryptHandlerLocal))
                {
                    throw new PdfDocumentEncryptedException("Document encrypted with security handler in document but no crypt dictionary found.", encryptionDictionary);
                }

                cryptHandler = cryptHandlerLocal;

                useAes = cryptHandlerLocal?.StreamDictionary?.Name == CryptDictionary.Method.AesV2 ||
                         cryptHandlerLocal?.StreamDictionary?.Name == CryptDictionary.Method.AesV3;
            }

            var charset = OtherEncodings.Iso88591;

            if (encryptionDictionary.Revision == 5 || encryptionDictionary.Revision == 6)
            {
                // ReSharper disable once RedundantAssignment
                charset = Encoding.UTF8;
            }

            var passwordBytes = charset.GetBytes(password);

            byte[] decryptionPasswordBytes;

            var length = encryptionDictionary.EncryptionAlgorithmCode == EncryptionAlgorithmCode.Rc4OrAes40BitKey
                ? 5
                : encryptionDictionary.KeyLength.GetValueOrDefault() / 8;

            var isUserPassword = false;

            if (IsOwnerPassword(passwordBytes, encryptionDictionary, length, documentIdBytes, out var userPassBytes))
            {
                if (encryptionDictionary.Revision == 5 || encryptionDictionary.Revision == 6)
                {
                    decryptionPasswordBytes = passwordBytes;
                }
                else
                {
                    decryptionPasswordBytes = userPassBytes;
                }
            }
            else if (IsUserPassword(passwordBytes, encryptionDictionary, length, documentIdBytes))
            {
                decryptionPasswordBytes = passwordBytes;
                isUserPassword          = true;
            }
            else
            {
                throw new PdfDocumentEncryptedException("The document was encrypted and the provided password was neither the user or owner password.", encryptionDictionary);
            }

            encryptionKey = CalculateEncryptionKey(decryptionPasswordBytes, encryptionDictionary,
                                                   length,
                                                   documentIdBytes,
                                                   isUserPassword);
        }