/** * Prepare document for encryption. * * @param document The document to encrypt. * * @ If there is an error accessing data. */ public override void PrepareDocumentForEncryption(Document document) { PdfEncryption encryptionDictionary = document.File.Encryption; if (encryptionDictionary == null) { encryptionDictionary = new PdfEncryption(document.File); } int version = ComputeVersionNumber(); int revision = ComputeRevisionNumber(version); encryptionDictionary.Filter = FILTER; encryptionDictionary.Version = version; if (version != 4 && version != 5) { // remove CF, StmF, and StrF entries that may be left from a previous encryption encryptionDictionary.RemoveV45filters(); } encryptionDictionary.Revision = revision; encryptionDictionary.Length = keyLength; string ownerPassword = policy.OwnerPassword ?? string.Empty; string userPassword = policy.UserPassword ?? string.Empty; // If no owner password is set, use the user password instead. if (ownerPassword.Length == 0) { ownerPassword = userPassword; } int permissionInt = policy.Permissions.PermissionBytes; encryptionDictionary.Permissions = permissionInt; int length = keyLength / 8; if (revision == 6) { // PDFBOX-4155 ownerPassword = SaslPrep.SaslPrepStored(ownerPassword); userPassword = SaslPrep.SaslPrepStored(userPassword); PrepareEncryptionDictRev6(ownerPassword, userPassword, encryptionDictionary, permissionInt); } else { PrepareEncryptionDictRev2345(ownerPassword, userPassword, encryptionDictionary, permissionInt, document, revision, length); } document.File.Encryption = encryptionDictionary; }
/** * Prepares everything to decrypt the document. * * Only if decryption of single objects is needed this should be called. * * @param encryption encryption dictionary * @param documentIDArray document id * @param decryptionMaterial Information used to decrypt the document. * * @throws InvalidPasswordException If the password is incorrect. * @ If there is an error accessing data. */ public override void PrepareForDecryption(PdfEncryption encryption, PdfArray documentIDArray, DecryptionMaterial decryptionMaterial) { if (!(decryptionMaterial is StandardDecryptionMaterial)) { throw new IOException("Decryption material is not compatible with the document"); } // This is only used with security version 4 and 5. if (encryption.Version >= 4) { SetStreamFilterName(encryption.StreamFilterName); SetStringFilterName(encryption.StreamFilterName); } SetDecryptMetadata(encryption.IsEncryptMetaData); StandardDecryptionMaterial material = (StandardDecryptionMaterial)decryptionMaterial; string password = material.Password ?? string.Empty; int dicPermissions = encryption.Permissions; int dicRevision = encryption.Revision; int dicLength = encryption.Version == 1 ? 5 : encryption.Length / 8; byte[] documentIDBytes = GetDocumentIDBytes(documentIDArray); // we need to know whether the meta data was encrypted for password calculation bool encryptMetadata = encryption.IsEncryptMetaData; byte[] userKey = encryption.UserKey; byte[] ownerKey = encryption.OwnerKey; byte[] ue = null, oe = null; var passwordCharset = Charset.ISO88591; if (dicRevision == 6 || dicRevision == 5) { passwordCharset = Charset.UTF8; ue = encryption.UserEncryptionKey; oe = encryption.OwnerEncryptionKey; } if (dicRevision == 6) { password = SaslPrep.SaslPrepQuery(password); // PDFBOX-4155 } AccessPermission currentAccessPermission; if (IsOwnerPassword(passwordCharset.GetBytes(password), userKey, ownerKey, dicPermissions, documentIDBytes, dicRevision, dicLength, encryptMetadata)) { currentAccessPermission = AccessPermission.getOwnerAccessPermission(); CurrentAccessPermission = currentAccessPermission; byte[] computedPassword; if (dicRevision == 6 || dicRevision == 5) { computedPassword = passwordCharset.GetBytes(password); } else { computedPassword = GetUserPassword(passwordCharset.GetBytes(password), ownerKey, dicRevision, dicLength); } encryptionKey = ComputeEncryptedKey( computedPassword, ownerKey, userKey, oe, ue, dicPermissions, documentIDBytes, dicRevision, dicLength, encryptMetadata, true); } else if (IsUserPassword(passwordCharset.GetBytes(password), userKey, ownerKey, dicPermissions, documentIDBytes, dicRevision, dicLength, encryptMetadata)) { currentAccessPermission = new AccessPermission(dicPermissions); currentAccessPermission.IsReadOnly = true; CurrentAccessPermission = currentAccessPermission; encryptionKey = ComputeEncryptedKey( passwordCharset.GetBytes(password), ownerKey, userKey, oe, ue, dicPermissions, documentIDBytes, dicRevision, dicLength, encryptMetadata, false); } else { throw new InvalidPasswordException("Cannot decrypt PDF, the password is incorrect"); } if (dicRevision == 6 || dicRevision == 5) { ValidatePerms(encryption, dicPermissions, encryptMetadata); } if (encryption.Version == 4 || encryption.Version == 5) { // 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. var stdCryptFilterDictionary = encryption.StdCryptFilterDictionary; if (stdCryptFilterDictionary != null) { PdfName cryptFilterMethod = stdCryptFilterDictionary.CryptFilterMethod; IsAES = PdfName.AESV2.Equals(cryptFilterMethod) || PdfName.AESV3.Equals(cryptFilterMethod); } } }