in pdfbox/src/main/java/org/apache/pdfbox/pdmodel/encryption/StandardSecurityHandler.java [146:297]
public void prepareForDecryption(PDEncryption encryption, COSArray documentIDArray,
DecryptionMaterial decryptionMaterial)
throws IOException
{
if(!(decryptionMaterial instanceof StandardDecryptionMaterial))
{
throw new IOException("Decryption material is not compatible with the document");
}
// This is only used with security version 4 and 5.
if (encryption.getVersion() >= REVISION_4) {
setStreamFilterName(encryption.getStreamFilterName());
setStringFilterName(encryption.getStringFilterName());
}
setDecryptMetadata(encryption.isEncryptMetaData());
StandardDecryptionMaterial material = (StandardDecryptionMaterial)decryptionMaterial;
String password = material.getPassword();
if(password == null)
{
password = "";
}
int dicPermissions = encryption.getPermissions();
int dicRevision = encryption.getRevision();
int dicLength = encryption.getVersion() == 1 ? 5 : encryption.getLength() / 8;
if (encryption.getVersion() == REVISION_4 || encryption.getVersion() == REVISION_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.
PDCryptFilterDictionary stdCryptFilterDictionary = encryption.getStdCryptFilterDictionary();
if (stdCryptFilterDictionary != null)
{
COSName cryptFilterMethod = stdCryptFilterDictionary.getCryptFilterMethod();
if (COSName.AESV2.equals(cryptFilterMethod))
{
dicLength = 128 / 8;
setAES(true);
if (encryption.getCOSObject().containsKey(COSName.LENGTH))
{
// PDFBOX-5345
int newLength = encryption.getLength() / 8;
if (newLength < dicLength)
{
LOG.warn(
"Using {} bytes key length instead of {} in AESV2 encryption?!",
newLength, dicLength);
dicLength = newLength;
}
}
}
if (COSName.AESV3.equals(cryptFilterMethod))
{
dicLength = 256 / 8;
setAES(true);
if (encryption.getCOSObject().containsKey(COSName.LENGTH))
{
// PDFBOX-5345
int newLength = encryption.getLength() / 8;
if (newLength < dicLength)
{
LOG.warn(
"Using {} bytes key length instead of {} in AESV3 encryption?!",
newLength, dicLength);
dicLength = newLength;
}
}
}
}
}
byte[] documentIDBytes = getDocumentIDBytes(documentIDArray);
// we need to know whether the meta data was encrypted for password calculation
boolean encryptMetadata = encryption.isEncryptMetaData();
byte[] userKey = encryption.getUserKey();
byte[] ownerKey = encryption.getOwnerKey();
byte[] ue = null, oe = null;
Charset passwordCharset = StandardCharsets.ISO_8859_1;
if (dicRevision == REVISION_5 || dicRevision == REVISION_6)
{
passwordCharset = StandardCharsets.UTF_8;
ue = encryption.getUserEncryptionKey();
oe = encryption.getOwnerEncryptionKey();
}
if (dicRevision == REVISION_6)
{
password = SaslPrep.saslPrepQuery(password); // PDFBOX-4155
}
AccessPermission currentAccessPermission;
byte[] encryptedKey;
byte[] passwordBytes;
boolean isOwnerPassword;
if( isOwnerPassword(password.getBytes(passwordCharset), userKey, ownerKey,
dicPermissions, documentIDBytes, dicRevision,
dicLength, encryptMetadata) )
{
currentAccessPermission = AccessPermission.getOwnerAccessPermission();
setCurrentAccessPermission(currentAccessPermission);
if (dicRevision == REVISION_5 || dicRevision == REVISION_6)
{
passwordBytes = password.getBytes(passwordCharset);
}
else
{
passwordBytes = getUserPassword234(password.getBytes(passwordCharset),
ownerKey, dicRevision, dicLength );
}
isOwnerPassword = true;
}
else if( isUserPassword(password.getBytes(passwordCharset), userKey, ownerKey,
dicPermissions, documentIDBytes, dicRevision,
dicLength, encryptMetadata) )
{
currentAccessPermission = new AccessPermission(dicPermissions);
currentAccessPermission.setReadOnly();
setCurrentAccessPermission(currentAccessPermission);
passwordBytes = password.getBytes(passwordCharset);
isOwnerPassword = false;
}
else
{
throw new InvalidPasswordException("Cannot decrypt PDF, the password is incorrect");
}
encryptedKey = computeEncryptedKey(
passwordBytes,
ownerKey, userKey, oe, ue,
dicPermissions,
documentIDBytes,
dicRevision,
dicLength,
encryptMetadata, isOwnerPassword);
if (dicRevision == REVISION_4 && encryptedKey.length < 16)
{
LOG.info("PDFBOX-5955: padding RC4 key to length 16");
encryptedKey = Arrays.copyOf(encryptedKey, 16);
}
setEncryptionKey(encryptedKey);
if (dicRevision == REVISION_5 || dicRevision == REVISION_6)
{
validatePerms(encryption, dicPermissions, encryptMetadata);
}
}