Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Should have used the WebCrypto API instead of the crypto-js npm package. https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_...


I spent some time Googling this about 6 months ago. Lots of tutorials on Crypto-js, not so many (and almost zero "here's a super simple implementation") for WebCrypto API. I can understand if this is a hobby project why you'd lean into one rather than the other, I probably would have done the same.


Not going to pretend that I know what the most of the stuff mean, or if it is even safe enough, but I've followed the MDN articles and put together this TypeScript snippet [1]. Maybe somebody could comment on it?

Also sorry for the long link. Is there any accepted way to post a shorted URL?

Edit: added a corrected version [2]

[1]: https://www.typescriptlang.org/play?#code/DYUwLgBAbiDGYHsBOE...

[2]: https://www.typescriptlang.org/play?#code/FAiGGcE8DsGMAIBmBX...


If you call "encrypt" more than once in that code, you'll leak the authentication key. Every invocation of GCM encryption needs a unique nonce. Cryptography nerds will chastise you for using a random nonce (there theoretically isn't enough room in the GCM nonce space to safely encrypt large numbers of message with random nonces), but the alternative (using a counter) is even more hazardous. This problem motivates a lot of people to use other AEADs like XChapoly, which has an extended nonce space that safely admits random nonces. Isn't cryptography fun?


It's still considered safe to call AES-GCM with a single key and a randomly generated nonce 2^32 times [1], most practical systems don't come anywhere near this limit. And there's AES-GCM-SIV that solves nonce reuse (mostly), though it's not available in the Web Cryptography API at the moment.

1: https://csrc.nist.gov/csrc/media/Projects/crypto-publication...


I don't personally care, and probably wouldn't even sev:info a random GCM nonce in an assessment, but I would also choose extended-nonce Chapoly in preference to GCM in part because of this issue.


From what I shallowly researched; GCM's nonce seems limited to 12 bytes by convention only. That nonce reuse is so fatal seems absurd to me.

Would "salting" the key safely tackle the problem?

Put explicitly;

  send <- nonce || salt || ciphertext
  recv -> decrypt(ciphertext, nonce, pbkdf(pass) || salt)
[edit: apply salt outside of the kdf]


As I remember it, the balance of the bytes in the AES block are used for the counter. At any rate, the convention is essentially universal.


Sounds above my (current) head.

Here I thought GCM was some modern foolproof/footgunless design.


It is sort of infamously footgunny.


Oh yes! Thank you for the feedback. I've added a new version where the `iv` and the `salt` is random. Maybe a followup question: Because you need both the `iv` and `salt` to decrypt the message is it ok in an E2E scenario to send all three: `iv`, `salt` and the encrypted message?


I didn't look to see what "salt" means in your design, but the idiom for using GCM in message encryption is to send ciphertexts that take the form `nonce || ciphertext`, and to decrypt by reading the nonce off the front of the message.


Sounds like a golden opportunity for someone with a developer blog to make useful content


WebCrypto only works in secure contexts (https), which is a significant limitation for some use cases. But I agree it should be an option.



What is the major difference? Isn't crypto-js still secure?


One is a Javascript package, the other is a browser library following a spec that is implemented by all the major browser companies.

Web Crypto is faster and has many more devs working in the different implementations between all the companies and doesn't require any includes.


I don't know what "secure" means. Is their implementation of OFB correct? Probably. But using OFB mode is itself a problem. From what I can see, crypto-js implements no authenticated modes, and exposes all sorts of crufty old things nobody should be using. The parent comment suggesting WebCrypto is correct in this case. Avoid crypto-js.


Why use a library (thus incurring the need for the user to download more JS) instead of using what is already in their browser?


It might be. Whereas the native lib should be.

Just levels of trust. I'd happily use the former if the latter didn't exist.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: