Package com.sun.pdfview.decrypt
Class StandardDecrypter
java.lang.Object
com.sun.pdfview.decrypt.StandardDecrypter
- All Implemented Interfaces:
PDFDecrypter
Standard simple decrypter for versions 1, 2 and 4 of the Standard
password-based decryption mechanisms, as described in section 3.5 of
the PDF Reference version 1.7.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic enum
Describes an encryption algorithm to be used, declaring not only the cipher type, but also key generation techniques -
Field Summary
FieldsModifier and TypeFieldDescriptionprivate static final byte[]
Extra salt to add to AES-based decryption keys, as per PDF Reference 1.7private static final String
The specification of the AES cipher for JCE interactions.private static final String
The specification of the RC4 cipher for JCE interactionsThe encryption algorithm being employedprivate byte[]
The general encryption key; may be mutated to form individual stream/string encryption keysprivate static final String
The key type for AES keysprivate static final String
The key type for RC4 keysprivate boolean
Whether the owner password was specifiedprivate static final byte[]
Padding used to bring passwords up to 32 bytes, as specified by the first step of Algorithm 3.2 in the PDF Reference version 1.7. -
Constructor Summary
ConstructorsConstructorDescriptionStandardDecrypter
(StandardDecrypter.EncryptionAlgorithm encryptionAlgorithm, PDFObject documentId, int keyBitLength, int revision, byte[] oValue, byte[] uValue, int pValue, boolean encryptMetadata, PDFPassword password) Class constructor -
Method Summary
Modifier and TypeMethodDescriptionprivate byte[]
calculateGeneralEncryptionKey
(byte[] userPassword, byte[] firstDocIdValue, int keyBitLength, int revision, byte[] oValue, int pValue, boolean encryptMetadata) Determine what the general encryption key is, given a configuration.private byte[]
calculateUValue
(byte[] generalKey, byte[] firstDocIdValue, int revision) Calculate what the U value should consist of given a particular key and document configuration.private byte[]
calculuateOValue
(byte[] ownerPassword, byte[] userPassword, int keyBitLength, int revision) Calculate what the O value of the Encrypt dict should look like given a particular configuration.private void
checkNums
(int objNum, int objGen) Check that object number and object generations are well-formed.private byte[]
checkOwnerPassword
(byte[] ownerPassword, byte[] firstDocIdValue, int keyBitLength, int revision, byte[] oValue, byte[] uValue, int pValue, boolean encryptMetadata) Check to see whether a given password is the owner password.private byte[]
checkUserPassword
(byte[] userPassword, byte[] firstDocIdValue, int keyBitLength, int revision, byte[] oValue, byte[] uValue, int pValue, boolean encryptMetadata) Check to see whether a provided user password is correct with respect to an Encrypt dict configuration.private Cipher
Create a new AES cipher.private Cipher
createAndInitialiseContentCipher
(ByteBuffer encrypted, byte[] decryptionKeyBytes) Setup the cipher for decryptionprivate MessageDigest
Create an MD5 digest.private Cipher
Create a new RC4 cipher.private SecretKeySpec
createRC4Key
(byte[] keyBytes) Create an RC4 keyprivate byte[]
Encrypt some bytesprivate void
cryptInPlace
(Cipher rc4, byte[] buffer) Encrypt/decrypt something in placedecryptBuffer
(String cryptFilterName, PDFObject streamObj, ByteBuffer streamBuf) Decrypt a buffer of dataprivate ByteBuffer
decryptBuffer
(ByteBuffer encrypted, byte[] decryptionKeyBytes) Decrypt a bufferdecryptString
(int objNum, int objGen, String inputBasicString) Decrypt abasic string
.private void
digestTo
(MessageDigest md5, byte[] hash) Hash into an existing byte arrayprivate byte[]
getInitialOwnerPasswordKeyBytes
(byte[] ownerPassword, int keyBitLength, int revision) Establish the key to be used for the generation and validation of the user password via the O entry.private byte[]
getObjectSaltedDecryptionKey
(int objNum, int objGen) Get a decryption key salted with an object number and object generation, for use when decrypting a string or stream within an object numbered soprivate int
Get the length of a salted keyprivate int
getSaltedContentKeyByteLength
(int generalKeyByteLength) Get the length of salted keys, in bytes.private byte[]
Get the unsalted content decryption key, used for streams with specific crypt filters, which aren't specific to particular objectsprivate void
initDecryption
(Cipher cipher, Key aKey) Setup a cipher for decryptionprivate void
initEncryption
(Cipher cipher, SecretKey key) Initialise a cipher for encryptionboolean
Determine whether this actually applies a decryption other than identity decryption.boolean
Determine whether the password known by the decrypter indicates that the user is the owner of the document.private byte[]
padPassword
(byte[] password) Pad a password as per step 1 of Algorithm 3.2 of the PDF Reference version 1.7private void
rc4shuffle
(byte[] shuffle, byte[] key, Cipher rc4) Shuffle some input using a series of RC4 encryptions with slight mutations of an given key per iteration.private void
rc4unshuffle
(Cipher rc4, byte[] shuffle, byte[] key) Reverse therc4shuffle(byte[], byte[], javax.crypto.Cipher)
operation, and the operation that invariable preceeds it, thereby obtaining an original messageprivate void
testJceAvailability
(int keyBitLength) Test that the platform (i.e., the JCE) can offer us all of the ciphers at the key length we need for content decryption.
-
Field Details
-
AESV2_SALT
private static final byte[] AESV2_SALTExtra salt to add to AES-based decryption keys, as per PDF Reference 1.7 -
PW_PADDING
private static final byte[] PW_PADDINGPadding used to bring passwords up to 32 bytes, as specified by the first step of Algorithm 3.2 in the PDF Reference version 1.7. -
CIPHER_RC4
The specification of the RC4 cipher for JCE interactions- See Also:
-
KEY_RC4
The key type for RC4 keys- See Also:
-
CIPHER_AES
The specification of the AES cipher for JCE interactions. As per the spec, cipher-block chanining (CBC) mode and PKCS5 padding are used- See Also:
-
KEY_AES
The key type for AES keys- See Also:
-
ownerAuthorised
private boolean ownerAuthorisedWhether the owner password was specified -
generalKeyBytes
private byte[] generalKeyBytesThe general encryption key; may be mutated to form individual stream/string encryption keys -
encryptionAlgorithm
The encryption algorithm being employed
-
-
Constructor Details
-
StandardDecrypter
public StandardDecrypter(StandardDecrypter.EncryptionAlgorithm encryptionAlgorithm, PDFObject documentId, int keyBitLength, int revision, byte[] oValue, byte[] uValue, int pValue, boolean encryptMetadata, PDFPassword password) throws IOException, EncryptionUnsupportedByProductException, EncryptionUnsupportedByPlatformException Class constructor- Parameters:
encryptionAlgorithm
- the algorithm used for encryptiondocumentId
- the contents of the ID entry of the document's trailer dictionary; can be null, but according to the spec, shouldn't be. Is expected to be an array of two byte sequences.keyBitLength
- the length of the key in bits; should be a multiple of 8 between 40 and 128revision
- the revision of the Standard encryption security handler being employed. Should be 2, 3 or 4.oValue
- the value of the O entry from the Encrypt dictionaryuValue
- the value of the U entry from the Encrypt dictionarypValue
- the value of the P entry from the Encrypt dictionaryencryptMetadata
- whether metadata is being encrypted, as identified by the Encrypt dict (with default true if not explicitly identified)password
- the password; not null- Throws:
IOException
- if there's a problem reading the fileEncryptionUnsupportedByPlatformException
- if the encryption is not supported by the environment in which the code is executingEncryptionUnsupportedByProductException
- if PDFRenderer does not currently support the specified encryption
-
-
Method Details
-
decryptBuffer
public ByteBuffer decryptBuffer(String cryptFilterName, PDFObject streamObj, ByteBuffer streamBuf) throws PDFParseException Description copied from interface:PDFDecrypter
Decrypt a buffer of data- Specified by:
decryptBuffer
in interfacePDFDecrypter
- Parameters:
cryptFilterName
- the name of the crypt filter, if V4 encryption is being used, where individual crypt filters may be specified for individual streams. If encryption is not using V4 encryption (indicated by V=4 in the Encrypt dictionary) then this must be null. Null may also be specified with V4 encryption to indicate that the default filter should be used.streamObj
- the object whose stream is being decrypted. The containing object's number and generation contribute to the key used for stream encrypted with the document's default encryption, so this is typically required. Should be null only if a cryptFilterName is specified, as objects with specific stream filters use the general document key, rather than a stream-specific key.streamBuf
- the buffer to decrypt- Returns:
- a buffer containing the decrypted stream, positioned at its beginning; will only be the same buffer as streamBuf if the identity decrypter is being used
- Throws:
PDFParseException
- if the named crypt filter does not exist, or if a crypt filter is named when named crypt filters are not supported. Problems due to incorrect passwords are revealed prior to this point.
-
decryptString
public String decryptString(int objNum, int objGen, String inputBasicString) throws PDFParseException Description copied from interface:PDFDecrypter
Decrypt abasic string
.- Specified by:
decryptString
in interfacePDFDecrypter
- Parameters:
objNum
- the object number of the containing objectobjGen
- the generation number of the containing objectinputBasicString
- the string to be decrypted- Returns:
- the decrypted string
- Throws:
PDFParseException
- if the named crypt filter does not exist, or if a crypt filter is named when named crypt filters are not supported. Problems due to incorrect passwords are revealed prior to this point.
-
isOwnerAuthorised
public boolean isOwnerAuthorised()Description copied from interface:PDFDecrypter
Determine whether the password known by the decrypter indicates that the user is the owner of the document. Can be used, in conjunction withPDFDecrypter.isEncryptionPresent()
to determine whether any permissions apply.- Specified by:
isOwnerAuthorised
in interfacePDFDecrypter
- Returns:
- whether owner authentication is being used to decrypt the document
-
isEncryptionPresent
public boolean isEncryptionPresent()Description copied from interface:PDFDecrypter
Determine whether this actually applies a decryption other than identity decryption.- Specified by:
isEncryptionPresent
in interfacePDFDecrypter
- Returns:
- whether encryption is present
-
testJceAvailability
private void testJceAvailability(int keyBitLength) throws EncryptionUnsupportedByPlatformException, PDFParseException Test that the platform (i.e., the JCE) can offer us all of the ciphers at the key length we need for content decryption. This shouldn't be a problem on the Java 5 platform unless a particularly restrictive policy file is in place. Calling this on construction should avoid problems like these being exposed as PDFParseExceptions as they're used during decryption and key establishment.- Parameters:
keyBitLength
- the length of the content key, in bits- Throws:
EncryptionUnsupportedByPlatformException
- if the platform does not support the required ciphers and key lengthsPDFParseException
- if there's an internal error while testing cipher availability
-
decryptBuffer
private ByteBuffer decryptBuffer(ByteBuffer encrypted, byte[] decryptionKeyBytes) throws PDFParseException Decrypt a buffer- Parameters:
encrypted
- the encrypted contentdecryptionKeyBytes
- the key to use for decryption- Returns:
- a freshly allocated buffer containing the decrypted content
- Throws:
PDFParseException
- if there's a problem decrypting the content
-
createAndInitialiseContentCipher
private Cipher createAndInitialiseContentCipher(ByteBuffer encrypted, byte[] decryptionKeyBytes) throws PDFParseException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException Setup the cipher for decryption- Parameters:
encrypted
- the encrypted content; required by AES encryption so that the initialisation vector can be establisheddecryptionKeyBytes
- the bytes for the decryption key- Returns:
- a content decryption cypher, ready to accept input
- Throws:
PDFParseException
- if the encrypted buffer is malformed or on an internal errorNoSuchAlgorithmException
- if the cipher algorithm is not supported by the platformNoSuchPaddingException
- if the cipher padding is not supported by the platformInvalidKeyException
- if the key is invalid according to the cipher, or too longInvalidAlgorithmParameterException
- if the cipher parameters are bad
-
getUnsaltedDecryptionKey
private byte[] getUnsaltedDecryptionKey()Get the unsalted content decryption key, used for streams with specific crypt filters, which aren't specific to particular objects- Returns:
- the general key
-
getObjectSaltedDecryptionKey
Get a decryption key salted with an object number and object generation, for use when decrypting a string or stream within an object numbered so- Parameters:
objNum
- the object numberobjGen
- the object generation- Returns:
- the key to be used for decrypting data associated with the object numbered so
- Throws:
PDFParseException
- if the MD5 digest is not available
-
getSaltedContentKeyByteLength
private int getSaltedContentKeyByteLength()Get the length of a salted key- Returns:
- length in bytes
-
getSaltedContentKeyByteLength
private int getSaltedContentKeyByteLength(int generalKeyByteLength) Get the length of salted keys, in bytes. Unsalted keys will be the same length asgeneralKeyBytes
- Parameters:
generalKeyByteLength
- the length of the general key, in bytes- Returns:
- byte length of salted keys
-
checkNums
Check that object number and object generations are well-formed. It is possible for somePDFObject
s to have uninitialised object numbers and generations, but such objects should not required decryption- Parameters:
objNum
- the object numberobjGen
- the object generation- Throws:
PDFParseException
- if the object numbering indicates that they aren't true object numbers
-
calculateUValue
private byte[] calculateUValue(byte[] generalKey, byte[] firstDocIdValue, int revision) throws GeneralSecurityException, EncryptionUnsupportedByProductException Calculate what the U value should consist of given a particular key and document configuration. Correponds to Algorithms 3.4 and 3.5 of the PDF Reference version 1.7- Parameters:
generalKey
- the general encryption keyfirstDocIdValue
- the value of the first element in the document's ID entry in the trailer dictionaryrevision
- the revision of the security handler- Returns:
- the U value for the given configuration
- Throws:
GeneralSecurityException
- if there's an error getting required ciphers, etc. (unexpected, since a check for algorithm availability is performed on construction)EncryptionUnsupportedByProductException
- if the revision is not supported
-
calculuateOValue
private byte[] calculuateOValue(byte[] ownerPassword, byte[] userPassword, int keyBitLength, int revision) throws GeneralSecurityException Calculate what the O value of the Encrypt dict should look like given a particular configuration. Not used, but useful for reference; this process is reversed to determine whether a given password is the owner password. Corresponds to Algorithm 3.3 of the PDF Reference version 1.7.- Parameters:
ownerPassword
- the owner passworduserPassword
- the user passwordkeyBitLength
- the key length in bits (40-128)revision
- the security handler revision- Returns:
- the O value entry
- Throws:
GeneralSecurityException
- if ciphers are unavailable or inappropriately used- See Also:
-
checkOwnerPassword
private byte[] checkOwnerPassword(byte[] ownerPassword, byte[] firstDocIdValue, int keyBitLength, int revision, byte[] oValue, byte[] uValue, int pValue, boolean encryptMetadata) throws GeneralSecurityException, EncryptionUnsupportedByProductException, PDFParseException Check to see whether a given password is the owner password. Corresponds to algorithm 3.6 of PDF Reference version 1.7.- Parameters:
ownerPassword
- the suggested owner password (may be null or empty)firstDocIdValue
- the byte stream from the first element of the value of the ID entry in the trailer dictionarykeyBitLength
- the key length in bitsrevision
- the security handler revisionoValue
- the O value from the Encrypt dictionaryuValue
- the U value from the Encrypt dictionarypValue
- the P value from the Encrypt dictionaryencryptMetadata
- the EncryptMetadata entry from the Encrypt dictionary (or false if not present or revision <= 3)- Returns:
- the general/user key bytes if the owner password is currect,
null
otherwise - Throws:
GeneralSecurityException
- if there's a problem with cipher or digest usage; unexpectedEncryptionUnsupportedByProductException
- if PDFRenderer doesn't support the security handler revisionPDFParseException
- if the document is malformed
-
getInitialOwnerPasswordKeyBytes
private byte[] getInitialOwnerPasswordKeyBytes(byte[] ownerPassword, int keyBitLength, int revision) throws GeneralSecurityException Establish the key to be used for the generation and validation of the user password via the O entry. Corresponds to steps 1-4 in Algorithm 3.3 of the PDF Reference version 1.7.- Parameters:
ownerPassword
- the owner passwordkeyBitLength
- the length of the key in bitsrevision
- the security handler revision- Returns:
- the key bytes to use for generation/validation of the O entry
- Throws:
GeneralSecurityException
- if there's a problem wranling ciphers
-
checkUserPassword
private byte[] checkUserPassword(byte[] userPassword, byte[] firstDocIdValue, int keyBitLength, int revision, byte[] oValue, byte[] uValue, int pValue, boolean encryptMetadata) throws GeneralSecurityException, EncryptionUnsupportedByProductException, PDFParseException Check to see whether a provided user password is correct with respect to an Encrypt dict configuration. Corresponds to algorithm 3.6 of the PDF Reference version 1.7- Parameters:
userPassword
- the user password to test; may be null or emptyfirstDocIdValue
- the byte stream from the first element of the value of the ID entry in the trailer dictionarykeyBitLength
- the length of the key in bitsrevision
- the security handler revisionoValue
- the O value from the Encrypt dictionaryuValue
- the U value from the Encrypt dictionarypValue
- the P value from the Encrypt dictionaryencryptMetadata
- the EncryptMetadata entry from the Encrypt dictionary (or false if not present or revision <= 3)- Returns:
- the general/user encryption key if the user password is correct, or null if incorrect
- Throws:
GeneralSecurityException
- if there's a problem with cipher or digest usage; unexpectedEncryptionUnsupportedByProductException
- if PDFRenderer doesn't support the security handler revisionPDFParseException
- if the document is improperly constructed
-
calculateGeneralEncryptionKey
private byte[] calculateGeneralEncryptionKey(byte[] userPassword, byte[] firstDocIdValue, int keyBitLength, int revision, byte[] oValue, int pValue, boolean encryptMetadata) throws GeneralSecurityException Determine what the general encryption key is, given a configuration. This corresponds to Algorithm 3.2 of PDF Reference version 1.7.- Parameters:
userPassword
- the desired user password; may be null or emptyfirstDocIdValue
- the byte stream from the first element of the value of the ID entry in the trailer dictionarykeyBitLength
- the length of the key in bitsrevision
- the security handler revisionoValue
- the O value from the Encrypt dictionarypValue
- the P value from the Encrypt dictionaryencryptMetadata
- the EncryptMetadata entry from the Encrypt dictionary (or false if not present or revision <= 3)- Returns:
- the general encryption key
- Throws:
GeneralSecurityException
- if an error occurs when obtaining and operating ciphers/digests
-
padPassword
private byte[] padPassword(byte[] password) Pad a password as per step 1 of Algorithm 3.2 of the PDF Reference version 1.7- Parameters:
password
- the password, may be null or empty- Returns:
- the padded password, always 32 bytes long
-
crypt
private byte[] crypt(Cipher cipher, byte[] input) throws IllegalBlockSizeException, BadPaddingException Encrypt some bytes- Parameters:
cipher
- the cipherinput
- the plaintext- Returns:
- the crypt text
- Throws:
BadPaddingException
- if there's bad paddingIllegalBlockSizeException
- if the block size is bad
-
initEncryption
Initialise a cipher for encryption- Parameters:
cipher
- the cipherkey
- the encryption key- Throws:
InvalidKeyException
- if the key is invalid for the cipher
-
rc4shuffle
Shuffle some input using a series of RC4 encryptions with slight mutations of an given key per iteration. Shuffling happens in place. Refer to the documentation of the algorithm steps where this is called.- Parameters:
shuffle
- the bytes to be shuffledkey
- the original keyrc4
- the cipher to use- Throws:
GeneralSecurityException
- if there's a problem with cipher operation
-
rc4unshuffle
Reverse therc4shuffle(byte[], byte[], javax.crypto.Cipher)
operation, and the operation that invariable preceeds it, thereby obtaining an original message- Parameters:
rc4
- the RC4 cipher to useshuffle
- the bytes in which shuffling will take place; unshuffling happens in placekey
- the encryption key- Throws:
GeneralSecurityException
- if there's a problem with cipher operation
-
cryptInPlace
private void cryptInPlace(Cipher rc4, byte[] buffer) throws IllegalBlockSizeException, ShortBufferException, BadPaddingException Encrypt/decrypt something in place- Parameters:
rc4
- the cipher to use; must be a stream cipher producing identical output length to input (e.g., RC4)buffer
- the buffer to read input from and write output to- Throws:
IllegalBlockSizeException
- if an inappropriate cipher is usedShortBufferException
- if an inappropriate cipher is usedBadPaddingException
- if an inappropriate cipher is used
-
initDecryption
Setup a cipher for decryption- Parameters:
cipher
- the cipheraKey
- the cipher key- Throws:
InvalidKeyException
- if the key is of an unacceptable size or doesn't belong to the cipher
-
createRC4Cipher
Create a new RC4 cipher. Should always be available for supported platforms.- Returns:
- the cipher
- Throws:
NoSuchAlgorithmException
- if the RC4 cipher is unavailableNoSuchPaddingException
- should not happen, as no padding is specified
-
createAESCipher
Create a new AES cipher. Should always be available for supported platforms.- Returns:
- the new cipher
- Throws:
NoSuchAlgorithmException
- if the AES cipher is unavailableNoSuchPaddingException
- if the required padding is unavailable
-
createMD5Digest
Create an MD5 digest. Should always be available for supported platforms.- Returns:
- the MD5 digest
- Throws:
NoSuchAlgorithmException
- if the digest is not available
-
createRC4Key
Create an RC4 key- Parameters:
keyBytes
- the bytes for the key- Returns:
- the key
-
digestTo
Hash into an existing byte array- Parameters:
md5
- the MD5 digesthash
- the hash destination- Throws:
GeneralSecurityException
- if there's a problem hashing; e.g., if the buffer is too small
-