/* * Copyright 2021 Netsyms Technologies. * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ var keymgr; var keyring = new kbpgp.keyring.KeyRing(); /** * Load and unlock the private key in localstorage, prompting user as needed. If there is no key, generates, saves, and loads a new one. * @param {function} callback Passed two arguments: message for user, and boolean true if OK false if error. * @returns {undefined} */ function loadKeyFromLocalStorage(callback) { if (typeof keymgr != "undefined") { callback("Key already loaded.", true); return; } $("#lockstatus").css("display", "none"); if (!inStorage("signingkey") || getStorage("signingkey") == "undefined") { var pass = prompt("Generating a new signing key (might take a while, be patient). Enter a password to protect it. You'll need to save this password somewhere safe; it cannot be recovered."); generatePrivateKey(getStorage("notary_name") + " ", pass, function (key) { if (typeof key == "undefined") { callback("Could not generate key.", false); return; } keymgr = key; keyring.add_key_manager(keymgr); setStorage("signingkey", keymgr.armored_pgp_private); callback("Signing key generated.", true); }); } else { var pass = prompt("Enter password to unlock signing key:"); loadPrivateKey(getStorage("signingkey"), pass, function (key) { if (typeof key == "undefined") { callback("Could not unlock key. Password is probably incorrect.", false); return; } keymgr = key; keyring.add_key_manager(keymgr); callback("Signing key unlocked.", true); }); } } function unloadKey() { keymgr = undefined; $("#lockstatus").css("display", ""); showToast(" Signing key locked."); } function loadKeyFromLocalStorageWithUserFeedback() { loadKeyFromLocalStorage(function (msg, ok) { if (ok) { showToast(" " + msg); } else { showAlert("Error: " + msg); } }); } /** * Load a private key. * @param {string} armoredkey PGP private key * @param {string} pass key password * @param {function} callback Passed a new keymanager for the key. * @returns {undefined} */ function loadPrivateKey(armoredkey, pass, callback) { kbpgp.KeyManager.import_from_armored_pgp({ armored: armoredkey }, function (err, key) { if (!err) { if (key.is_pgp_locked()) { key.unlock_pgp({ passphrase: pass }, function (err) { if (!err) { console.log("Loaded private key with passphrase"); callback(key); } else { console.error(err); callback(undefined); } }); } else { console.log("Loaded private key w/o passphrase"); callback(key); } } else { console.error(err); callback(undefined); } }); } /** * Sign a message with a key and return the signed message in the callback. * @param {type} text * @param {type} key * @param {type} callback * @returns {undefined} */ function signMessage(text, key, callback) { var params = { msg: text, sign_with: key }; kbpgp.box(params, function (err, result_string, result_buffer) { //console.log(err, result_string, result_buffer); callback(result_string); }); } /** * Read a signed PGP message and return the contents and signer's fingerprint/key ID. * @param {string} pgpmsg "-----BEGIN PGP MESSAGE----- ..." * @param {function} callback function(message, fingerprint) {} * @param {function} onerror function(errormessage) {} * @returns {undefined} */ function verifyMessage(pgpmsg, callback, onerror) { kbpgp.unbox({keyfetch: keyring, armored: pgpmsg}, function (err, literals) { if (err != null) { onerror(err); } else { var message = literals[0].toString(); var fingerprint = null; var ds = km = null; ds = literals[0].get_data_signer(); if (ds) { km = ds.get_key_manager(); } if (km) { fingerprint = km.get_pgp_fingerprint().toString('hex'); } callback(message, fingerprint); } }); } /** * Generate a new private key. * @param {string} userid Something like "Test User " * @param {string} passphrase protects the key * @param {function} callback Passed the keymanager for the new key * @returns {undefined} */ function generatePrivateKey(userid, passphrase, callback) { var statustextEl = $("#statustext"); statustextEl.html(" Generating cryptographic key..."); setTimeout(function () { var F = kbpgp["const"].openpgp; var opts = { userid: userid, primary: { nbits: 2048, flags: F.certify_keys | F.sign_data | F.auth | F.encrypt_comm | F.encrypt_storage, expire_in: 0 // never expire }, subkeys: [] }; kbpgp.KeyManager.generate(opts, function (err, alice) { if (!err) { alice.sign({}, function (err) { alice.export_pgp_private({ passphrase: passphrase }, function (err, pgp_private) { statustextEl.html(" Key generated!"); setTimeout(function () { statustextEl.html(""); }, 5000); callback(alice); }); }); } }); }, 100); } function exportPublicKey() { loadKeyFromLocalStorage(function (message, ok) { if (ok) { openSaveFileDialog(function (path) { keymgr.export_pgp_public({}, function (err, pgp_public) { if (err) { showAlert("Something went wrong."); } else { writeToFile(path, pgp_public); } }); }, "public-key.asc", ".asc"); } else { showAlert("Error: " + message); } }); } function exportPrivateKey() { var pass = prompt("Enter password for private key:"); const savepriv = function (key) { var pass2 = prompt("Enter a password to protect the key backup:"); openSaveFileDialog(function (path) { key.export_pgp_private({ passphrase: pass2 }, function (err, pgp_private) { if (err) { showAlert("Something went wrong."); } else { writeToFile(path, pgp_private); } }); }, "private-key.asc", ".asc"); } kbpgp.KeyManager.import_from_armored_pgp({ armored: getStorage("signingkey") }, function (err, key) { if (!err) { if (key.is_pgp_locked()) { key.unlock_pgp({ passphrase: pass }, function (err) { if (!err) { savepriv(key); } else { showAlert("Could not unlock key. Password is probably incorrect."); } }); } else { console.log("Loaded private key w/o passphrase"); savepriv(key); } } else { showAlert("Could not unlock key: " + err); } }); } function importPrivateKey() { if (inStorage("signingkey") && getStorage("signingkey") != "undefined") { if (!confirm("The restored key will replace the current key, which will be unrecoverable unless you made a backup. Continue?")) { return; } } keymgr = null; openFileDialog(function (path) { var keyfile = getFileAsString(path); var pass = prompt("Enter password for imported key (password was set when exported):"); loadPrivateKey(keyfile, pass, function (key) { if (typeof key == "undefined") { showAlert("Could not import key. Password is probably incorrect."); return; } keymgr = key; setStorage("signingkey", keymgr.armored_pgp_private); showAlert("Private key imported."); }); }, ".asc"); } function calculateSHA256HashOfBuffer(buffer) { const hasha = require('hasha'); var hashstr = hasha(Buffer.from(buffer), {algorithm: 'sha256'}); return hashstr; } function calculateSHA256HashOfString(str) { const hasha = require('hasha'); var hashstr = hasha(str, {algorithm: 'sha256'}); return hashstr; } function openPublicKeyFile() { openFileDialog(function (path, html5file) { var importpk = function (keyfile) { kbpgp.KeyManager.import_from_armored_pgp({ armored: keyfile }, function (err, pubkeymgr) { if (!err) { keyring.add_key_manager(pubkeymgr); showAlert("Public key file loaded. You can now analyze PDFs signed by the key's owner."); } else { showAlert("Error loading public key: " + err); } }); }; if (typeof nw != 'undefined') { var keyfile = getFileAsString(path); importpk(keyfile); } else { var fileReader = new FileReader(); fileReader.onload = function (e) { importpk(e.target.result); } fileReader.readAsText(html5file); } }, ".asc"); } /** * Show visual indicator when private key is not loaded/unlocked. * @returns {undefined} */ setInterval(function () { if (typeof keymgr == "undefined") { $("#lockstatus").css("display", ""); } else { $("#lockstatus").css("display", "none"); } }, 1000);