2
0
MasterPassword/Site/2013-05/algorithm.html

394 lines
24 KiB
HTML
Raw Normal View History

2013-05-26 05:06:44 +00:00
<!DOCTYPE HTML>
<html itemscope itemtype="http://schema.org/Product">
<head>
<title itemprop="name">Master Password &mdash; Secure your life, forget your passwords.</title>
<link rel="icon" href="img/favicon.png" type="image/x-png" />
<link rel="shortcut icon" href="img/favicon.png" type="image/x-png" />
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<meta itemprop="description" content="Master Password is an ingenious password solution that makes your passwords truly impossible to lose." />
<meta itemprop="image" content="http://masterpassword.lyndir.com/img/iTunesArtwork-Rounded.png" />
<meta name="apple-itunes-app" content="app-id=510296984" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" media="screen" href="css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="css/screen.css" />
<link rel="stylesheet" type="text/css" href="css/ml-shadows.css" />
<link rel="stylesheet" type="text/css" href="css/buttons/buttons.css" />
<!-- Google Analytics -->
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-90535-15']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<!-- Get Satisfaction -->
<!--script type="text/javascript" charset="utf-8">
var is_ssl = ("https:" == document.location.protocol);
var asset_host = is_ssl ? "https://d3rdqalhjaisuu.cloudfront.net/" : "http://d3rdqalhjaisuu.cloudfront.net/";
document.write(unescape("%3Cscript src='" + asset_host + "javascripts/feedback-v2.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript" charset="utf-8">
var feedback_widget_options = {};
feedback_widget_options.display = "overlay";
feedback_widget_options.company = "lyndir";
feedback_widget_options.placement = "right";
feedback_widget_options.color = "#222";
feedback_widget_options.style = "question";
var feedback_widget = new GSFN.feedback_widget(feedback_widget_options);
</script-->
<!-- UserEcho -->
<script type='text/javascript'>
var _ues = {
host:'support.lyndir.com',
forum:'13031',
lang:'en',
tab_icon_show:false,
tab_corner_radius:5,
tab_font_size:20,
tab_image_hash:'RmVlZGJhY2s%3D',
tab_alignment:'right',
tab_text_color:'#FFFFFF',
tab_bg_color:'#DDDDDD',
tab_hover_color:'#CCCCCC'
};
(function() {
var _ue = document.createElement('script'); _ue.type = 'text/javascript'; _ue.async = true;
_ue.src = ('https:' == document.location.protocol ? 'https://s3.amazonaws.com/' : 'http://') + 'cdn.userecho.com/js/widget-1.4.gz.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(_ue, s);
})();
</script>
<!-- AdWords -->
<script type="text/javascript">
/* <![CDATA[ */
goog_snippet_vars = function() {
var w = window;
w.google_conversion_id = 1015576061;
w.google_conversion_label = "PcXqCPPz5AIQ_euh5AM";
w.google_conversion_value = 4;
}
goog_report_conversion = function(url) {
goog_snippet_vars();
window.google_conversion_format = "3";
window.google_is_call = true;
var opt = new Object();
opt.onload_callback = function() {
if (typeof(url) != 'undefined') {
window.location = url;
}
}
var conv_handler = window['google_trackConversion'];
if (typeof(conv_handler) == 'function') {
conv_handler(opt);
}
}
/* ]]> */
</script>
<script type="text/javascript" src="http://www.googleadservices.com/pagead/conversion_async.js"></script>
<!-- Google +1 -->
<script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script>
</head>
<body itemscope itemtype="http://schema.org/MobileSoftwareApplication" id="algorithm">
<nav class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="brand" href="./">●●●|</a>
<div class="nav-collapse collapse">
<ul class="nav">
<li><a href="./">App</a></li>
<li class="active"><a href="algorithm.html">Algorithm</a></li>
<li><a href="http://github.com/Lyndir/MasterPassword">Source</a></li>
</ul>
<ul class="nav pull-right">
<li class="divider-vertical"></li>
<li><a href="MasterPassword_PressKit.zip" onclick="_gaq.push(['_trackPageview', '/outbound/presskit']);">⬇ Press Kit</a></li>
<li><a href="http://itunes.apple.com/app/id510296984" onclick="goog_report_conversion('index-fixed-header');_gaq.push(['_trackPageview', '/outbound/itunes']);" class="img"><img src="img/appstore.svg" /></a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</div>
</nav>
<header><div class="content">
<!-- <div class="box effect-8">
iframe id="ytplayer" type="text/html" width="640" height="360" frameborder="0"
src="http://www.youtube.com/embed/QTfA0O7YnHQ?origin=http://masterpassword.lyndir.com&autohide=1&autoplay=0&rel=0&showinfo=0&theme=light&color=white"></iframe
<iframe width="640" height="360" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen
src="http://player.vimeo.com/video/45803664?title=0&amp;byline=0&amp;portrait=0&amp;color=ffffff"></iframe>
</div> -->
<h2>The Master Password Algorithm</h2>
</div></header>
<section><div class="content">
<div class="thumb container">
<p><b>Master Password is <em>an algorithm used to generate unique passwords</em></b> for websites, email accounts, or anything else <em>based only on easily reproducible input</em>.<br />
The goal is a process that avoids all the problems involved with other password solutions.</p>
<h1>The Password Problem</h1>
<img class="pull-right" src="img/thumb-authenticate.png" />
<p>Passwords are used to authenticate you to someone else. That means, convince someone that you really are who you say you are. The theory is that when you two are the only ones that know a certain secret word, then the other party can be certain of your identity when you prove to them you know the secret word.</p>
<p>Authentication using passwords is pretty good in theory but fails when the password is either:
<ul>
<li>Easily guessed by an impersonator.</li>
<li>Known by others.</li>
</ul>
</p>
<p>So the only way to do passwords right is by inventing a secure (ie. hard to guess) and unique (ie. different for each site) password each time.</p>
<p>Unfortunately, secure passwords are hard to come up with and even harder to remember.</p>
<p>People generally give up and begin reusing passwords between sites. The password is now no longer secret. This can lead to your identity getting stolen when sites get hacked, you get conned by a hoax site, or you sign up with an untrustworthy website.</p>
<h1>Password Solutions</h1>
<p>To help with these problems, there are a bunch of apps available that remember your passwords for you. They accomplish this by saving your passwords in an encrypted vault or by sending them off to a cloud server.</p>
<p>These approaches are very helpful, but they come with a few very <em>important</em> downsides:
<ul>
<li>Vaults need to be backed-up to avoid the risk of complete identity loss.</li>
<li>Vaults need to be kept nearby and in-sync across the your devices or you won't always be able to access the password you need.</li>
<li>Sending passwords to the cloud means handing your keys to a company.</li>
<li>When your passwords are in the cloud they may not be available when you have no Internet access.</li>
</ul>
</p>
<h1>Solving Availability</h1>
<p>Losing all your passwords or other password availability issues are frustrating and sometimes even disastrous.</p>
<p>Master Password solves this problem by being a <em>stateless</em> solution. That means that no information needs to be saved in order for the program to be able to give you your password again in the future.</p>
<p>Since Master Password doesn't save your passwords and doesn't send them anywhere, it avoids the following risks:
<ul>
<li>Your passwords cannot be found in a file.</li>
<li>Your passwords cannot be intercepted during transport.</li>
<li>You don't need to trust a third party with your secrets.</li>
<li>You can't lose your passwords.</li>
</ul>
</p>
</div>
<div class="thumb container">
<img class="pull-left" src="img/thumb-process-black.png" />
<h1>How Does It Work?</h1>
<p>The user is expected to remember the following information:
<ul>
<li>Their <strong>full name</strong> (eg. <em>Robert Lee Mitchell</em>):<br />
This is a salt for the master key generation.</li>
<li>Their personal <strong>master password</strong> (eg. <em>pink fluffy door frame</em>):<br />
This is the secret for the master key generation.</li>
<li><strong>The site name</strong> (eg. <em>apple.com</em>):<br />
The user chooses a name for each site. The bare domain name is an ideal choice.</li>
<li><strong>The site's password counter</strong> (default: <em>0</em>):<br />
This is an integer that can be incremented when the user needs a new password for the site.</li>
<li><strong>The site's password type</strong> (default: <em>Long Password</em>):<br />
This type determines the format of the output password. It can be changed if the site's password policy does not accept passwords of this format.</li>
</ul>
</p>
<p>In practice, the secret master password is the only extra thing users will actually need to remember. Their full name, they'll hopefully remember regardless. If the site is always named after the bare domain name, it needn't explicitly be remembered but can be found in the browser's address bar. The counter and type need only be remembered if they are changed from their default values.</p>
<p>In short, the algorithm involves the following steps:
<ol>
<li>Calculate the <strong>master key</strong> from a user's name and master password.</li>
<li>Calculate the <strong>template seed</strong> from the site's name and counter.</li>
<li>Encode a <strong>site password</strong> using the site's type template.</li>
</ol>
</p>
<h1>The Master Key</h1>
<p>The master <code>key</code> is a 64-byte secret key generated by performing expensive key derivation using the user's master password salted by their full name. It represents the user's global secret.</p>
<p>The purpose of this process is to deter any attempts at brute-forcing a user's master password from a known site password. The key derivation is done using the <a href="http://www.tarsnap.com/scrypt.html" onclick="_gaq.push(['_trackPageview', '/outbound/tarsnap.com/scrypt.html">scrypt</a> algorithm, which guarantees that the process sufficiently time- and resource-consuming to make brute-forcing an infeasible attack.</p>
<p>The key derivation is salted by the user's full name to prevent the generation of rainbow tables on the algorithm. This salt is not secret, and the user's full name is chosen because it is an input of sufficiently high entropy while being (hopefully) impossible to forget by the user.</p>
<pre>key = scrypt( P, S, N, r, p, dkLen )
where
P = master password
S = "com.lyndir.masterpassword" . name length . name
N = 32768
r = 8
p = 2
dkLen = 64</pre>
<h1>The Template Seed</h1>
<p>With the master <code>key</code> known, we can proceed to calculate a template <code>seed</code> for the site. The template <code>seed</code> is essentially the site-specific secret in binary form.</p>
<p>To generate the template <code>seed</code>, we construct an authentication code for the site's <code>name</code> and <code>counter</code> using the user's master <code>key</code>.</p>
<p>We employ the <a href="https://tools.ietf.org/html/rfc4868">HMAC-SHA-256</a> algorithm to obtain a large enough <code>seed</code> for the encoding step that follows.</p>
<pre>seed = hmac-sha256( key, "com.lyndir.masterpassword" . site name length . site name . counter )</pre>
<h1>The Site Password</h1>
<p>The template <code>seed</code> is a site-specific secret for our user, but it's in a binary form which is not useful as a password. To convert this byte string into a password, we need to encode it as a string of characters.</p>
<p>We have two additional problems that need to be solved: The output password should be easy for a user to read from a screen and type using a keyboard or smartphone. Additionally, it should also be compatible with most site's password policies. These policies often restrict the kind of passwords users can assign to their accounts in an attempt to foil bad password habits but often have the opposite effect, especially on secure passwords. Commonly, they are a side-effect of a site's bad password handling (eg. storing clear-text passwords in a database).</p>
<p>Master Password addresses these problems by introducing password type templates. Each password type describes what an output password must look like and maps to a set of <code>templates</code>. Templates describe the resulting output password using a series of character groups mappings.</p>
<p>
By default, Master Password uses the <em>Long Password</em> type for any new passwords. The user is able to choose a different password type, which is normally only done if the site's password policy is incompatible with the output password produced by this type.
</p>
<p>
To create the output password, the bytes in the template <code>seed</code> are encoded according to the <code>template</code>. The first <code>seed</code> byte is used to determine which of the type's templates to use for encoding an output password. We take the byte value of the first <code>seed</code> byte modulo the amount of <code>templates</code> set for the chosen password type and use the result as a zero-based index in the <code>templates</code> list for the password type.
</p>
<pre>templates = [ "CvcvCvcvnoCvcv", "CvcvnoCvcvCvcv", "CvcvCvcvCvcvno", ... ]
template = templates[ seed[0] % count( templates ) ]</pre>
<p>
Now that we know what <code>template</code> to use for building our output password, all that's left is to iterate the <code>template</code>, and produce a character of password output for each step. When we iterate the <code>template</code> (index <code>i</code>), we look in the character group identified by the character (string <code>passChars</code>) in the <code>template</code> at index <code>i</code>.
</p>
<p>
We use the <code>seed</code>'s byte value at index <code>i + 1</code> modulo the amount of characters in the character class to determine which character (<code>passChar</code>) in the class to use for the output password at index <code>i</code>.
</p>
<pre>passChar = passChars[ seed[i + 1] % count( passChars ) ]
passWord[i] = passChar</pre>
<p>The result is an encoded <code>passWord</code> string that contains the password generated for the site, such as:</p>
<h2 class="text-center well well-large">CuzaSasy3*Rimo</h2>
<h1>Password Type Templates</h1>
<p>
Master Password defines the following password types and their templates:
<ul>
<li><p>
Type: <strong>Maximum Security Password</strong>
<ul>
<li><code>anoxxxxxxxxxxxxxxxxx</li></code>
<li><code>axxxxxxxxxxxxxxxxxno</li></code>
</ul>
</p></li>
<li><p>Type: <strong>Long Password</strong>
<ul>
<li><code>CvcvnoCvcvCvcv</li></code>
<li><code>CvcvCvcvnoCvcv</li></code>
<li><code>CvcvCvcvCvcvno</li></code>
<li><code>CvccnoCvcvCvcv</li></code>
<li><code>CvccCvcvnoCvcv</li></code>
<li><code>CvccCvcvCvcvno</li></code>
<li><code>CvcvnoCvccCvcv</li></code>
<li><code>CvcvCvccnoCvcv</li></code>
<li><code>CvcvCvccCvcvno</li></code>
<li><code>CvcvnoCvcvCvcc</li></code>
<li><code>CvcvCvcvnoCvcc</li></code>
<li><code>CvcvCvcvCvccno</li></code>
<li><code>CvccnoCvccCvcv</li></code>
<li><code>CvccCvccnoCvcv</li></code>
<li><code>CvccCvccCvcvno</li></code>
<li><code>CvcvnoCvccCvcc</li></code>
<li><code>CvcvCvccnoCvcc</li></code>
<li><code>CvcvCvccCvccno</li></code>
<li><code>CvccnoCvcvCvcc</li></code>
<li><code>CvccCvcvnoCvcc</li></code>
<li><code>CvccCvcvCvccno</li></code>
</ul>
</p></li>
<li><p>Type: <strong>Medium Password</strong>
<ul>
<li><code>CvcnoCvc</code></li>
<li><code>CvcCvcno</code></li>
</ul>
</p></li>
<li><p>Type: <strong>Short Password</strong>
<ul>
<li><code>Cvcn</code></li>
</ul>
</p></li>
<li><p>Type: <strong>Basic Password</strong>
<ul>
<li><code>aaanaaan</code></li>
<li><code>aannaaan</code></li>
<li><code>aaannaaa</code></li>
</ul>
</p></li>
<li><p>Type: <strong>PIN</strong>
<ul>
<li><code>nnnn</code></li>
</ul>
</p></li>
</ul>
</p>
<p>
Where each of the letters above expand any of the characters in their respective character group:
<ul>
<li><p>Template character: <code>V</code>
<ul>
<li><code>AEIOU</code></li>
</ul>
</p></li>
<li><p>Template character: <code>C</code>
<ul>
<li><code>BCDFGHJKLMNPQRSTVWXYZ</code></li>
</ul>
</p></li>
<li><p>Template character: <code>v</code>
<ul>
<li><code>aeiou</code></li>
</ul>
</p></li>
<li><p>Template character: <code>c</code>
<ul>
<li><code>bcdfghjklmnpqrstvwxyz</code></li>
</ul>
</p></li>
<li><p>Template character: <code>A</code> (<code>= V . C</code>)
<ul>
<li><code>AEIOUBCDFGHJKLMNPQRSTVWXYZ</code></li>
</ul>
</p></li>
<li><p>Template character: <code>a</code> (<code>= V . v . C . c</code>)
<ul>
<li><code>AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz</code></li>
</ul>
</p></li>
<li><p>Template character: <code>n</code>
<ul>
<li><code>0123456789</code></li>
</ul>
</p></li>
<li><p>Template character: <code>o</code>
<ul>
<li><code>@&amp;%?,=[]_:-+*$#!'^~;()/.</code></li>
</ul>
</p></li>
<li><p>Template character: <code>X</code> (<code>= a . n . o</code>)
<ul>
<li><code>AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789@&amp;%?,=[]_:-+*$#!'^~;()/.</code></li>
</ul>
</p></li>
</ul>
</p>
</div>
</div></section>
<footer><div class="muted content">
<p><em>Master Password is a security product and algorithm by <a href="http://www.lhunath.com">Maarten Billemont</a>, <a href="http://www.lyndir.com">Lyndir</a>.</em></p>
<p><a href="http://gorillas.lyndir.com">Gorillas</a><a href="http://deblock.lyndir.com">DeBlock</a><a href="http://github.com/Lyndir">GitHub</a></p>
</div></footer>
<script src="http://code.jquery.com/jquery.js"></script>
<script src="js/bootstrap.min.js"></script>
</body>
</html>