The importance of randomness in authentication
Last Update: 2023-04-16
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 and therefor not cryptographically secure, it can be more easily brute forced.
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;
}
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 or 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 ± 1 Minutes, when it was generated.
Your lucky API-Key is:
Took seconds to guess the API-Key with
requests and 0.1 seconds between each request.
Hash not found!