|
|
|
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 |
|
)); |
|
} |
@EGreg
This is something I've been looking into as well and I can't find a clear answer.
We can store imported and generated cryptoKeys in memory or IndexedDB as cryptoKeys for quick operations. They aren't strings, or plain objects, or json objects. They cannot be extracted directly, only used for their intended operations. So it seems.
That leads me to think they might be stored as one-way functions. Essentially its just a function, and its constructed using values that when combined can derive the same "state" that your cryptoKey has when its in memory. The parts themselves however cannot be used to derive the initial material (raw bits).
This might be ok. I'd really like to see some documentation somewhere that outlines how they are TRUELY stored on disk when stored in IndexedDB. A "safe" non-extractable cryptoKey stored in IndexedDB that can be used to quickly encrypt or derive our true key sounds REALLY good. From a security stand point, sounds too good to be true.
If someone has a link that can demonstrate that the imported CryptoKey CANNOT be extracted (i.e. the raw bits can't be derieved from the hard drive) I'd like to see that. If its merely the case that they are encrypted because its ASSUMED that the file system is encrypted when not in use, that isn't good enough for me. I'd rather do it the hard way then find out later that cryptoKeys have been stored with the raw bits in plain text in some browser cache file somewhere the whole time.
@kavinRkz
If you're new to the Web Crypto API (crypto.subtle) it can be very confusing and there isn't a silverbullet framework out there that I've seen just yet. Personally, I've been using it every day for a while now and actually I like it a lot now. It grows on you. I don't think I want a framework, but I have been writing my own abstractions and functions around the API for ease of use.
To help you learn I recommend this above all other resources:
https://github.com/diafygi/webcrypto-examples
Also, to help get you started, I am writing some examples using various parts of the API. I have an example for AES here:
https://github.com/themikefuller/Web-Cryptography
Look for "AES-GCM encryption / decryption with PBKDF2 key derivation". There are some examples, and I included an aes.js file that has the function that is outlined in the readme.
AES is symmetric encryption. The key used to encrypt is the key used to decrypt. The "password" you use when encrypting with AES is usually used in another function to derive the necessary bits required to encrypt (128 or 256). Many libraries provide this, along with encoding and iv / salt generation, in their encrypt / decrypt functions. Web Crypto is closer to metal. You are using encryption primitives and dealing with byteArrays.
Public and private keys are a part of asymmetric encryption and the Web Crypto API supports RSA and ECDH. On that note, you can also use RSA or ESDSA to sign and verify messages, but to just encrypt between two separate parties, you want to use ECDH. I also provide an example for that under the cheeky heading "Formula for encrypted communication with advanced extraterrestrial lifeforms (Aliens) familar with Elliptic Curve Diffie-Hellman and JavaScript".
If you ever need help with this, let me know.