staticrypt
staticrypt copied to clipboard
Replace crypto-js by browser native WebCrypto ?
Pro/Cons that I see:
Pros
- no dependencies at all
- smaller output (not a big issue I think, minified crypto-js is quite lean already)
- no need to update the lib, always as up to date as the browser
Cons
-
at encryption time: I see it as going from using the crypto implementation of a single library that can be audited to leaving it to each user's browser, so the responsability of checking that their browser is up to date/bugfree on that point falls on each user.
Makes sense ? Is there any data on the crypto implementation of that API in browsers ?
-
it might be nice to have a cli tool that can be inserted into one's workflow to update the encrypted files automatically. We can't use the browser API for that, crypto-js as a node library could also be used. Though the website and cli could use different tools.
-
probably wider support (for now) for crypto-js but that'd need to be checked and by how much :)
Keeping in mind that it would be possible to use different solutions for encrypting/decrypting: encrypting needs to be the safest option, decrypting the most convenient one.
Looks like it is supported for 88% of users: https://caniuse.com/#feat=cryptography
Chrome is only supported over secure connections. That is how the w2c spec is defined though, so other browsers might follow.
Supported algorithms: https://diafygi.github.io/webcrypto-examples/
AES-GCM - encrypt
window.crypto.subtle.encrypt(
{
name: "AES-GCM",
//Don't re-use initialization vectors!
//Always generate a new iv every time your encrypt!
//Recommended to use 12 bytes length
iv: window.crypto.getRandomValues(new Uint8Array(12)),
//Additional authentication data (optional)
additionalData: ArrayBuffer,
//Tag length (optional)
tagLength: 128, //can be 32, 64, 96, 104, 112, 120 or 128 (default)
},
key, //from generateKey or importKey above
data //ArrayBuffer of data you want to encrypt
)
.then(function(encrypted){
//returns an ArrayBuffer containing the encrypted data
console.log(new Uint8Array(encrypted));
})
.catch(function(err){
console.error(err);
});
AES-GCM - decrypt
window.crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: ArrayBuffer(12), //The initialization vector you used to encrypt
additionalData: ArrayBuffer, //The addtionalData you used to encrypt (if any)
tagLength: 128, //The tagLength you used to encrypt (if any)
},
key, //from generateKey or importKey above
data //ArrayBuffer of the data
)
.then(function(decrypted){
//returns an ArrayBuffer containing the decrypted data
console.log(new Uint8Array(decrypted));
})
.catch(function(err){
console.error(err);
});
Thanks for the data @tarpdalton! I agree it would be nice to use the webcrypto API - that would solve any potential adblocker misconfiguration and remove one more dependency. From your link local files seem to be considered a secure ressource by chrome which is good news.
The interface is less straightforward to deal with than cryptoJS but I've started looking into the implementation and hope to merge soon.
This gist helped me understand the interface better. I'm not great with javascript, but it looks like the steps would be:
Encrypt
- encode then digest/hash the password
- generate the IV
- encode then encrypt the text
- encode, convert to hex, and concatenate the IV to the ciphertext
Decrypt
- encode then digest/hash the password
- split the IV off of the encrypted data
- decode then decrypt
web crypto is promise based so it would require extra changes to the code
Here is a jsfiddle I got working with a password. It's pretty messy right now but it works. The annoying part is switching all the encodings back and forth.
Thanks for the good work @tarpdalton !
Yep, the pain point definitely is the encoding part. The fiddle is quite nice, but when we use asciiToUint8Array we assume the text to encrypt is ascii - if we try to encrypt/decrypt test 🐳 for example we get back test =3.
We could first convert the string to hex (https://stackoverflow.com/questions/21647928/javascript-unicode-string-to-hex) then use the hexStringToUint8Array to pass it to the webcrypto API and I'm guessing that should make us pretty much encoding agnostic.
I got it to work for unicode instead of ascii, and I opened a PR #111 https://developers.google.com/web/updates/2014/08/Easier-ArrayBuffer-String-conversion-with-the-Encoding-API
There is still more work to get the CLI to work with webcrypto
but when we use asciiToUint8Array we assume the text to encrypt is ascii
The browser has this build in via TextEncoder/TextDecoder.
https://developer.mozilla.org/en-US/docs/Web/API/Encoding_API