Skip to content

Instantly share code, notes, and snippets.

@sdaves
Last active May 23, 2021 17:00
Show Gist options
  • Save sdaves/70384b896e858f7d7abee1678d1b3fda to your computer and use it in GitHub Desktop.
Save sdaves/70384b896e858f7d7abee1678d1b3fda to your computer and use it in GitHub Desktop.
Securely generate passwords for every service you use based on a shared master password.
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cryptopass Web</title>
<script>
//https://unpkg.com/[email protected]/lib/index.browser.bundle.iife.js
var pbkdf2Hmac=function(){"use strict";const e={"SHA-1":{outputLength:20,blockSize:64},"SHA-256":{outputLength:32,blockSize:64},"SHA-384":{outputLength:48,blockSize:128},"SHA-512":{outputLength:64,blockSize:128}};function t(...e){const t=e.reduce((e,t)=>e+t.length,0);if(!e.length)throw new RangeError("Cannot concat no arrays");const r=new Uint8Array(t);let n=0;for(const t of e)r.set(t,n),n+=t.length;return r}function r(e,t){for(let r=0;r<e.length;r++)e[r]^=t[r]}return function(n,a,o,i,s="SHA-256"){return new Promise((c,u)=>{s in e||u(new RangeError("Valid hash algorithm values are any of "+Object.keys(e))),"string"==typeof n?n=(new TextEncoder).encode(n):n instanceof ArrayBuffer?n=new Uint8Array(n):ArrayBuffer.isView(n)||u(RangeError("P should be string, ArrayBuffer, TypedArray, DataView")),"string"==typeof a?a=(new TextEncoder).encode(a):a instanceof ArrayBuffer?a=new Uint8Array(a):ArrayBuffer.isView(a)||u(RangeError("S should be string, ArrayBuffer, TypedArray, DataView")),crypto.subtle.importKey("raw",n,"PBKDF2",!1,["deriveBits"]).then(f=>{const y={name:"PBKDF2",hash:s,salt:a,iterations:o};crypto.subtle.deriveBits(y,f,8*i).then(e=>c(e),f=>{(async function(n,a,o,i,s){if(!(s in e))throw new RangeError("Valid hash algorithm values are any of "+Object.keys(e));if(!Number.isInteger(o)||o<=0)throw new RangeError("c must be a positive integer");const c=e[s].outputLength;if(!Number.isInteger(i)||i<=0||i>=(2**32-1)*c)throw new RangeError("dkLen must be a positive integer < (2 ** 32 - 1) * hLen");const u=Math.ceil(i/c),f=i-(u-1)*c,y=new Array(u);0===n.length&&(n=new Uint8Array(e[s].blockSize));n=await crypto.subtle.importKey("raw",n,{name:"HMAC",hash:{name:s}},!0,["sign"]);const w=async function(e,t){const r=await crypto.subtle.sign("HMAC",e,t);return new Uint8Array(r)};for(let e=0;e<u;e++)y[e]=await h(n,a,o,e+1);async function h(e,n,a,o){const i=await w(e,t(n,function(e){const t=new ArrayBuffer(4);return new DataView(t).setUint32(0,e,!1),new Uint8Array(t)}(o)));let s=i;for(let t=1;t<a;t++)s=await w(e,s),r(i,s);return i}return y[u-1]=y[u-1].slice(0,f),t(...y).buffer})(n,a,o,i,s).then(e=>c(e),e=>u(e))})},e=>u(e))})}}();
</script>
<script>
//https://cdn.jsdelivr.net/npm/[email protected]/base64.min.js
/**
* Minified by jsDelivr using Terser v5.3.5.
* Original file: /npm/[email protected]/base64.js
*
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
*/
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):function(){const r=e.Base64,o=t();o.noConflict=()=>(e.Base64=r,o),e.Meteor&&(Base64=o),e.Base64=o}()}("undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:this,(function(){"use strict";const e="3.6.1",t="function"==typeof atob,r="function"==typeof btoa,o="function"==typeof Buffer,n="function"==typeof TextDecoder?new TextDecoder:void 0,a="function"==typeof TextEncoder?new TextEncoder:void 0,f=[..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="],i=(e=>{let t={};return e.forEach(((e,r)=>t[e]=r)),t})(f),c=/^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/,u=String.fromCharCode.bind(String),s="function"==typeof Uint8Array.from?Uint8Array.from.bind(Uint8Array):(e,t=(e=>e))=>new Uint8Array(Array.prototype.slice.call(e,0).map(t)),d=e=>e.replace(/[+\/]/g,(e=>"+"==e?"-":"_")).replace(/=+$/m,""),l=e=>e.replace(/[^A-Za-z0-9\+\/]/g,""),h=e=>{let t,r,o,n,a="";const i=e.length%3;for(let i=0;i<e.length;){if((r=e.charCodeAt(i++))>255||(o=e.charCodeAt(i++))>255||(n=e.charCodeAt(i++))>255)throw new TypeError("invalid character found");t=r<<16|o<<8|n,a+=f[t>>18&63]+f[t>>12&63]+f[t>>6&63]+f[63&t]}return i?a.slice(0,i-3)+"===".substring(i):a},p=r?e=>btoa(e):o?e=>Buffer.from(e,"binary").toString("base64"):h,y=o?e=>Buffer.from(e).toString("base64"):e=>{let t=[];for(let r=0,o=e.length;r<o;r+=4096)t.push(u.apply(null,e.subarray(r,r+4096)));return p(t.join(""))},A=(e,t=!1)=>t?d(y(e)):y(e),b=e=>{if(e.length<2)return(t=e.charCodeAt(0))<128?e:t<2048?u(192|t>>>6)+u(128|63&t):u(224|t>>>12&15)+u(128|t>>>6&63)+u(128|63&t);var t=65536+1024*(e.charCodeAt(0)-55296)+(e.charCodeAt(1)-56320);return u(240|t>>>18&7)+u(128|t>>>12&63)+u(128|t>>>6&63)+u(128|63&t)},g=/[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g,B=e=>e.replace(g,b),x=o?e=>Buffer.from(e,"utf8").toString("base64"):a?e=>y(a.encode(e)):e=>p(B(e)),C=(e,t=!1)=>t?d(x(e)):x(e),m=e=>C(e,!0),U=/[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g,F=e=>{switch(e.length){case 4:var t=((7&e.charCodeAt(0))<<18|(63&e.charCodeAt(1))<<12|(63&e.charCodeAt(2))<<6|63&e.charCodeAt(3))-65536;return u(55296+(t>>>10))+u(56320+(1023&t));case 3:return u((15&e.charCodeAt(0))<<12|(63&e.charCodeAt(1))<<6|63&e.charCodeAt(2));default:return u((31&e.charCodeAt(0))<<6|63&e.charCodeAt(1))}},w=e=>e.replace(U,F),S=e=>{if(e=e.replace(/\s+/g,""),!c.test(e))throw new TypeError("malformed base64.");e+="==".slice(2-(3&e.length));let t,r,o,n="";for(let a=0;a<e.length;)t=i[e.charAt(a++)]<<18|i[e.charAt(a++)]<<12|(r=i[e.charAt(a++)])<<6|(o=i[e.charAt(a++)]),n+=64===r?u(t>>16&255):64===o?u(t>>16&255,t>>8&255):u(t>>16&255,t>>8&255,255&t);return n},E=t?e=>atob(l(e)):o?e=>Buffer.from(e,"base64").toString("binary"):S,v=o?e=>s(Buffer.from(e,"base64")):e=>s(E(e),(e=>e.charCodeAt(0))),D=e=>v(z(e)),R=o?e=>Buffer.from(e,"base64").toString("utf8"):n?e=>n.decode(v(e)):e=>w(E(e)),z=e=>l(e.replace(/[-_]/g,(e=>"-"==e?"+":"/"))),T=e=>R(z(e)),Z=e=>({value:e,enumerable:!1,writable:!0,configurable:!0}),j=function(){const e=(e,t)=>Object.defineProperty(String.prototype,e,Z(t));e("fromBase64",(function(){return T(this)})),e("toBase64",(function(e){return C(this,e)})),e("toBase64URI",(function(){return C(this,!0)})),e("toBase64URL",(function(){return C(this,!0)})),e("toUint8Array",(function(){return D(this)}))},I=function(){const e=(e,t)=>Object.defineProperty(Uint8Array.prototype,e,Z(t));e("toBase64",(function(e){return A(this,e)})),e("toBase64URI",(function(){return A(this,!0)})),e("toBase64URL",(function(){return A(this,!0)}))},O={version:e,VERSION:"3.6.1",atob:E,atobPolyfill:S,btoa:p,btoaPolyfill:h,fromBase64:T,toBase64:C,encode:C,encodeURI:m,encodeURL:m,utob:B,btou:w,decode:T,isValid:e=>{if("string"!=typeof e)return!1;const t=e.replace(/\s+/g,"").replace(/=+$/,"");return!/[^\s0-9a-zA-Z\+/]/.test(t)||!/[^\s0-9a-zA-Z\-_]/.test(t)},fromUint8Array:A,toUint8Array:D,extendString:j,extendUint8Array:I,extendBuiltins:()=>{j(),I()},Base64:{}};return Object.keys(O).forEach((e=>O.Base64[e]=O[e])),O}));
</script>
</head>
<style>
body {
background-color:black;
}
#root {
color:white;
text-align:center;
margin-top:20%;
}
</style>
<script>
async function generate(secret, user, domain) {
const hmac = await pbkdf2Hmac(secret, user + '@' + domain, 5000, 32)
const val = Base64.fromUint8Array(new Uint8Array(hmac))
return val.substring(0,25)
}
async function main() {
const val = await generate(prompt("Master Secret Password: \n (Can be the same across accounts, use letters, numbers, symbols, etc.)"), prompt("Site Username: \n (Example: [email protected], whatever123, etc.)"), prompt("Site Domain: \n (Example: google.com, sub.mysite.com, etc.)"))
window["root"].innerHTML=val
}
</script>
<body onload="main()">
<div id="root"></div>
</body>
</html>
#!/usr/bin/python
import os
os.system("python -m pip install PySimpleGUI pyperclip pyinstaller shortcut")
import sys, shortcut, stat, hashlib as h, base64 as b, PySimpleGUI as sg, pyperclip as p
def install():
try:
os.mkdir(os.getenv("HOME") + "/.local/share/applications")
except:
pass
name = "simplepassword.py"
s = os.stat(name)
os.chmod(name, s.st_mode | stat.S_IEXEC)
platform = sys.platform
if sys.platform.startswith("linux"):
platform = "linux"
# operating system specific imports
if platform == "win32":
from shortcut.windows import ShortCutterWindows as ShortCutter
elif platform == "linux":
from shortcut.linux import ShortCutterLinux as ShortCutter
elif platform == "darwin":
from shortcut.macos import ShortCutterMacOS as ShortCutter
else:
raise Exception("Error: '{}' platform is not supported.")
shortcutter = ShortCutter()
target_path = shortcutter.find_target(name)
shortcutter.create_desktop_shortcut(target_path)
shortcutter.create_menu_shortcut(target_path)
def generate(secret, user, domain):
val = lambda x: bytearray(map(ord, x))
hmac = h.pbkdf2_hmac("sha256", val(secret), val(f"{user}@{domain}"), 5000)
return b.b64encode(hmac)[:25].decode()
def main():
win = sg.Window(
"SimplePassword",
[
[
sg.Text("Master Secret Password:", justification="right", size=(30, 0)),
sg.Input(),
],
[
sg.Text("Site Username:", size=(30, 0), justification="right"),
sg.Input(),
],
[
sg.Text(
"Site Domain (Example: google.com):",
justification="right",
size=(30, 0),
),
sg.Input(),
],
[sg.OK(), sg.Cancel(), sg.Button("Install")],
],
)
event, values = win.read()
win.Hide()
win.close()
if event == "OK":
p.copy(generate(values[0], values[1], values[2]))
elif event == "Install":
install()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment