-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
116 lines (109 loc) · 5.8 KB
/
index.html
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
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Simple Password Backup">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Simple Password Backup</title>
</head>
<body>
<script>
/** Redacts text - allows negative and wrapping. */
function splice(str, index, count, wrap = false) {
const strlen = str.length
let add = ''.padStart(count, '█')
const indexBefore = index
const addBefore = add
if (index < 0) {
add = add.substring(-index)
index = 0;
}
count = add.length
str = str.slice(0, index) + (add || "") + str.slice(index + count);
if (wrap && str.length > strlen) {
return splice(str.substring(0, strlen), 0, str.length - strlen)
}
return str
}
let useMethod = 1
function toggleMethods() {
useMethod = useMethod === 1 ? 2 : 1
x()
}
function x() {
try {
const [a,b,c,d] = 'abcd'.split('').map(id => document.getElementById(id))
const users = parseInt(a.value)
const requiredUsers = parseInt(b.value)
const redundantUsers = users - requiredUsers
const pwd = c.value
if (pwd.length < users) throw new Error('Password must be longer than backups.')
const minUsers = Math.ceil(users / (redundantUsers + 1))
let str = ''
str += `Reconstruct using any ${requiredUsers} backups\n(OR ${minUsers} specific backups)\n`
const gaplen = requiredUsers - 1 // how long the black gap is
const pwdmodlen = pwd.length - (pwd.length % users)
const redactlen = pwdmodlen / users
switch (useMethod) {
case 1:
// method 1: redact every x-th char
const separatorlen = redundantUsers + 1 // dist between gaps (how many are required to piece it back together)
for (let i = 0; i < users; i++) {
let tmp = pwd
let x = i - gaplen
while (x < pwd.length) {
tmp = splice(tmp, x, gaplen, false)
x += gaplen + separatorlen
}
str += `\n#${(i+1+'').padEnd(2, ' ')}: ${tmp.substring(0, pwd.length)}`
}
break
case 2:
// method 2: split the password into chunks, then redact the chunks
for (let i = 0; i < users; i++) {
let x = i
let tmp = pwd.substring(0, pwdmodlen)
let remainder = pwd.substring(pwdmodlen)
while (x < tmp.length) {
tmp = splice(tmp, x * redactlen, redactlen * gaplen, true)
x += pwdmodlen
}
if (i < remainder.length) remainder = splice(remainder, i, 1, false)
str += `\n#${(i+1+'').padEnd(2, ' ')}: ${tmp + remainder}`
}
break
}
d.innerHTML = str + '\n\n'
} catch (err) {
console.log(`Error: ${err.message}`)
d.innerHTML = `Error: ${err.message}`
}
}
setTimeout(x, 100)
</script>
<style>
label,input,button,body{font-size:18px;font-family:'Times New Roman', Times, serif;}
input,button{height:35px;box-sizing: border-box;}
button{background:#ddd;border:1px solid #bbb;padding:0 15px;cursor:pointer;}
h1,p{margin-top:0;}
label{margin-top:5px;}
input{padding:5px;}
body{padding:15px;background:#eee;display:flex;flex-direction:column;gap:15px;}
pre{letter-spacing:5px;border:1px solid grey;padding:5px;margin:0;background:#FFF;min-height:100px;}
hr{background:#ddd;height:1px;width:100%;}
</style>
<h1>Simple Password Backup</h1>
<p>Split your password into multiple, partially redacted, reconstructable backups.</p>
<p>Why? Because it's simple. You can physically divide your password amongst trusted guardians without a single point of risk. You can choose your level of redundancy. It's simple to reconstruct. And it's most likely better than whatever your current master password/private key backup strategy is...</p>
<p>Is this secure? Absolutely... there are no libraries, no dependencies, no connections. The code is a single, readable, 117 lines, html file. For the security conscious, this page can be saved and run in an incognito browser, from your local disk, on an air-gapped (offline) laptop. Please disable/disconnect/isolate all screen sharing tools, key loggers, usb devices, cameras, microphones, recording devices (mobile phones, conversational AI home assistants). Ensure your screen is not visible to others. Do not read the passwords out aloud. Do not copy them using the clipboard. Close the browser when finished. Test reconstructing your password to avoid human error.</p>
<p>Recommendations: Do not store backups together, consider separating them physically, geographically, socially, etc. Do not store or transmit them digitally, use a pen and paper to record - take care not to leave imprints on surfaces. Manually distribute. Store them in a safe, secure, robust, non-corruptible, fireproof, waterproof, tamperproof container, under the guardianship of a trusted entity. Choose your own risk mitigation level: Risk = Likelihood x Impact.</p>
<hr>
<label>1. How many password backups?</label><input id="a" onkeyup="x()" autocomplete="off" placeholder="users" value="5" />
<label>2. How many backups are needed to reconstruct the password?</label><input id="b" onkeyup="x()" autocomplete="off" placeholder="numparts" value="3" />
<label>3. What is the Password?</label><input id="c" onkeyup="x()" autocomplete="off" placeholder="pwd" value="abcdefghijklm" />
<label>Redacted Passwords Output (store these separately!)</label>
<pre id="d"></pre>
<div><button onclick="toggleMethods()">Toggle redaction method</button></div>
<p>Tip: Is your redacted password guessable, or a common phrase? Consider changing it!</p>
</body>
</html>