correcthorsebatterystaple/src/index.ejs
2022-12-30 18:12:17 -05:00

260 lines
14 KiB
Plaintext

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Correct Horse Battery Staple: xkcd-Style Password Generator</title>
</head>
<body data-spy="scroll" data-target="nav" data-offset="72">
<nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
<div class="container">
<a class="navbar-brand" href="#">Correct Horse Battery <span class="staple">Staple</span></a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#nav-anchors"
aria-controls="nav-anchors" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="nav-anchors">
<ul class="nav navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="#generator">Password Generator</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#idea">Idea</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#faq">FAQ</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container" id="generator">
<div class="jumbotron py-4">
<div class="alert alert-danger" id="too-old">
<%= require('octicons').alert.toSVG({ height: 24 }) %>
Your browser is too old: it does not support the necessary APIs for this web application.
</div>
<p class="lead">This is a truly secure password generator that generates xkcd-style easy-to-remember passwords.</p>
<hr class="my-4">
<div class="input-group mb-3">
<div id="generated-password" class="form-control form-control-lg text-monospace placeholder">
Click the Generate button to generate a new password</div>
<div class="input-group-append">
<button class="btn btn-success copy" type="button" id="copy-password"
data-clipboard-target="#generated-password" disabled>
<%= require('octicons').clippy.toSVG({ height: 20 }) %>
</button>
</div>
</div>
<div class="progress my-3" id="password-bits">
<div class="progress-bar" role="progressbar" aria-valuemin="0"></div>
</div>
<form id="options-form">
<div class="form-group row">
<label for="word-list" class="col-sm-2 col-form-label">Word List</label>
<div class="col-sm-10">
<select id="word-list" class="form-control custom-select" name="list">
<option value="small">2048 words (11 bits/word)</option>
<option value="medium">4096 words (12 bits/word)</option>
<option value="large" selected>8192 words (13 bits/word)</option>
</select>
</div>
</div>
<div class="form-group row">
<label for="word-count" class="col-sm-2 col-form-label">Word Count</label>
<div class="col-sm-10">
<input id="word-count" class="form-control" type="number" name="count" value="4" min="1">
</div>
</div>
<div class="form-group row">
<div class="pt-0 col-sm-2 col-form-label">Options</div>
<div class="col-sm-10">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="use-capitalize" name="capitalize">
<label for="use-capitalize">Capitalize the first letter</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="use-symbol" name="symbol" checked>
<label for="use-symbol">Use separator symbol:</label>
<select id="separator-symbol" name="separator">
<% [...require('./generator').symbols].forEach(symbol => { %>
<option<% if (symbol === ' ') { %> value=" "<% } %>><%= _.escape(symbol) %></option>
<% }) %>
</select>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="use-digit" name="digit">
<label for="use-digit">Add a digit</label>
</div>
</div>
</div>
<div>
<button class="btn btn-lg my-1 btn-primary" id="run-generator">Generate</button>
<button class="btn btn-lg my-1 btn-success" id="save-settings">Save Settings</button>
<button class="btn btn-lg my-1 btn-danger" id="clear-settings">Clear Settings</button>
</div>
</form>
</div>
</div>
<div class="container mb-5" id="idea">
<h3 class="mb-3">The Idea</h3>
<p class="lead">We tend to associate secure passwords with complicated and hard-to-remember passwords. But it
doesn't have to be this way.</p>
<p>We make password difficult to guess by increasing <em>entropy</em> &mdash; the degree of uncertainty in the
password. The higher the entropy, the harder it is to guess the password.</p>
<p>One way of increasing entropy is to make passwords more complicated. Another way is to make the password
longer, but keeping it simple, as the following xkcd comic shows:</p>
<a class="d-block" href="https://xkcd.com/936/"
title="To anyone who understands information theory and security and is in an infuriating argument with someone who does not (possibly involving mixed case), I sincerely apologize.">
<figure class="figure border rounded p-4 bg-light">
<img class="figure-img img-fluid d-block mx-auto p-2 bg-white border border-dark rounded"
src="<%= require('./xkcd.png') %>" srcset="<%= require('./xkcd.png') %>, <%= require('./xkcd_2x.png') %> 2x" alt="xkcd comic about password strength">
<figcaption class="figure-caption">To anyone who understands information theory and security and is in an
infuriating argument with someone who does not (possibly involving mixed case), I sincerely apologize.
</figcaption>
</figure>
</a>
<p>The core idea is that while using a <em>single</em> dictionary word as a password is horribly insecure and can be
cracked in seconds, each <em>additional</em> word makes cracking exponentially harder.</p>
<p>There is a lot of criticism on the internet about this password scheme. However, most of them fail to get the
actual point. There are also claims that <code>correcthorsebatterystaple</code> is as secure as a 9 character
password, which sounds fairly bad. This is true if your 9 character password is truly random, such as
<code>n98idhi3n</code>, and not say, <code>Tr0ub4d0r</code>. The point is that,
<code>correcthorsebatterystaple</code> is more memorable than <code>n98idhi3n</code>, for approximately equal
security. To increase security, we can always add more words.</p>
<p class="lead"><span class="mark">5 words from the large list</span>, or <span class="mark">6 words
from the small list</span> is sufficient for all reasonable threats.</p>
<p>Let us consider the absolute worst case, assuming the attacker knows your password is generated by this site,
knowing that it has 65 bits of entropy, your password was insecurely hashed, and your enemy has GPUs to run
<span class="mark">500 billion attempts every second</span>. Even then, this scheme will resist the
cracking attempt for <em>over a year</em>.</p>
<p>Running this sort of attack is <em>prohibitively expensive</em>. Unless you possess highly valuable secrets that
makes this sort of effort worthwhile (you should use something more secure than passwords in such a case), you don't
have to worry about this hypothetical scenario. If you have to, you can simply add more words.</p>
<p class="lead">In practice, most real life systems use secure password hashing algorithms, captchas, and other
mechanisms to stop password cracking. It is unlikely that your attacker can reach anywhere close to a million
guesses a second, and so a <span class="mark">four word password</span> (from the large list) is probably sufficient
in real life. If you are paranoid and want to feel better, use five.</p>
</div>
<div class="container mb-5" id="faq">
<h3 class="mb-3">Frequently Asked Questions</h3>
<div class="card">
<div class="card-body">
<h5 class="card-title">Why did you make this website?</h5>
<p class="card-text">
I made this website because I wanted a good password generator. I know the xkcd-style password scheme is fairly
secure and easy to remember, especially if you increase the length, and it's simple enough to understand and
verify. Most programmers can audit the source code of this website to ensure security.
</p>
<p class="card-text">
Another major part of the reason is that a lot of the similar websites fail to generate passwords securely: for
example, they used <code>Math.random()</code>, which is not a cryptographically secure random number generator,
and should never be used to generate passwords. This website aims to avoid such pitfalls, and provide a truly
secure experience.
</p>
<p class="card-text">
To guarantee this experience, this website does not use any external scripts, not even analytics. Since the
entire website is aggressively cached on the Cloudflare edge servers, I have no idea who you are, or how many
of you are using it. To show your support, star
<a href="https://github.com/quantum5/correcthorsebatterystaple">the GitHub repository</a>.
</p>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title">Why is this site more secure than alternatives?</h5>
<ol>
<li>I have a large list of 8192 words.</li>
<li>All passwords are generated on your computer. No one else will see it.</li>
<li>I use <a href="https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues">
<code>window.crypto.getRandomValues()</code></a> &mdash; the only cryptographically-secure random number
generator in JavaScript, instead of
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random">
<code>Math.random()</code></a>, whose use is explicitly discouraged for this purporse.
</li>
<li>The source code is available on <a href="https://github.com/quantum5/correcthorsebatterystaple">GitHub</a>.
You can audit the code all you want, and build your own trusted version locally.
</li>
</ol>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title">I like this website. How can I support you?</h5>
<p class="card-text">
For security reasons, this website will <b>NEVER</b> serve ads. Unfortunately, servers and domains are not free,
though I try to be as economical as I can. I would rather lose money running this public service than serve
ads or shut it down, but if you would like to help me offset the costs, feel free to send some money my way
on:
</p>
<ul>
<li><a href="https://github.com/sponsors/quantum5">GitHub Sponsors</a></li>
</ul>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title">Bruce Schneier says this password scheme is broken. Is it?</h5>
<p class="card-text">
Bruce Schneier completely missed the point:
</p>
<blockquote class="blockquote">
<p class="card-text">Modern password crackers combine different words from their dictionaries:</p>
<p class="card-text">&hellip;</p>
<p class="card-text">This is why the oft-cited XKCD scheme for generating passwords -- string together
individual words like "correcthorsebatterystaple" -- is no longer good advice. The password crackers are on to
this trick.</p>
<footer class="blockquote-footer">Bruce Schneier, <cite title="Source Title"><a
href="https://www.schneier.com/blog/archives/2014/03/choosing_secure_1.html" rel="nofollow">Choosing Secure
Passwords</a></cite></footer>
</blockquote>
<p class="card-text">
Excuse me, Bruce, but the entropy calculation for this password scheme is based on the absolute worst case
scenario: that the attackers knows exactly which words you have to choose from, and attempts to guess every
possible combinations from the known dictionary.
</p>
<p class="card-text">
In essence, we are assuming the attacker is <em>more than</em> <q>on to this trick</q> already. Whether
attackers are <q>on to this trick</q> is completely therefore irrelevant to its security. If Bruce
Schneier thinks using four words is insufficiently secure, he should be suggesting five or six words, not
<strong>shamelessly promoting his own password generation scheme</strong>.
</p>
<p class="card-text">
If you don&rsquo;t believe me, that&rsquo;s okay. Check out
<a href="https://security.stackexchange.com/q/62832/103593">this post on the Information Security Stack
Exchange</a>. The top four answers (with vast majority of the votes) agree with me, and they provide more
details and additional material to support xkcd-style passwords.</p>
</div>
</div>
</div>
<footer class="footer bg-light">
<div class="container">
<p class="text-muted">Copyright &copy; 2018-<%= new Date().getFullYear() %> <a href="https://quantum5.ca">Quantum</a>. Licensed under
<a href="https://www.gnu.org/licenses/agpl-3.0.en.html">GNU AGPLv3</a>. Source code available on
<a href="https://github.com/quantum5/correcthorsebatterystaple">GitHub</a>.<br>
Available on clearnet at <a href="https://correcthorse.pw">correcthorse.pw</a>.<br>
Available over Tor at <a href="http://correctpw3wmw7mw.onion">correctpw3wmw7mw.onion</a> and
<a href="http://correct2qlofpg4tjz5m7zh73lxtl7xrt2eqj27m6vzoyoqyw4d4pgyd.onion">
correct2<wbr>qlofpg4t<wbr>jz5m7zh7<wbr>3lxtl7xr<wbr>t2eqj27m<wbr>6vzoyoqy<wbr>w4d4pgyd.onion</a>.
</p>
</div>
</footer>
</body>
</html>