|
|
|
async function encryptDataSaveKey() { |
|
var data = await makeData(); |
|
console.log("generated data", data); |
|
var keys = await makeKeys() |
|
var encrypted = await encrypt(data, keys); |
|
callOnStore(function (store) { |
|
store.put({id: 1, keys: keys, encrypted: encrypted}); |
|
}) |
|
} |
|
|
|
function loadKeyDecryptData() { |
|
callOnStore(function (store) { |
|
var getData = store.get(1); |
|
getData.onsuccess = async function() { |
|
var keys = getData.result.keys; |
|
var encrypted = getData.result.encrypted; |
|
var data = await decrypt(encrypted, keys); |
|
console.log("decrypted data", data); |
|
}; |
|
}) |
|
} |
|
|
|
function callOnStore(fn_) { |
|
|
|
// This works on all devices/browsers, and uses IndexedDBShim as a final fallback |
|
var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB || window.shimIndexedDB; |
|
|
|
// Open (or create) the database |
|
var open = indexedDB.open("MyDatabase", 1); |
|
|
|
// Create the schema |
|
open.onupgradeneeded = function() { |
|
var db = open.result; |
|
var store = db.createObjectStore("MyObjectStore", {keyPath: "id"}); |
|
}; |
|
|
|
|
|
open.onsuccess = function() { |
|
// Start a new transaction |
|
var db = open.result; |
|
var tx = db.transaction("MyObjectStore", "readwrite"); |
|
var store = tx.objectStore("MyObjectStore"); |
|
|
|
fn_(store) |
|
|
|
|
|
// Close the db when the transaction is done |
|
tx.oncomplete = function() { |
|
db.close(); |
|
}; |
|
} |
|
} |
|
|
|
async function encryptDecrypt() { |
|
var data = await makeData(); |
|
console.log("generated data", data); |
|
var keys = await makeKeys() |
|
var encrypted = await encrypt(data, keys); |
|
console.log("encrypted", encrypted); |
|
var finalData = await decrypt(encrypted, keys); |
|
console.log("decrypted data", data); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function makeData() { |
|
return window.crypto.getRandomValues(new Uint8Array(16)) |
|
} |
|
|
|
function makeKeys() { |
|
return window.crypto.subtle.generateKey( |
|
{ |
|
name: "RSA-OAEP", |
|
modulusLength: 2048, //can be 1024, 2048, or 4096 |
|
publicExponent: new Uint8Array([0x01, 0x00, 0x01]), |
|
hash: {name: "SHA-256"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" |
|
}, |
|
false, //whether the key is extractable (i.e. can be used in exportKey) |
|
["encrypt", "decrypt"] //must be ["encrypt", "decrypt"] or ["wrapKey", "unwrapKey"] |
|
) |
|
} |
|
|
|
function encrypt(data, keys) { |
|
return window.crypto.subtle.encrypt( |
|
{ |
|
name: "RSA-OAEP", |
|
//label: Uint8Array([...]) //optional |
|
}, |
|
keys.publicKey, //from generateKey or importKey above |
|
data //ArrayBuffer of data you want to encrypt |
|
) |
|
} |
|
|
|
|
|
async function decrypt(data, keys) { |
|
return new Uint8Array(await window.crypto.subtle.decrypt( |
|
{ |
|
name: "RSA-OAEP", |
|
//label: Uint8Array([...]) //optional |
|
}, |
|
keys.privateKey, //from generateKey or importKey above |
|
data //ArrayBuffer of the data |
|
)); |
|
} |
I am going to use it for a web-based end-to-end encrypted messaging system.
For that purpose, I think it's pretty safe because the only vulnerability comes from the user end if the user gives his device to some malicious person then he might steal his private key otherwise there is no way to use networking to grab the private key.
Some sort of the same mechanism might Whatsapp using because when you uninstalled it all of your chats are gone unless you have a backup so a similar thing will happen to my messaging system.
If he cleared his browser data then all the previous ciphers will also be gone and I don't need to save the cipher on the database because they can only be decrypted with the user's private key so as long as the user has his private key he can read those cipher so private key and cipher associated with that key will reside on user IndexDB.
What would you say? @tcortega