The importance of randomness in authentication

Authentication keys are machine-generated character sequences used for password resets, account deletions, API keys and other use cases. The generated random character sequence must use a secure random generator to create the key, otherwise anyone can use them.

Why?

If the attacker knows the algorithm used to generate the authentication key, which uses pseudo random numbers based on known metrics such as time.

Take for example this time-based generating algorithm:

// Additional is a parameter for additional bytes to avoid collisions. Don't
// be confused by this, its just to add to the productionness of this function.
async function generateSecretKey(additional) {

// Get current timestamp
const now = new Date();
const now_timestamp = now.getTime();

return await hashSecretKey(now_timestamp, additional);
}

async function hashSecretKey(secret_key, additional) {
if (!additional) {
additional = '';
}

// Create a hexadecimal array from it
const hexdec_string = Number(secret_key).toString(16) + additional;
const hexdec_array = Int16Array.from(hexdec_string);

// Obfuscate the data with a hashing algorithm
const byteHash = Array.from(
new Uint8Array(await crypto.subtle.digest('SHA-256', hexdec_array)));
const charHash =
byteHash.map((b) => b.toString(16).padStart(2, '0')).join('');

return charHash;
}

This generates a string like f5351e6ef49c017173cd0d3bf53b8f9ee1a128dc57fbec3a52f34b4325cf1c2b.

And the function to guess the hash:

// Guess the hash with a given estimated time when the hash was created
async function guessHash(target_hash, time_created) {
const start_time = (new Date()).getTime();

// Guess milliseconds between 2.5 min before up to 3.0 min after the estimated
// creation time
const start = time_created - 2500;
const end = time_created + 3000;

for (time = start; time <= end; ++time) {
const hash = await hashSecretKey(time);

// Imagine a http request here
let found_hash = hash === target_hash;

if (found_hash) {
const end_time = (new Date()).getTime();

return {
duration: end_time - start_time,
requests: time - start + 1
};
}
}

return false;
}

Pseudo random generators are weak against attacks guessing the seed/the original data. In this example it just particulary easy to guess the API-Key, because the time - which is kinda known - is used.

Interactive example

This example generates a hash and records the time with ± 2 Minutes, when it was generated.