Class StandardDecrypter

  • All Implemented Interfaces:
    PDFDecrypter

    public class StandardDecrypter
    extends java.lang.Object
    implements 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 Classes 
      Modifier and Type Class Description
      static class  StandardDecrypter.EncryptionAlgorithm
      Describes an encryption algorithm to be used, declaring not only the cipher type, but also key generation techniques
    • Field Summary

      Fields 
      Modifier and Type Field Description
      private static byte[] AESV2_SALT
      Extra salt to add to AES-based decryption keys, as per PDF Reference 1.7
      private static java.lang.String CIPHER_AES
      The specification of the AES cipher for JCE interactions.
      private static java.lang.String CIPHER_RC4
      The specification of the RC4 cipher for JCE interactions
      private StandardDecrypter.EncryptionAlgorithm encryptionAlgorithm
      The encryption algorithm being employed
      private byte[] generalKeyBytes
      The general encryption key; may be mutated to form individual stream/string encryption keys
      private static java.lang.String KEY_AES
      The key type for AES keys
      private static java.lang.String KEY_RC4
      The key type for RC4 keys
      private boolean ownerAuthorised
      Whether the owner password was specified
      private static byte[] PW_PADDING
      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.
    • Method Summary

      All Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      private 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 javax.crypto.Cipher createAESCipher()
      Create a new AES cipher.
      private javax.crypto.Cipher createAndInitialiseContentCipher​(java.nio.ByteBuffer encrypted, byte[] decryptionKeyBytes)
      Setup the cipher for decryption
      private java.security.MessageDigest createMD5Digest()
      Create an MD5 digest.
      private javax.crypto.Cipher createRC4Cipher()
      Create a new RC4 cipher.
      private javax.crypto.spec.SecretKeySpec createRC4Key​(byte[] keyBytes)
      Create an RC4 key
      private byte[] crypt​(javax.crypto.Cipher cipher, byte[] input)
      Encrypt some bytes
      private void cryptInPlace​(javax.crypto.Cipher rc4, byte[] buffer)
      Encrypt/decrypt something in place
      java.nio.ByteBuffer decryptBuffer​(java.lang.String cryptFilterName, PDFObject streamObj, java.nio.ByteBuffer streamBuf)
      Decrypt a buffer of data
      private java.nio.ByteBuffer decryptBuffer​(java.nio.ByteBuffer encrypted, byte[] decryptionKeyBytes)
      Decrypt a buffer
      java.lang.String decryptString​(int objNum, int objGen, java.lang.String inputBasicString)
      Decrypt a basic string.
      private void digestTo​(java.security.MessageDigest md5, byte[] hash)
      Hash into an existing byte array
      private 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 so
      private int getSaltedContentKeyByteLength()
      Get the length of a salted key
      private int getSaltedContentKeyByteLength​(int generalKeyByteLength)
      Get the length of salted keys, in bytes.
      private byte[] getUnsaltedDecryptionKey()
      Get the unsalted content decryption key, used for streams with specific crypt filters, which aren't specific to particular objects
      private void initDecryption​(javax.crypto.Cipher cipher, java.security.Key aKey)
      Setup a cipher for decryption
      private void initEncryption​(javax.crypto.Cipher cipher, javax.crypto.SecretKey key)
      Initialise a cipher for encryption
      boolean isEncryptionPresent()
      Determine whether this actually applies a decryption other than identity decryption.
      boolean isOwnerAuthorised()
      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.7
      private void rc4shuffle​(byte[] shuffle, byte[] key, javax.crypto.Cipher rc4)
      Shuffle some input using a series of RC4 encryptions with slight mutations of an given key per iteration.
      private void rc4unshuffle​(javax.crypto.Cipher rc4, byte[] shuffle, byte[] key)
      Reverse the rc4shuffle(byte[], byte[], javax.crypto.Cipher) operation, and the operation that invariable preceeds it, thereby obtaining an original message
      private 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.
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Field Detail

      • AESV2_SALT

        private static final byte[] AESV2_SALT
        Extra salt to add to AES-based decryption keys, as per PDF Reference 1.7
      • PW_PADDING

        private static final byte[] PW_PADDING
        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.
      • CIPHER_RC4

        private static final java.lang.String CIPHER_RC4
        The specification of the RC4 cipher for JCE interactions
        See Also:
        Constant Field Values
      • KEY_RC4

        private static final java.lang.String KEY_RC4
        The key type for RC4 keys
        See Also:
        Constant Field Values
      • CIPHER_AES

        private static final java.lang.String 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:
        Constant Field Values
      • KEY_AES

        private static final java.lang.String KEY_AES
        The key type for AES keys
        See Also:
        Constant Field Values
      • ownerAuthorised

        private boolean ownerAuthorised
        Whether the owner password was specified
      • generalKeyBytes

        private byte[] generalKeyBytes
        The general encryption key; may be mutated to form individual stream/string encryption keys
    • Constructor Detail

      • StandardDecrypter

        public StandardDecrypter​(StandardDecrypter.EncryptionAlgorithm encryptionAlgorithm,
                                 PDFObject documentId,
                                 int keyBitLength,
                                 int revision,
                                 byte[] oValue,
                                 byte[] uValue,
                                 int pValue,
                                 boolean encryptMetadata,
                                 PDFPassword password)
                          throws java.io.IOException,
                                 EncryptionUnsupportedByProductException,
                                 EncryptionUnsupportedByPlatformException
        Class constructor
        Parameters:
        encryptionAlgorithm - the algorithm used for encryption
        documentId - 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 128
        revision - 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 dictionary
        uValue - the value of the U entry from the Encrypt dictionary
        pValue - the value of the P entry from the Encrypt dictionary
        encryptMetadata - whether metadata is being encrypted, as identified by the Encrypt dict (with default true if not explicitly identified)
        password - the password; not null
        Throws:
        java.io.IOException - if there's a problem reading the file
        EncryptionUnsupportedByPlatformException - if the encryption is not supported by the environment in which the code is executing
        EncryptionUnsupportedByProductException - if PDFRenderer does not currently support the specified encryption
    • Method Detail

      • decryptBuffer

        public java.nio.ByteBuffer decryptBuffer​(java.lang.String cryptFilterName,
                                                 PDFObject streamObj,
                                                 java.nio.ByteBuffer streamBuf)
                                          throws PDFParseException
        Description copied from interface: PDFDecrypter
        Decrypt a buffer of data
        Specified by:
        decryptBuffer in interface PDFDecrypter
        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 java.lang.String decryptString​(int objNum,
                                              int objGen,
                                              java.lang.String inputBasicString)
                                       throws PDFParseException
        Description copied from interface: PDFDecrypter
        Decrypt a basic string.
        Specified by:
        decryptString in interface PDFDecrypter
        Parameters:
        objNum - the object number of the containing object
        objGen - the generation number of the containing object
        inputBasicString - 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 with PDFDecrypter.isEncryptionPresent() to determine whether any permissions apply.
        Specified by:
        isOwnerAuthorised in interface PDFDecrypter
        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 interface PDFDecrypter
        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 lengths
        PDFParseException - if there's an internal error while testing cipher availability
      • decryptBuffer

        private java.nio.ByteBuffer decryptBuffer​(java.nio.ByteBuffer encrypted,
                                                  byte[] decryptionKeyBytes)
                                           throws PDFParseException
        Decrypt a buffer
        Parameters:
        encrypted - the encrypted content
        decryptionKeyBytes - 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 javax.crypto.Cipher createAndInitialiseContentCipher​(java.nio.ByteBuffer encrypted,
                                                                     byte[] decryptionKeyBytes)
                                                              throws PDFParseException,
                                                                     java.security.NoSuchAlgorithmException,
                                                                     javax.crypto.NoSuchPaddingException,
                                                                     java.security.InvalidKeyException,
                                                                     java.security.InvalidAlgorithmParameterException
        Setup the cipher for decryption
        Parameters:
        encrypted - the encrypted content; required by AES encryption so that the initialisation vector can be established
        decryptionKeyBytes - 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 error
        java.security.NoSuchAlgorithmException - if the cipher algorithm is not supported by the platform
        javax.crypto.NoSuchPaddingException - if the cipher padding is not supported by the platform
        java.security.InvalidKeyException - if the key is invalid according to the cipher, or too long
        java.security.InvalidAlgorithmParameterException - 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

        private byte[] getObjectSaltedDecryptionKey​(int objNum,
                                                    int objGen)
                                             throws PDFParseException
        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 number
        objGen - 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 as generalKeyBytes
        Parameters:
        generalKeyByteLength - the length of the general key, in bytes
        Returns:
        byte length of salted keys
      • checkNums

        private void checkNums​(int objNum,
                               int objGen)
                        throws PDFParseException
        Check that object number and object generations are well-formed. It is possible for some PDFObjects to have uninitialised object numbers and generations, but such objects should not required decryption
        Parameters:
        objNum - the object number
        objGen - 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 java.security.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 key
        firstDocIdValue - the value of the first element in the document's ID entry in the trailer dictionary
        revision - the revision of the security handler
        Returns:
        the U value for the given configuration
        Throws:
        java.security.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 java.security.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 password
        userPassword - the user password
        keyBitLength - the key length in bits (40-128)
        revision - the security handler revision
        Returns:
        the O value entry
        Throws:
        java.security.GeneralSecurityException - if ciphers are unavailable or inappropriately used
        See Also:
        checkOwnerPassword(byte[], byte[], int, int, byte[], byte[], int, boolean)
      • checkOwnerPassword

        private byte[] checkOwnerPassword​(byte[] ownerPassword,
                                          byte[] firstDocIdValue,
                                          int keyBitLength,
                                          int revision,
                                          byte[] oValue,
                                          byte[] uValue,
                                          int pValue,
                                          boolean encryptMetadata)
                                   throws java.security.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 dictionary
        keyBitLength - the key length in bits
        revision - the security handler revision
        oValue - the O value from the Encrypt dictionary
        uValue - the U value from the Encrypt dictionary
        pValue - the P value from the Encrypt dictionary
        encryptMetadata - 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:
        java.security.GeneralSecurityException - if there's a problem with cipher or digest usage; unexpected
        EncryptionUnsupportedByProductException - if PDFRenderer doesn't support the security handler revision
        PDFParseException - if the document is malformed
      • getInitialOwnerPasswordKeyBytes

        private byte[] getInitialOwnerPasswordKeyBytes​(byte[] ownerPassword,
                                                       int keyBitLength,
                                                       int revision)
                                                throws java.security.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 password
        keyBitLength - the length of the key in bits
        revision - the security handler revision
        Returns:
        the key bytes to use for generation/validation of the O entry
        Throws:
        java.security.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 java.security.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 empty
        firstDocIdValue - the byte stream from the first element of the value of the ID entry in the trailer dictionary
        keyBitLength - the length of the key in bits
        revision - the security handler revision
        oValue - the O value from the Encrypt dictionary
        uValue - the U value from the Encrypt dictionary
        pValue - the P value from the Encrypt dictionary
        encryptMetadata - 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:
        java.security.GeneralSecurityException - if there's a problem with cipher or digest usage; unexpected
        EncryptionUnsupportedByProductException - if PDFRenderer doesn't support the security handler revision
        PDFParseException - 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 java.security.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 empty
        firstDocIdValue - the byte stream from the first element of the value of the ID entry in the trailer dictionary
        keyBitLength - the length of the key in bits
        revision - the security handler revision
        oValue - the O value from the Encrypt dictionary
        pValue - the P value from the Encrypt dictionary
        encryptMetadata - the EncryptMetadata entry from the Encrypt dictionary (or false if not present or revision <= 3)
        Returns:
        the general encryption key
        Throws:
        java.security.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​(javax.crypto.Cipher cipher,
                             byte[] input)
                      throws javax.crypto.IllegalBlockSizeException,
                             javax.crypto.BadPaddingException
        Encrypt some bytes
        Parameters:
        cipher - the cipher
        input - the plaintext
        Returns:
        the crypt text
        Throws:
        javax.crypto.BadPaddingException - if there's bad padding
        javax.crypto.IllegalBlockSizeException - if the block size is bad
      • initEncryption

        private void initEncryption​(javax.crypto.Cipher cipher,
                                    javax.crypto.SecretKey key)
                             throws java.security.InvalidKeyException
        Initialise a cipher for encryption
        Parameters:
        cipher - the cipher
        key - the encryption key
        Throws:
        java.security.InvalidKeyException - if the key is invalid for the cipher
      • rc4shuffle

        private void rc4shuffle​(byte[] shuffle,
                                byte[] key,
                                javax.crypto.Cipher rc4)
                         throws java.security.GeneralSecurityException
        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 shuffled
        key - the original key
        rc4 - the cipher to use
        Throws:
        java.security.GeneralSecurityException - if there's a problem with cipher operation
      • rc4unshuffle

        private void rc4unshuffle​(javax.crypto.Cipher rc4,
                                  byte[] shuffle,
                                  byte[] key)
                           throws java.security.GeneralSecurityException
        Reverse the rc4shuffle(byte[], byte[], javax.crypto.Cipher) operation, and the operation that invariable preceeds it, thereby obtaining an original message
        Parameters:
        rc4 - the RC4 cipher to use
        shuffle - the bytes in which shuffling will take place; unshuffling happens in place
        key - the encryption key
        Throws:
        java.security.GeneralSecurityException - if there's a problem with cipher operation
      • cryptInPlace

        private void cryptInPlace​(javax.crypto.Cipher rc4,
                                  byte[] buffer)
                           throws javax.crypto.IllegalBlockSizeException,
                                  javax.crypto.ShortBufferException,
                                  javax.crypto.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:
        javax.crypto.IllegalBlockSizeException - if an inappropriate cipher is used
        javax.crypto.ShortBufferException - if an inappropriate cipher is used
        javax.crypto.BadPaddingException - if an inappropriate cipher is used
      • initDecryption

        private void initDecryption​(javax.crypto.Cipher cipher,
                                    java.security.Key aKey)
                             throws java.security.InvalidKeyException
        Setup a cipher for decryption
        Parameters:
        cipher - the cipher
        aKey - the cipher key
        Throws:
        java.security.InvalidKeyException - if the key is of an unacceptable size or doesn't belong to the cipher
      • createRC4Cipher

        private javax.crypto.Cipher createRC4Cipher()
                                             throws java.security.NoSuchAlgorithmException,
                                                    javax.crypto.NoSuchPaddingException
        Create a new RC4 cipher. Should always be available for supported platforms.
        Returns:
        the cipher
        Throws:
        java.security.NoSuchAlgorithmException - if the RC4 cipher is unavailable
        javax.crypto.NoSuchPaddingException - should not happen, as no padding is specified
      • createAESCipher

        private javax.crypto.Cipher createAESCipher()
                                             throws java.security.NoSuchAlgorithmException,
                                                    javax.crypto.NoSuchPaddingException
        Create a new AES cipher. Should always be available for supported platforms.
        Returns:
        the new cipher
        Throws:
        java.security.NoSuchAlgorithmException - if the AES cipher is unavailable
        javax.crypto.NoSuchPaddingException - if the required padding is unavailable
      • createMD5Digest

        private java.security.MessageDigest createMD5Digest()
                                                     throws java.security.NoSuchAlgorithmException
        Create an MD5 digest. Should always be available for supported platforms.
        Returns:
        the MD5 digest
        Throws:
        java.security.NoSuchAlgorithmException - if the digest is not available
      • createRC4Key

        private javax.crypto.spec.SecretKeySpec createRC4Key​(byte[] keyBytes)
        Create an RC4 key
        Parameters:
        keyBytes - the bytes for the key
        Returns:
        the key
      • digestTo

        private void digestTo​(java.security.MessageDigest md5,
                              byte[] hash)
                       throws java.security.GeneralSecurityException
        Hash into an existing byte array
        Parameters:
        md5 - the MD5 digest
        hash - the hash destination
        Throws:
        java.security.GeneralSecurityException - if there's a problem hashing; e.g., if the buffer is too small