Class BCryptPasswordImpl

    • Field Detail

      • hash

        private final byte[] hash
      • salt

        private final byte[] salt
      • iterationCount

        private final int iterationCount
      • Parray

        private static final int[] Parray
      • Sboxes

        private static final int[] Sboxes
      • orpheanBeholderScryDoubt

        private static final int[] orpheanBeholderScryDoubt
      • zeroedSalt

        private static final byte[] zeroedSalt
    • Method Detail

      • getHash

        public byte[] getHash()
        Description copied from interface: BCryptPassword
        Get the hash segment of this password.
        Specified by:
        getHash in interface BCryptPassword
        Returns:
        the hash segment
      • getSalt

        public byte[] getSalt()
        Description copied from interface: BCryptPassword
        Get the salt segment of this password.
        Specified by:
        getSalt in interface BCryptPassword
        Returns:
        the salt segment
      • getIterationCount

        public int getIterationCount()
        Description copied from interface: BCryptPassword
        Get the iteration count of this password.
        Specified by:
        getIterationCount in interface BCryptPassword
        Returns:
        the iteration count
      • bcrypt

        static byte[] bcrypt​(int cost,
                             byte[] salt,
                             byte[] password)

        Hashes the password with the given salt and cost using the bcrypt algorithm. The algorithm is defined as follows:

             bcrypt(cost, salt, pwd)
                 state <- eksBlowfishSetup(cost, salt, pwd)
                 ctext <- "OrpheanBeholderScryDoubt"
                 repeat(64)
                     ctext <- EncryptECB(state, ctext)
                 return Concatenate(cost, salt, ctext)
         

        This implementation differs from the above algorithm in that it returns the encrypted ctext in its raw form. The ModularCrypt class can be used to obtain the hashed password in its crypt string format (i.e. $2a$cost$encodedSaltencodedPassword).

        It is important to note that bcrypt has a limitation when it comes to the password size: only the first 72 bytes of the password are involved in the key schedule phase, so large keys that share the same first 72 bytes will produce the same hash.

        Parameters:
        cost - the cost of the bcrypt algorithm. It represents the log value of the number of rounds to be applied. Thus, a cost value of 6 means that a total of 2^6 = 64 rounds will be applied, while a cost value of 20 means that a total of 2^20 = 1.048.576 rounds will be applied. It must be a value between 4 and 31 (inclusive).
        salt - the 128-bit salt to be used. It is represented by a 16-byte array.
        password - the password to be hashed, in its byte array form.
        Returns:
        a byte[] containing the hashed password.
      • eksBlowfishSetup

        private static BCryptPasswordImpl.BCryptState eksBlowfishSetup​(int cost,
                                                                       byte[] salt,
                                                                       byte[] key)

        Performs the Blowfish expensive key schedule setup. This phase is defined as follows:

             eksBlowfishSetup(cost, salt, key)
                 state <- InitState();
                 state <- expandKey(state, salt, key)
                 repeat(2^cost)
                     state <- expandKey(state, 0, key)
                     state <- expandKey(state, 0, salt)
                 return state
         

        Parameters:
        cost - the cost of the bcrypt algorithm. It represents the log value of the number of rounds to be applied. Thus, a cost value of 6 means that a total of 2^6 = 64 rounds will be applied, while a cost value of 20 means that a total of 2^20 = 1.048.576 rounds will be applied. It must be a value between 4 and 31 (inclusive).
        salt - the 128-bit salt to be used. It is represented by a 16-byte array.
        key - the password being hashed, in its byte array form.
      • expandKey

        private static void expandKey​(BCryptPasswordImpl.BCryptState state,
                                      byte[] salt,
                                      byte[] key)

        Performs the expandKey step in the expensive key schedule setup. This step is defined as follows:

             expandKey(state, salt, key)
                 for(n = 1..18)
                     P[n] <- key[32(n-1)..32n-1] ^ P[n] // treat key as cyclic.
                 ctext <- encrypt(salt[0..63])
                 P[0] <- ctext[0..31]
                 P[1] <- ctext[32..63]
                 for(n = 1..8)
                     ctext <- encrypt(ctext ^ salt[64(n-1)..64n-1]) // encrypt using the current key schedule and treat the salt as cyclic.
                     P[2n] <- ctext[0..31]
                     P[2n+1] <- ctext[32..63]
                 for(i = 1..4]
                     for(n = 0..127]
                         ctext <- encrypt(ctext ^ salt[64(n-1)..64n-1]) // as above
                         Si[2n] <- ctext[0..31]
                         Si[2n+1] <- ctext[32..63]
                 return state;
         

        Parameters:
        state - the current bcrypt state (P-array and S-boxes).
        salt - the 128-bit salt to be used. It is represented by a 16-byte array.
        key - the password being hashed, in its byte array form.
      • encrypt

        private static void encrypt​(BCryptPasswordImpl.BCryptState state,
                                    int[] value)

        Encrypt splits 64-bit blocks into two 32-bit halves, left and right. The most significant half (left) is xored with subkey P[0] and used as input for function F (Feistel substitution). The result of that function is xored with the least significant half (right). The halves are then swapped and the process repeats for a total of 16 times:

             L0 <- block[0..31]
             R0 <- block[32..63]
        
             for(i = 1..16)
                 Ri <- Li-1 ^ P[i-1]
                 Li <- Ri-1 ^ F(Ri)
         

        After 16 rounds the halves are swapped again and xored with the final two subkeys:

             R17 <- L16 ^ P[16]
             L17 <- R16 ^ P[17]
         

        This method takes the 64-bit blocks as pairs of integers (32-bits each) in the value parameter and encrypts each pair separately. Encryption happens in place - i.e. the encrypted values are written back to the incoming array, replacing the previous values.

        Parameters:
        state - the current bcrypt state (P-array and S-boxes).
        value - a int[] containing the 32-bit pairs that must be encrypted.
      • writeReplace

        Object writeReplace()