/// <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)); }
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); } }
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); }