1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
# Implementation
Adapted from [source](https://spectre.app/blog/2018-01-06-algorithm/).
## User Key Derivation
([code](user_key.go))
A user's key should be generated at "construction" time of a potential client. The user key derivation step is the
longer part of the generation and should be separated from the cheaper site key and password generation steps.
### Variables
* `user_name`
* `user_secret`
### Steps
1. `user_name` as byte slice
2. `user_secret` as byte slice
3. `key_scope` ([Authentication](#scopes)) as byte slice
4. `key_salt` = `key_scope` + `len(user_name)` (big endian) + `user_name`
5. `user_key` = `scrypt(password = user_secret, salt = key_salt, N = 32768, r = 8, p = 2, key_length = 64)`
Store the `user_key` for use later.
## Site Key Generation
([code](site_key.go))
The site key generation step is part of getting a password and is used against a [template](#templates).
### Variables
* `site_name`
* `counter`
* [`scope`](#scopes)
### Steps
1. `site_name` as byte slice
2. `scope` as byte slice
3. `key_salt` = `scope` + `len(site_name)` (big endian) + `site_name` + `counter` (big endian)
4. `site_key` = `HMAC-SHA256(key = user_key, data = key_salt)`
## Site Password Generation
([code](site_password.go))
### Variables
* `site_name`
* `counter` (default is `1`)
* `scope` (default is [Authentication](#scopes))
* `template_type` (default is [based on scope](#scopes))
### Steps
1. `site_key` as byte slice
2. `template_set` = `templates[ template_type ]` ([templates](#templates))
3. `template` = `template_set[ site_key[0] % len(template_set) ]`
4. for each character `b` in the template (`loop_index` starting at `0`)
1. `chars` = `characters[ b ]` ([characters](#characters))
2. `char` = `chars[ site_key[ loop_index + 1 ] % len(chars) ]`
3. add `char` to output string
## Walkthrough
* `user_name` = `Robert Lee Mitchell`
* `user_secret` = `banana colored duckling`
* `scope` = [Authentication](#scopes)
* `counter` = `1`
* `template` = [Long](#scopes)
* `site_name` = `masterpasswordapp.com`
### User Key
```text
[24 76 42 206 37 187 113 129 122 202 164 134 75 113 147 21 177 89 17 50 52 178 162 191 86 144 232 125 103 172 42 251 195 72 15 109 194 103 28 206 230 240 192 133 230 226 64 32 195 166 175 242 54 123 217 242 58 194 205 104 168 74 95 194]
```
### Site Key
```text
[18 27 156 216 202 205 54 139 226 53 64 140 63 35 242 105 24 249 162 30 135 30 0 50 101 141 213 27 212 150 120 210]
```
### Site Password
`Jejr5[RepuSosp`
## Appendix
### Scopes
([code](scope.go))
Scopes are chosen by a user (default **Authentication**) to denote what type of password they need.
|Scope|Value|Default Template|
|:---:|:---:|:---:|
|Authentication|`com.lyndir.masterpassword`|Long|
|Identification|`com.lyndir.masterpaswword.login`|Name|
|Recovery|`com.lyndir.masterpassword.answer`|Phrase|
**NOTE:** One difference in my implementations compared to the original is allowing consumers to choose
their own "scoper", some interface that can respond to the three scopes with whatever response they choose.
**This means that any custom implementation will not return the same results, so keep that in mind when using
a service.**
### Templates
([code](template.go))
Template sets are used when generating a password, each character relates to a corresponding set in [characters](#characters).
|Template|Sets|
|:---:|:---:|
|Maximum| `["anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno"]`|
|Long|`["CvcvnoCvcvCvcv", "CvcvCvcvnoCvcv", "CvcvCvcvCvcvno", "CvccnoCvcvCvcv", "CvccCvcvnoCvcv", "CvccCvcvCvcvno", "CvcvnoCvccCvcv", "CvcvCvccnoCvcv", "CvcvCvccCvcvno", "CvcvnoCvcvCvcc", "CvcvCvcvnoCvcc", "CvcvCvcvCvccno", "CvccnoCvccCvcv", "CvccCvccnoCvcv", "CvccCvccCvcvno", "CvcvnoCvccCvcc", "CvcvCvccnoCvcc", "CvcvCvccCvccno", "CvccnoCvcvCvcc", "CvccCvcvnoCvcc", "CvccCvcvCvccno"]`|
|Medium|`["CvcnoCvc", "CvcCvcno"]`|
|Short|`["Cvcn"]`|
|Pin|`["nnnn"]`|
|Name|`["cvccvcvcv"]`|
|Phrase|`["cvcc cvc cvccvcv cvc", "cvc cvccvcvcv cvcv", "cv cvccv cvc cvcvccv"]`|
|Basic|`["aaanaaan", "aannaaan", "aaannaaa"]`|
### Characters
([code](template.go))
Characters are sets of characters used in a [Template](#templates).
|Symbol|Set|
|:---:|:---:|
|V|`AEIOU`|
|C|`BCDFGHJKLMNPQRSTVWXYZ`|
|v|`aeiou`|
|c|`bcdfghjklmnpqrstvwxyz`|
|A|`AEIOUBCDFGHJKLMNPQRSTVWXYZ`|
|a|`AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz`|
|n|`0123456789`|
|o|`@&%?,=[]_:-+*$#!'^~;()/.`|
|x|`AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()`|
|(literal space)|` `|
|