# ** Functions/symbols ** # ** Exponential # % Modulus # ^ XOR two strings # || Concatenate two strings # swap Swaps the values of two variables # zeros(N) Creates a N byte string of zeros # pad(string, N) Pads a string with zeros to N bytes # truncate(string, N) Truncates a string to N bytes # split(string, N) Splits a string into an array of N byte strings # LE_32_TO_STR Converts a 32 bit little endian integer to a 4 byte string # STR_TO_LE_32 Converts the first 4 bytes of a string into a 32 bit little endian integer # aes_5_rounds_encrypt Does 5 standard rounds of AES with static key "00010203...0e0f" # ** Inputs ** string password string salt string secret integer t_cost integer m_cost integer outlen # ** Algorithm ** state_size = 64 * m_cost INPUT_BLOCKS = 32 INPUT_SIZE = 12 * INPUT_BLOCKS # Initialize temp = LE_32_TO_STR(inlen) || LE_32_TO_STR(saltlen) || LE_32_TO_STR(secretlen)|| LE_32_TO_STR(t_cost) || LE_32_TO_STR(m_cost) || LE_32_TO_STR(outlen) || truncate(in, 256) || truncate(salt, 32) || truncate(secret,16) input = split(pad(temp, INPUT_SIZE), 12) # Fill state for i = 0 to state_size - 1 state[i] = aes_5_rounds_encrypt(input[i % INPUT_BLOCKS] || LE_32_TO_STR(i)) # Main loop for i = 0 to t_cost - 1 state = sub_groups(state, state_size) # Shuffle slices for s = 0 to 31 j = 0 for k = 0 to state_size / 32 - 1 j = j + STR_TO_LE_32(state[32 * k + s]) j = j % (state_size / 32) swap(state[32 * k + s], state[32 * j + s]) # Finish state = sub_groups(state, state_size) out1 = zeros(16) out2 = zeros(16) for i = 0 to state_size / 2 - 1 out1 = out1 ^ state[i] out2 = out2 ^ state[i + state_size / 2] if outlen <= 16 out = out1 ^ out2 out = aes_5_rounds_encrypt(out) out = aes_5_rounds_encrypt(out) out = aes_5_rounds_encrypt(out) out = aes_5_rounds_encrypt(out) out = out ^ out1 ^ out2 else temp = out1 temp = aes_5_rounds_encrypt(temp) temp = aes_5_rounds_encrypt(temp) temp = aes_5_rounds_encrypt(temp) temp = aes_5_rounds_encrypt(temp) out = temp ^ out1 temp = out2 temp = aes_5_rounds_encrypt(temp) temp = aes_5_rounds_encrypt(temp) temp = aes_5_rounds_encrypt(temp) temp = aes_5_rounds_encrypt(temp) out = out || (temp ^ out2) return truncate(out, outlen) # ** Helper functions ** sub_groups(state, state_size) for i = 0 to state_size - 1 step 32 X[ 0] = state[i+ 3] ^ state[i+ 7] ^ state[i+11] ^ state[i+15] ^ state[i+19] ^ state[i+23] ^ state[i+27] ^ state[i+31] X[ 1] = state[i+ 1] ^ state[i+ 3] ^ state[i+ 9] ^ state[i+11] ^ state[i+17] ^ state[i+19] ^ state[i+25] ^ state[i+27] X[ 2] = state[i+ 0] ^ state[i+ 2] ^ state[i+ 4] ^ state[i+ 6] ^ state[i+16] ^ state[i+18] ^ state[i+20] ^ state[i+22] X[ 3] = state[i+ 1] ^ state[i+ 3] ^ state[i+ 5] ^ state[i+ 7] ^ state[i+ 9] ^ state[i+11] ^ state[i+13] ^ state[i+15] X[ 4] = state[i+ 6] ^ state[i+ 7] ^ state[i+14] ^ state[i+15] ^ state[i+22] ^ state[i+23] ^ state[i+30] ^ state[i+31] X[ 5] = state[i+10] ^ state[i+11] ^ state[i+14] ^ state[i+15] ^ state[i+26] ^ state[i+27] ^ state[i+30] ^ state[i+31] X[ 6] = state[i+16] ^ state[i+17] ^ state[i+20] ^ state[i+21] ^ state[i+24] ^ state[i+25] ^ state[i+28] ^ state[i+29] X[ 7] = state[i+12] ^ state[i+13] ^ state[i+14] ^ state[i+15] ^ state[i+28] ^ state[i+29] ^ state[i+30] ^ state[i+31] X[ 8] = state[i+ 4] ^ state[i+ 5] ^ state[i+ 6] ^ state[i+ 7] ^ state[i+12] ^ state[i+13] ^ state[i+14] ^ state[i+15] X[ 9] = state[i+16] ^ state[i+17] ^ state[i+18] ^ state[i+19] ^ state[i+20] ^ state[i+21] ^ state[i+22] ^ state[i+23] X[10] = state[i+ 1] ^ state[i+ 5] ^ state[i+ 9] ^ state[i+13] ^ state[i+17] ^ state[i+21] ^ state[i+25] ^ state[i+29] X[11] = state[i+ 2] ^ state[i+ 6] ^ state[i+10] ^ state[i+14] ^ state[i+18] ^ state[i+22] ^ state[i+26] ^ state[i+30] X[12] = state[i+ 4] ^ state[i+ 5] ^ state[i+ 6] ^ state[i+ 7] ^ state[i+20] ^ state[i+21] ^ state[i+22] ^ state[i+23] X[13] = state[i+ 8] ^ state[i+ 9] ^ state[i+10] ^ state[i+11] ^ state[i+24] ^ state[i+25] ^ state[i+26] ^ state[i+27] X[14] = state[i+ 0] ^ state[i+ 1] ^ state[i+ 2] ^ state[i+ 3] ^ state[i+ 8] ^ state[i+ 9] ^ state[i+10] ^ state[i+11] X[15] = state[i+ 0] ^ state[i+ 4] ^ state[i+ 8] ^ state[i+12] ^ state[i+16] ^ state[i+20] ^ state[i+24] ^ state[i+28] for j = 0 to 15 temp = aes_5_rounds_encrypt(X[j]) state[i+2*j ] = aes_5_rounds_encrypt(state[i+2*j ] ^ temp) state[i+2*j+1] = aes_5_rounds_encrypt(state[i+2*j+1] ^ temp)