combine into a single file
This commit is contained in:
parent
4cf7438328
commit
6fc7af7686
9
generate.sh
Executable file
9
generate.sh
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
awk '/openpgp.min.js/ {
|
||||||
|
print "<script>"
|
||||||
|
while(getline < "openpgp.min.js") { print; }
|
||||||
|
print "</script>";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
{print}' < source.html > index.html
|
501
source.html
Normal file
501
source.html
Normal file
@ -0,0 +1,501 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Crypto test</title>
|
||||||
|
<script>
|
||||||
|
// primes used for Shamir's Secret Sharing method
|
||||||
|
const large_primes = [
|
||||||
|
// generated using `openssl prime -generate -bits XXXX`
|
||||||
|
26013800316714693659487360106106576859446408140997727416684553647485913737527506224154159131021149031471925848188633045078893861608747018494713017361294680716680118653824608236875958327849429464985041509482020024640031860838265292357141341135797263686786173873087642663969196834962111089230588045539441312239718192315305970193707150287182381185472989128205869996790062835198989400329480521790509433619234601525286972527863796466644417099290273737897696408900798080603049307089600914440953002542676566189811596585259202284000341527357607212326209139406647000473009380221243221069300299351304668072790318472314168860759n,
|
||||||
|
857908717760401559068028658471571657946962457971409672831772838172131478347791874002022287489642233226344550154381694396450325517548082259873894584140331044970735800272584620445118216897059937245611505375289737129464298159348368574296753291623038525750286800721601067857073212179030797160281838407107404517365485346611287684513259639468464324661024847873457888697657005129675229974657842151139338371647475491395012735979136039720996395370528690475711412280056729606823574306401667627041294907691260832046733641716487744410354436009830988814481031969765508301874597416407883672495852313261560858246454276556214721350976268943858089426367354584853954538642652672225376259044410283111961655958346629654520092629849280881747434464878015147446833346558198224631284779186745655600561432054875662125636368490741650406480538918284023345260994849377140284027753905909394839383458005027654353873905144604473432264691766100538256383275596227027381072806473990399132689380793925265914699099790981717613653117821763366356805273903151332410528824908772288826115814531889721492063937956352790086339017420478641853030067684757524530660412039422923461248039020640296031924795730962649482971647253342812605278174053522537678469005083063230322368259957n,
|
||||||
|
42051613837217905477400960241727065545380274896740361252119841037129963997644904836403309515887204520414200749416517639193287736259706062451367573395358363849684496293575248988025538418680386412029957484178182381151432240593315274496744810103765229589895469908719506159040264079872721605860140567817015850592209293731392557283429996122755837206428621694497004513972481761702624089712485046944785875181486670173683494560753735074714857534215562577340874184593253689347221882860128032682370551448303580873026166326616209477598115633823050505271356315102765606939581238188251426188017201674208119387531195082316347657727814189720228852856895821190143977110002317484899163610615458298668807431232965915533409795006730645822003650579406085783522341580945676873702767515032776216529999815186426798572468312778484612767864183293313962175919889121117642587107367003216269560230193299927414644382148405314244321657457811744258244133641648132587254837645775760425074420335150703811495133325689910067259365825997132274671492074028291031996763864182304862298487626724124649030861927018311749457437231768992530112593625905142762953078374132065191868729444312132857056069606705492967889716547958438389427695807386216779510341962630888856128872057908771480043568895958299369772600267102448782734788539571073496449290664924598728844493916101753048924710504101306255085153n,
|
||||||
|
27322052264104655861400818625895739654685477554826524679792026738754122220380511438339944106961637040793725280215800716381496668776752693326830296769220814390920245572522443487340023818746664748915258432280236761826174095959960275111309248890001057724297198282946508759821401819314930790341102012462960633997713885651819568388398695164955135426939874410245680599717584687234789093192982601142543049994455430191519083313400637113232929083598625381764262518180155040092149584940075560815384021169239192643469752937422155100737882216571747467883325932675103193615220851242805922054990514279884089441982540910521167503943976667483287955121976867078292157406429001021152454912499600934736020762984787628624394212157440831544670637090010733509454390804386326692137929439481287992840008268862362129093150888434364632981690378179056920818887936762708502213590636058169652723826969907527209612926232878110573241960118242777684934368488823371543242472508148893903931475976852778800935257836878044358817919613664964128635433765674577022531941967567046792184615974494283837554355291719273647759791745543196701870835078362996288636404554040877620963492616589948969674377637697017822049422859398350295396213126838342352038294438863785785965087229178419799259552701432956498283521600931650664048313199358697291493715370427944030887169645537937863883460737778953905911888098918493570017000111635315956405999740708517849365569838821154740123475069512138072349027979677684319661908884153163410254816479441406649041625436480655329755420007768187784183169370876746044924805044448454454379833182087399559734454108592699538085057337419847285316366279667816150705569595759757583783829276659314230979478463803378118547344981083307521117773175027567727271832694991086195837991631259211701912348602475899043515299103087874624411122017022243158804321645303871984840122933412767n,
|
||||||
|
1067145027806771896736348885201650520217682536144480054962414237260675149345425580833604638553254555553450516905594270310215323220554955743166747664212810667924739323286132444586240362334974379521147620858785277986492501704235616109075864067774820029277982307910523435598035747995561704315623170146250954311839861990164148352059696244492499350745811714406873325781200666772436973779301867636130559940380214236807863978216034608177339239785157816672248111313127934009323837209046997706736924517668495975505109434485814738420126604281177486651942695134987862996087141461138985819668776634974521002672548209946493421911244257865273713298997478148275323403478140262314677990602905369872165803312468468196682089866320691811138046397258988457087599252348435749995677274830713978400396535341627797619039747345374158897705020261205844349478572717354515895071536910728957016820340878297419274409311876169531912679029965314409377133968232741777449081225446017422780740487500490302760038171852724526896870578871873965885630345326776370465627249974269058549505437624688835806153923199404004072461774279546739933771154130132197816275614323408701079856017813257982040041760737088759156983414150654480336132277672003225738445285430047413304772618293704912659529766597970879313533992954211080398555794343386696810547300820057892472631379493468492846464793101134340436484985900056931089743386606670422620801925011810627958444477076039156986802351793781845354101186374167815407429459530425468169262678107647879548917515619061140983268922899874767217134251427822634346444954530041777889149673629521927949770953118691529003011591473442997897411242514693507582583074997782841646405446079405629601243085143096158590569547732987594487737452587151639703336174965339982813747174020001083084219324686589921118108344654274776002924949699514759820503910984443396225085556329453262160312195475332365052302858783105407745663740585803098305023249756111368049950163462388385362335937010786959132576587845583579588056574658340601882631020529595113806813975952098429751621777437426581760176612378200144749546283222278632927625036689224728552301833015747115546334419012004870091311801727234396627282154659341220005712383030184513423146821824749625141220375926274254838083359422096107376456254874227230786791473401400818685683588726561134800854232826696808345124633056379503082658309023861152443764421786399116516058974263475670452557479495335125983247709460380575872076251131971902570828620338999143577n
|
||||||
|
];
|
||||||
|
|
||||||
|
// this is used to encode big nums into json, so it isn't printed directly
|
||||||
|
//const string_encoding = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'
|
||||||
|
const string_encoding = ' "+,/0123456789:=ABCDEFGHIJKLMNOPQRSTUVWXYZ\\abcdefghijklmnopqrstuvwxyz{}';
|
||||||
|
const base58_encoding = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ';
|
||||||
|
|
||||||
|
function encode_bigint(encoding, x) {
|
||||||
|
let r = '', l = BigInt(encoding.length);
|
||||||
|
while(x != 0n) {
|
||||||
|
r += encoding[x % l];
|
||||||
|
x = x / l;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
function decode_bigint(encoding, x) {
|
||||||
|
let r = 0n, l = BigInt(encoding.length);
|
||||||
|
for(let i = x.length - 1; i >= 0; i--) {
|
||||||
|
let v = encoding.indexOf(x[i]);
|
||||||
|
if(v == -1) { alert('invalid character: '+x[i]); return; }
|
||||||
|
r = r * l + BigInt(v);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
function uint8ToBigint(x) {
|
||||||
|
let a = 0n;
|
||||||
|
for(let i = x.length - 1; i >= 0; i--) {
|
||||||
|
a = (a << 8n) + BigInt(x[i]);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bigintToUint8(a) {
|
||||||
|
let num_bytes = 1;
|
||||||
|
while(a > (1n << BigInt(num_bytes*8)))
|
||||||
|
num_bytes++;
|
||||||
|
let r = new Uint8Array(num_bytes);
|
||||||
|
for(let i = 0; i < num_bytes; i++) {
|
||||||
|
r[i] = Number(a & 255n);
|
||||||
|
a = a >> 8n;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extended_gcd(a, b) {
|
||||||
|
if(a == 0n) {
|
||||||
|
return [b, 0n, 1n];
|
||||||
|
} else {
|
||||||
|
let [g, y, x] = extended_gcd(b % a, a);
|
||||||
|
return [g, x - (b / a) * y, y];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function inverse(v, mod) {
|
||||||
|
if(v < 0n) {
|
||||||
|
return mod - inverse(-v, mod);
|
||||||
|
} else {
|
||||||
|
let [g, x, y] = extended_gcd(v, mod);
|
||||||
|
if(g != 1n) alert('no inverse');
|
||||||
|
if(x < 0n)
|
||||||
|
return (mod + x) % mod;
|
||||||
|
else
|
||||||
|
return x % mod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// for implementing Shamir's Secret Sharing
|
||||||
|
function evaluatePolynomialAtPoint(poly, mod, x) {
|
||||||
|
let r = 0n;
|
||||||
|
for(let i = 0; i < poly.length; i++) {
|
||||||
|
let p = 1n;
|
||||||
|
let d = 1n;
|
||||||
|
for(let k = 0; k < poly.length; k++) {
|
||||||
|
if(k != i) {
|
||||||
|
p = (p * (x - poly[k][0])) % mod;
|
||||||
|
d = (d * (poly[i][0] - poly[k][0])) % mod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r = (r + poly[i][1] * p * inverse(d, mod)) % mod;
|
||||||
|
}
|
||||||
|
if(r < 0n) r += mod;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function hash(str) {
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
const data = encoder.encode(str);
|
||||||
|
const h = await crypto.subtle.digest('SHA-1', data);
|
||||||
|
return encode_bigint(string_encoding, uint8ToBigint(new Uint8Array(h)));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function is_key(x) {
|
||||||
|
return ('x' in x) && ('y' in x) && ('fingerprint' in x) && ('mod' in x) && ('required' in x) && ('name' in x) && ('version' in x) && x.version == 1 && x.hash == await hash(x.y + x.x + x.mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generate_key() {
|
||||||
|
const num_pub_generate = document.getElementById("number_private_generate").value * 1;
|
||||||
|
const num_required = document.getElementById("number_private_required").value * 1;
|
||||||
|
const name = document.getElementById("user_name").value
|
||||||
|
|
||||||
|
if(num_pub_generate < num_required) {
|
||||||
|
alert('The number of public keys that are to be generated is less than the number of public keys which will be required for decryption\nThis will not work');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { privateKey, publicKey } = await openpgp.generateKey({
|
||||||
|
type: 'ecc', // Type of the key, defaults to ECC
|
||||||
|
curve: 'curve25519', // ECC curve name, defaults to curve25519
|
||||||
|
userIDs: [{ name: "Key for "+name+" in the event of death", email: name.replace(/[^A-Za-z0-9]/g, '-')+"@in-event-of-death.none" }],
|
||||||
|
format: 'object'
|
||||||
|
//format: 'armored' // output key format, defaults to 'armored' (other options: 'binary' or 'object')
|
||||||
|
});
|
||||||
|
const pk = publicKey.armor();
|
||||||
|
const priv = privateKey.write();
|
||||||
|
const fingerprint = publicKey.getFingerprint();
|
||||||
|
//debugger;
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById("num_required_span").innerHTML = num_required;
|
||||||
|
//document.getElementById("private_key").value = privateKey;
|
||||||
|
document.getElementById("public_key_gen").value = pk;
|
||||||
|
document.getElementById("public_key_gen").rows = pk.split('\n').length + 1;
|
||||||
|
document.getElementById("public_key").value = pk;
|
||||||
|
|
||||||
|
let poly_values = [[0n, uint8ToBigint(priv)]];
|
||||||
|
for(let i = 1; i < num_required; i++) {
|
||||||
|
let arr = new Uint8Array(priv.length);
|
||||||
|
crypto.getRandomValues(arr);
|
||||||
|
poly_values.push([BigInt(i), uint8ToBigint(arr)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mod = large_primes[0];
|
||||||
|
for(let i = 1; i < large_primes.length && mod < (1n << BigInt(priv.length*8)); i++)
|
||||||
|
mod = large_primes[i];
|
||||||
|
if(mod < (1n << BigInt(priv.length*8))) {
|
||||||
|
alert('FAILURE: Encryption key too big');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let pk_list = document.getElementById('private_keys');
|
||||||
|
pk_list.innerHTML = '';
|
||||||
|
|
||||||
|
location.hash = '';
|
||||||
|
const key_prefix= 'https://in-event-of-death.github.io/v1/#';
|
||||||
|
for(let i = 0; i < num_pub_generate; i++) {
|
||||||
|
let x = BigInt(i)*1191531196035921311916814842367n + 1196999169309667173465223891789n + BigInt(num_required);
|
||||||
|
if(x == 0n) x = 123n; // zero encodes the secret key, so we do not want to generate its value
|
||||||
|
let y = evaluatePolynomialAtPoint(poly_values, mod, x);
|
||||||
|
let k = {
|
||||||
|
'y': encode_bigint(string_encoding, y),
|
||||||
|
'id': i,
|
||||||
|
'x': encode_bigint(string_encoding, x),
|
||||||
|
'required': num_required,
|
||||||
|
'fingerprint': fingerprint,
|
||||||
|
'mod': encode_bigint(string_encoding, mod),
|
||||||
|
'name': btoa(name), // the string encoding cant handle non-standard characters
|
||||||
|
'version': 1,
|
||||||
|
};
|
||||||
|
k.hash = await hash(k.y + k.x + k.mod);
|
||||||
|
let s = encode_bigint(base58_encoding, decode_bigint(string_encoding, JSON.stringify(k)));
|
||||||
|
let inp = document.createElement('input');
|
||||||
|
inp.type = 'text';
|
||||||
|
inp.size = 80;
|
||||||
|
inp.readOnly = true;
|
||||||
|
inp.value = key_prefix + s;
|
||||||
|
inp.name = 'gen_decrypt_key';
|
||||||
|
inp.onclick = function () { this.select(); }
|
||||||
|
let li = document.createElement('li');
|
||||||
|
li.appendChild(inp);
|
||||||
|
pk_list.appendChild(li);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function encrypt() {
|
||||||
|
const publicKey = document.getElementById("public_key").value;
|
||||||
|
|
||||||
|
const encrypted = await openpgp.encrypt({
|
||||||
|
message: await openpgp.createMessage({ text: document.getElementById("to_encrypt").value }),
|
||||||
|
encryptionKeys: await openpgp.readKey({ armoredKey: publicKey }),
|
||||||
|
format: 'armored'
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("encrypted").value = encrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
function load_json(s) {
|
||||||
|
s = s.replace(/^(.+#)/, '').replace(new RegExp('[^'+base58_encoding+']', 'g'), '')
|
||||||
|
return JSON.parse(encode_bigint(string_encoding, decode_bigint(base58_encoding, s)));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function decrypt() {
|
||||||
|
let private_keys = [];
|
||||||
|
let has_x = {};
|
||||||
|
let keys = document.getElementsByName('decrypt_key');
|
||||||
|
for(let i = 0; i < keys.length; i++) {
|
||||||
|
try {
|
||||||
|
let k = load_json(keys[i].value);
|
||||||
|
if(!(await is_key(k)) || k.x in has_x) {
|
||||||
|
keys[i].value = ''; // this is redudant
|
||||||
|
} else {
|
||||||
|
private_keys.push(k);
|
||||||
|
has_x[k.x] = true;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
keys[i].value = ''; // this was not loaded correctly
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(private_keys.length == 0) {
|
||||||
|
alert('Private keys are entered incorrectly');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(let i = 1; i < private_keys.length; i++) {
|
||||||
|
if(private_keys[i].fingerprint != private_keys[0].fingerprint) {
|
||||||
|
alert('Private keys have been mixed up with different encryption keys');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(private_keys.length < private_keys[0].required) {
|
||||||
|
alert('Not enough private keys, require '+private_keys[0].required+' keys to decrypt the data');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let poly_values = [];
|
||||||
|
for(let i = 0; i < private_keys[0].required; i++) {
|
||||||
|
poly_values.push([decode_bigint(string_encoding, private_keys[i].x), decode_bigint(string_encoding, private_keys[i].y)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mod = decode_bigint(string_encoding, private_keys[0].mod);
|
||||||
|
|
||||||
|
let private_key = bigintToUint8(evaluatePolynomialAtPoint(poly_values, mod, 0n));
|
||||||
|
|
||||||
|
let pkey = await openpgp.readPrivateKey({ binaryKey: private_key });
|
||||||
|
|
||||||
|
let message = await openpgp.readMessage({
|
||||||
|
armoredMessage: document.getElementById('to_decrypt').value
|
||||||
|
});
|
||||||
|
|
||||||
|
let { data: decrypted } = await openpgp.decrypt({
|
||||||
|
message,
|
||||||
|
decryptionKeys: pkey
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('decrypted').value = decrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
function add_decrypt_key() {
|
||||||
|
let d = document.getElementById('decryption_keys');
|
||||||
|
let inp = document.createElement('input');
|
||||||
|
inp.type = 'text';
|
||||||
|
inp.size = 80;
|
||||||
|
inp.onchange = on_decrypt_key_change;
|
||||||
|
inp.name = 'decrypt_key';
|
||||||
|
let li = document.createElement('li');
|
||||||
|
li.appendChild(inp);
|
||||||
|
d.appendChild(li);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function on_decrypt_key_change() {
|
||||||
|
let private_keys = [];
|
||||||
|
let has_x = {};
|
||||||
|
let keys = document.getElementsByName('decrypt_key');
|
||||||
|
let has_invalid = false;
|
||||||
|
for(let i = 0; i < keys.length; i++) {
|
||||||
|
try {
|
||||||
|
let v = keys[i].value;
|
||||||
|
if(v) {
|
||||||
|
let k = load_json(v);
|
||||||
|
if((await is_key(k)) && !(k.x in has_x)) {
|
||||||
|
private_keys.push(k);
|
||||||
|
has_x[k.x] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
has_invalid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(private_keys.length == 0) {
|
||||||
|
document.getElementById('decrypt_key_status').innerHTML = has_invalid ? '<span style="color:red"><b>Encryption key is corrupted</b></span>' : '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let message = 'Decryption keys for <i><b>'+atob(private_keys[0].name)+'</b></i> loaded';
|
||||||
|
let error = '';
|
||||||
|
|
||||||
|
for(let i = 1; i < private_keys.length; i++) {
|
||||||
|
if(private_keys[i].fingerprint != private_keys[0].fingerprint) {
|
||||||
|
error = '<br><span style="color:red"><b>Different encryption keys are mixed together. This will not work</b></span>';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!error && private_keys.length < private_keys[0].required) {
|
||||||
|
error = '<br><span style="color:red"><b>'+private_keys.length+' decryption '+(private_keys.length==1 ? 'key' : 'keys')+' loaded, '+(private_keys[0].required-private_keys.length)+' additional '+(private_keys[0].required-private_keys.length==1 ? 'key' : 'keys')+' required</b></span>';
|
||||||
|
for(let i = keys.length; i < private_keys[0].required; i++)
|
||||||
|
add_decrypt_key();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!error) {
|
||||||
|
error = '<br><span style="color:green">Ready to decrypt</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('decrypt_key_status').innerHTML = '<p>' + message + error + '</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = function () {
|
||||||
|
try {
|
||||||
|
load_json(location.hash);
|
||||||
|
let v = document.getElementsByName('decrypt_key');
|
||||||
|
for(let a in v) a.value = '';
|
||||||
|
v[0].value = location.href;
|
||||||
|
} catch(e) {}
|
||||||
|
on_decrypt_key_change();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(location.protocol === 'http:') {
|
||||||
|
location.protocol = 'https:'; // the crypto APIs require https
|
||||||
|
}
|
||||||
|
|
||||||
|
async function example() {
|
||||||
|
await generate_key();
|
||||||
|
await encrypt();
|
||||||
|
const num_required = document.getElementById("number_private_required").value * 1;
|
||||||
|
while(document.getElementsByName('decrypt_key').length < num_required)
|
||||||
|
add_decrypt_key();
|
||||||
|
const genk = document.getElementsByName('gen_decrypt_key');
|
||||||
|
const deck = document.getElementsByName('decrypt_key');
|
||||||
|
for(let i = 0; i < num_required; i++) {
|
||||||
|
deck[i].value = genk[i].value;
|
||||||
|
}
|
||||||
|
await on_decrypt_key_change();
|
||||||
|
document.getElementById('to_decrypt').value = document.getElementById('encrypted').value;
|
||||||
|
await decrypt();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@media (min-width: 970px) {
|
||||||
|
body {
|
||||||
|
width:960px;
|
||||||
|
margin:auto;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #445;
|
||||||
|
}
|
||||||
|
#content {
|
||||||
|
background-color:#fff;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
#forkongithub a{background:#c00;color:#fff;text-decoration:none;font-family:arial,sans-serif;text-align:center;font-weight:bold;padding:5px 40px;font-size:1rem;line-height:2rem;position:relative;transition:0.5s;}#forkongithub a:hover{background:#c11;color:#fff;}#forkongithub a::before,#forkongithub a::after{content:"";width:100%;display:block;position:absolute;top:1px;left:0;height:1px;background:#fff;}#forkongithub a::after{bottom:1px;top:auto;}@media screen and (min-width:800px){#forkongithub{position:absolute;display:block;top:0;right:0;width:200px;overflow:hidden;height:200px;z-index:9999;}#forkongithub a{width:200px;position:absolute;top:60px;right:-60px;transform:rotate(45deg);-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);-moz-transform:rotate(45deg);-o-transform:rotate(45deg);box-shadow:4px 4px 10px rgba(0,0,0,0.8);}}
|
||||||
|
}
|
||||||
|
@media (max-width: 970px) {
|
||||||
|
#forkongithub { display: none; }
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font: 13px/1.5 'Helvetica Neue',Arial,'Liberation Sans',FreeSans,sans-serif;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="content">
|
||||||
|
|
||||||
|
<center><a name="description" /><h1>Description</h1></a></center>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This is designed to encrypt messages which can be passed along in the
|
||||||
|
event of death. This webpage is entirely self contained, which means that
|
||||||
|
it can be used offline and saved to a file. This webpage generates
|
||||||
|
encryption keys using <a href="https://openpgpjs.org/">OpenPGP.js</a> and
|
||||||
|
<a href="https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing">Shamir's
|
||||||
|
Secret Sharing</a>. This means that a your data is encrypted such that it
|
||||||
|
requires <i>multiple</i> description keys to descrypt a message. For
|
||||||
|
example, you can generate 10 encryption keys such that any 3 encryption
|
||||||
|
keys can be used to decrypt the data.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
To see an example of how this works, click the
|
||||||
|
<button type="button" onclick="example()">Show Example</button>
|
||||||
|
button.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If you have a decryption key and want to decrypt a message, go to
|
||||||
|
the <a href="#decrypt">Decrypt Message</a> section below.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<button type="button" onclick="example()">Show Example</button>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<center><a name="generate" /><h1>Generate Encryption Key</h1></center>
|
||||||
|
|
||||||
|
<p>Name: <input type="text" value="John Doe" id="user_name"></p>
|
||||||
|
<p>Number of private keys to generate: <input type="number" value="10" id="number_private_generate"></p>
|
||||||
|
<p>Number of private keys required to decrypt: <input type="number" value="3" id="number_private_required"></p>
|
||||||
|
<p><button type="button" onclick="generate_key()">Generate Encryption Key</button></p>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<p><b>Public key used for encryption:</b>
|
||||||
|
<br>You should save the public key somewhere safe. The Public Key
|
||||||
|
can <i>only</i> be used to encrypt messages. You can encrypt messages in
|
||||||
|
the <a href="#encrypt">Encryption section</a> of this webpage or by
|
||||||
|
using <a href="https://gnupg.org/">PGP</a> software on your computer. <br>
|
||||||
|
<textarea id="public_key_gen" readonly cols=60 rows=10 autocomplete="off"></textarea>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<b>Private keys for decryption:</b><br> The Private key can be used to
|
||||||
|
decrypt a message. Ideally, each trusted individual will be given 1 of
|
||||||
|
these keys. Note, <i>anyone</i> who gets access to more
|
||||||
|
than <b><span id="num_required_span">3</span></b> of these private keys
|
||||||
|
(as configured above) can decrypt all of your messages.
|
||||||
|
|
||||||
|
<!-- These keys should be distributed such that 1 key is provide to each individual. As configured above, any <b><span id="num_required_span">3</span></b> of these keys are required to decrypt your data. -->
|
||||||
|
<br>
|
||||||
|
<ol id="private_keys">
|
||||||
|
<li><input type="text" size=80 readonly /></li>
|
||||||
|
<li><input type="text" size=80 readonly /></li>
|
||||||
|
</ol>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<center><a name="encrypt" /><h1>Encrypt Message</h1></center>
|
||||||
|
|
||||||
|
<p><b>Public Key used for Encryption:</b><br>
|
||||||
|
<textarea id="public_key" cols=60 rows=10 autocomplete="off"></textarea>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p><b>Message to Encrypt:</b><br>
|
||||||
|
<textarea id="to_encrypt" cols=60 rows=10 autocomplete="off">Example message to encrypt
|
||||||
|
|
||||||
|
This message can contain any content, for exmaple you might encrypt your email password to be passed along.
|
||||||
|
|
||||||
|
You can come back and encrypt multiple messages as long as you still have the encryption key.
|
||||||
|
</textarea>
|
||||||
|
</p>
|
||||||
|
<p><button type="button" onclick="encrypt()">Encrypt message</button></p>
|
||||||
|
|
||||||
|
<p><b>Encrypted data:</b> <br>
|
||||||
|
<textarea id="encrypted" readonly cols=60 rows=10 autocomplete="off"></textarea>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<center><a name="decrypt" /><h1>Decrypt Message</h1></center>
|
||||||
|
|
||||||
|
<p>Decryption Keys:
|
||||||
|
<ol id="decryption_keys">
|
||||||
|
<li><input name="decrypt_key" type="text" size=80 onchange="on_decrypt_key_change()" /></li>
|
||||||
|
<li><input name="decrypt_key" type="text" size=80 onchange="on_decrypt_key_change()" /></li>
|
||||||
|
<li><input name="decrypt_key" type="text" size=80 onchange="on_decrypt_key_change()" /></li>
|
||||||
|
</ol>
|
||||||
|
<button type="button" onclick="add_decrypt_key()">Add addition decryption Key <b>+</b></button><br>
|
||||||
|
<div id="decrypt_key_status"></div>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>Encrypted message:<br>
|
||||||
|
<textarea autocomplete="off" id="to_decrypt" cols=60 rows=10 onfocus="this.value='';" spellcheck="false">-----BEGIN PGP MESSAGE-----
|
||||||
|
Paste your encrypted message here
|
||||||
|
....
|
||||||
|
-----END PGP MESSAGE-----
|
||||||
|
</textarea>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p><button type="button" onclick="decrypt()">Decrypt message</button></p>
|
||||||
|
|
||||||
|
<p>Decrypted message:<br>
|
||||||
|
<textarea autocomplete="off" id="decrypted" readonly cols=60 rows=10></textarea>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<footer><center>Created By <a href="https://matthewfl.com">Matthew Francis-Landau</a> 2023</center></footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
if(true || location.hostname.indexOf('github') != -1)
|
||||||
|
document.write('<span id="forkongithub"><a href="https://github.com/in-event-of-death/v1/">Fork me on GitHub</a></span>')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="openpgp.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user