A hash function to effectively create a secure and unique password for each service.
- Secure
ISAAC has very strong avalanche effects: every unknown tiny change of its initial state can cause unpredictable output, therefore it is resistant to brute force attack and pre-calculated attack, and hasn't be proven any vulnerabilities for more than 30 years. This hash function implements ISAAC.
- Customizable
In hash.js, you are encouraged to customize your secret 256-bit salt. It mitigates the risks that your passwords being cracked by preventing pre-calculated attack. I've also developed a tool to generate it.
seed(isaac.state, binaryStringToArray(decompose(yourSalt)));
- Lightweight
The size of this extension is about 30 kB.
- Logless
It doesn't use localStorage or produce any logs. ISAAC uses deterministic algorithm, so your password can be retrieved with correct keys whenever you wish.
- Cross-platform
It is an Chromium extension, and it workable on desktop devices or Android with Kiwi Browser or Lemur Browser.
When you click on the icon of this extension, it shows a distraction-free tiny pop-up.

There're two input bars. One is mainKey, and another is siteKey.
For example, if you want to generate/retrieve your Facebook password, you should enter correct mainKey and siteKey that align with your registration setup. Those keys are as important as your derived passwords, so they shouldn't be guessable by others, which means you should evaluate their strength yourself. Those keys can be either mnemonic or you can log them elsewhere physically or digitally secure.
- How is each
passworddetermined
hash is a hash function that implements ISAAC.
function derivePassword(mainKey, siteKey) {
const hashedSiteKey = simpleHash(siteKey);
const combinedKey = hashedSiteKey + mainKey;
return simpleHash(combinedKey);
}
As above,
password = hash(mainKey + hash(siteKey)).
- How is
hashdesigned
function simpleHash(input) {
const binaryString = decompose(input);
// Convert the binary string to an array
const binaryArray = binaryStringToArray(binaryString);
// Create an instance of the ISAAC PRNG
const isaac = new ISAAC();
// Seed the PRNG with yourSalt
seed(isaac.state, binaryStringToArray(decompose('yourSalt')));
// Seed the PRNG with the input key
seed(isaac.state, binaryArray);
// Generate a hash by taking five 4-byte integers and converting them to hexadecimal
let hash = '';
for (let i = 0; i < 5; i++) {
const randNum = isaac.rand();
const hexRandNum = randNum.toString(16).padStart(8, '0');
hash += hexRandNum;
}
return hash; // `hash` is a 160-bit hexadecimal
}
As above, when you enter a key string, each character will be transformed into unicode, and be decomposed into 21-bit binary string with decompose. Then those binary strings will be combined together into one.
seed will change the internal state of ISAAC with mix or isaac, dependent on each bit consecutively.
function decompose(str) {
let binaryString = '';
// Iterate over the characters in the string
for (let i = 0; i < str.length; i++) {
let unicodeValue = str.charCodeAt(i);
// Convert the Unicode value to a binary string and pad it to 21 bits
let binaryValue = unicodeValue.toString(2).padStart(21, '0');
// Append the binary value to the binary string
binaryString += binaryValue;
}
return binaryString;
}
function seed(state, arr) {
for (let i = 0; i < arr.length; i++) {
if (arr[i] === 0) {
// If the value is 0, perform one iteration of the PRNG mixing step
mix(state); // Corrected: Pass the state object
} else {
// Otherwise, refresh the random state
isaac(state); // Corrected: Pass the state object
}
}
}
// Function to convert a binary string to an array
function binaryStringToArray(binaryString) {
return binaryString.split('').map(char => parseInt(char, 10));
}
- References
[1]. Code of ISAAC
[2]. ISAAC's theory written by the author
[3]. Rosetta Code
[4]. Wikipedia
If you are using it, please backup yourself, because future updates are possible.