Add XKCD Password entropy tester
This commit is contained in:
parent
9f6fb1a2c5
commit
cc7a8fce86
1 changed files with 243 additions and 0 deletions
243
2025.xkcd-password-strength.html
Normal file
243
2025.xkcd-password-strength.html
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>Password Entropy calculator</title>
|
||||
<style>
|
||||
html {
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
}
|
||||
body {
|
||||
margin: 3em 1em;
|
||||
}
|
||||
form {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 2rem 1rem;
|
||||
}
|
||||
input[type=range] {
|
||||
display: block;
|
||||
}
|
||||
|
||||
label[id] > output {
|
||||
font-size: 2rem;
|
||||
display: block;
|
||||
border: 1px solid lightseagreen;
|
||||
background-color: lightgreen;
|
||||
padding: 0.5rem;
|
||||
overflow: auto;
|
||||
white-space: nowrap;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
fieldset > label {
|
||||
display: flex;
|
||||
gap: 0.25em;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
fieldset input {
|
||||
display: inline-block;
|
||||
transform: translateY(0.15em);
|
||||
}
|
||||
|
||||
footer {
|
||||
color: gray;
|
||||
font-size: small;
|
||||
margin-top: 3em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.standard > label:has(#common-words),
|
||||
.standard > label:has(#common-words-pool),
|
||||
.standard > label:has(#dictionary-pool),
|
||||
.xkcd-symbols > label:has(#lowercase-latin-letters),
|
||||
.xkcd-symbols > label:has(#uppercase-latin-letters),
|
||||
.xkcd-symbols > label:has(#digits),
|
||||
.xkcd-symbols > label:has(#special-chars),
|
||||
.xkcd-symbols > label:has(#special-chars-pool),
|
||||
.xkcd-symbols > label:has(#dictionary-pool),
|
||||
.xkcd-dictionary > label:has(#common-words),
|
||||
.xkcd-dictionary > label:has(#special-chars-pool),
|
||||
.xkcd-dictionary > label:has(#common-words-pool) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
grid-column: 1 / 4;
|
||||
}
|
||||
|
||||
small {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
b {
|
||||
cursor: help;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>XKCD Password strength demo</h1>
|
||||
<form class="standard">
|
||||
<fieldset>
|
||||
<legend>Formel</legend>
|
||||
<label>
|
||||
<input type="radio" checked value="standard" id="formula-standard" name="formula">
|
||||
<span>Standard (<code>log2(urval^längd)</code>)</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" value="xkcd-dictionary" id="formula-xkcd-dictionary" name="formula">
|
||||
<span>XKCD uppslagsord + extra versaler, gemener eller specialtecken (<code>log2(65000*urval*urval)</code>)</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" value="xkcd-symbols" id="formula-xkcd-symbols" name="formula">
|
||||
<span>XKCD symboler av vanliga ord (<code>log2(urval*antal)</code>)</span>
|
||||
</label>
|
||||
</fieldset>
|
||||
<label id="length">
|
||||
Lösenordslängd
|
||||
<output>
|
||||
|
||||
</output>
|
||||
</label>
|
||||
<label id="entropy">
|
||||
Lösenordsentropi
|
||||
<output>
|
||||
|
||||
</output>
|
||||
</label>
|
||||
<label id="brute-force-estimate">
|
||||
Brute force max <b title="1000 försök per sekund">?</b>
|
||||
<output>
|
||||
|
||||
</output>
|
||||
</label>
|
||||
<label>
|
||||
<input type="range" step="1" max="50" value="0" id="lowercase-latin-letters" name="lowercase-latin-letters">
|
||||
Latinska gemener <small>(a-z)</small>: <output></output>
|
||||
</label>
|
||||
<label>
|
||||
<input type="range" step="1" max="50" value="0" id="uppercase-latin-letters" name="uppercase-latin-letters">
|
||||
Latinska versaler <small>(A-Z)</small>: <output></output>
|
||||
</label>
|
||||
<label>
|
||||
<input type="range" step="1" max="50" value="0" id="digits" name="digits">
|
||||
Siffror <small>(0-9)</small>: <output></output>
|
||||
</label>
|
||||
<label>
|
||||
<input type="range" step="1" max="50" value="0" id="special-chars" name="special-chars">
|
||||
"Specialtecken" <small>(inkl Å, Ä och Ö)</small>: <output></output>
|
||||
</label>
|
||||
<label>
|
||||
<input type="range" step="1" max="50" value="30" id="special-chars-pool" name="special-chars-pool">
|
||||
Specialteckensurval: <output>30</output>
|
||||
</label>
|
||||
<label>
|
||||
<input type="range" step="1" max="10" value="0" id="common-words" name="common-words">
|
||||
Vanliga ord: <output></output>
|
||||
</label>
|
||||
<label>
|
||||
<input type="range" step="128" max="4096" value="2048" id="common-words-pool" name="common-words-pool">
|
||||
Vanliga ord-urval: <output>2048</output>
|
||||
</label>
|
||||
<label>
|
||||
<input type="range" step="1000" max="100000" value="65000" id="dictionary-pool" name="dictionary-pool">
|
||||
Uppslagsordsurval: <output>65000</output>
|
||||
</label>
|
||||
</form>
|
||||
<footer>
|
||||
<p>
|
||||
Baserad på <a href="https://www.omnicalculator.com/other/password-entropy#password-entropy-is-not-all-that-matters">Omni Password Entropy Calculator</a>
|
||||
men modifierad för att verifiera <a href="https://www.explainxkcd.com/wiki/index.php/936:_Password_Strength">XKCD 936</a>.
|
||||
<br>Skapad okt 2025 av <a href="https://madr.se">madr</a>
|
||||
</p>
|
||||
</footer>
|
||||
<script>
|
||||
(function(G){
|
||||
const $v = (id) => parseInt(document.getElementById(id).value, 10);
|
||||
const inputs = document.querySelectorAll("input");
|
||||
const lengthOutput = document.querySelector("#length > output");
|
||||
const entropyOutput = document.querySelector("#entropy > output");
|
||||
const bruteforceEstimateOutput = document.querySelector("#brute-force-estimate > output");
|
||||
let mode = "standard";
|
||||
|
||||
calcBFE = (entropy) => {
|
||||
let bfe = (2**entropy) / 1000
|
||||
if (bfe < 1.0) {
|
||||
return "<1s"
|
||||
}
|
||||
if (bfe < 60.0) {
|
||||
return `~ ${Math.round(bfe)} sek`
|
||||
}
|
||||
bfe = bfe / 60
|
||||
if (bfe < 60.0) {
|
||||
return `~ ${Math.round(bfe)} min`
|
||||
}
|
||||
bfe = bfe / 60
|
||||
if (bfe < 24.0) {
|
||||
return `~ ${Math.round(bfe)} tim`
|
||||
}
|
||||
bfe = bfe / 24
|
||||
if (bfe < 7.0) {
|
||||
return `~ ${Math.round(bfe)} dgr`
|
||||
}
|
||||
bfe = bfe / 7
|
||||
if (bfe < 52.0) {
|
||||
return `~ ${Math.round(bfe)} v`
|
||||
}
|
||||
bfe = bfe * 7 / 30
|
||||
if (bfe < 12.0) {
|
||||
return `~ ${Math.round(bfe)} mån`
|
||||
}
|
||||
bfe = bfe * 30 / 365
|
||||
if (bfe < 100.0) {
|
||||
return `~ ${Math.round(bfe)} år`
|
||||
}
|
||||
return "> 100 år"
|
||||
}
|
||||
|
||||
const calcEntropy = ({target: elm}) => {
|
||||
if (elm.type == "range") {
|
||||
elm.parentNode.querySelector("output").innerHTML = elm.value;
|
||||
} else {
|
||||
elm.form.className = elm.value;
|
||||
mode = elm.value;
|
||||
}
|
||||
let a, b, entropy;
|
||||
const c = 27 * !!$v("lowercase-latin-letters") + 27 * !!$v("uppercase-latin-letters") + 10 * !!$v("digits") + 30 * !!$v("special-chars");
|
||||
if (mode != "xkcd-symbols" && !c) {
|
||||
lengthOutput.innerHTML = " ";
|
||||
entropyOutput.innerHTML = " ";
|
||||
bruteforceEstimateOutput.innerHTML = " ";
|
||||
return;
|
||||
}
|
||||
if (mode == "standard") {
|
||||
a = c;
|
||||
b = $v("special-chars") + $v("digits") + $v("uppercase-latin-letters") + $v("lowercase-latin-letters");
|
||||
entropy = Math.floor(Math.log2(a**b));
|
||||
} else if (mode == "xkcd-dictionary") {
|
||||
a = $v("dictionary-pool");
|
||||
b = c;
|
||||
entropy = Math.floor(Math.log2(a*b*b));
|
||||
} else if (mode == "xkcd-symbols") {
|
||||
a = $v("common-words-pool");
|
||||
b = $v("common-words");
|
||||
entropy = Math.floor(Math.log2(a**b));
|
||||
}
|
||||
const passwordLength = (mode != "standard") ? "*" : $v("special-chars") + $v("digits") + $v("uppercase-latin-letters") + $v("lowercase-latin-letters");
|
||||
lengthOutput.innerHTML = "";
|
||||
lengthOutput.insertAdjacentHTML("afterbegin", passwordLength);
|
||||
entropyOutput.innerHTML = "";
|
||||
entropyOutput.insertAdjacentHTML("afterbegin", entropy);
|
||||
bruteforceEstimateOutput.innerHTML = "";
|
||||
bruteforceEstimateOutput.insertAdjacentHTML("afterbegin", calcBFE(entropy));
|
||||
};
|
||||
|
||||
inputs.forEach(function(elm) {
|
||||
elm.onchange = (e) => calcEntropy(e)
|
||||
})
|
||||
}(this))
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Reference in a new issue