I ported GnuPG to Javascript using Emscripten (not released yet). Now I need a good replacement for /dev/random//dev/urandom. New browsers support window.crypto.getRandomValues() but for older browsers I need something else. I was thinking about recording some audio using HTML5 and calculating the sha 512-bit digest. Then splitting this digest into two halfs and using them for AES 256-bit encryption (256-bit IV and 256-bit key) of a photo taken also with HTML5.

Is it safe to use this encrypted image as a replacement of /dev/(u)random? Which mode should I use for AES encryption?

  • $\begingroup$ "Which mode should I use for AES encryption?" - None of them. Encryption is the wrong primitive here. You want to use a cryptographic PRNG (which may involve hashing low-entropy data, so it might use a hash function); but you really don't want to build one of those yourself, you're better off using a carefully-vetted scheme and implementation built by someone who knows this stuff cold. $\endgroup$ – D.W. May 14 '13 at 4:52
  • $\begingroup$ Speaking of user-generated sources of entropy, you could also consider using the mouse coordinates too. I believe TrueCrypt/VeraCrypt do this (on desktop). I would make this a comment, but unfortunately I don't have enough reputation. $\endgroup$ – Alex Greensmith Jun 21 '18 at 18:40

Gathering binary data from a webcam/microphone can be a good (albeit unusual) source of entropy, yes. It's already been discussed here - see the second answer for some useful discussion. You mention 'encrypted image' but you probably mean 'hashed' - they're quite different things.

In terms of the mode of operation, GCM is a popular choice as it's an authenticated mode which provides data integrity as well as confidentiality. Of course, GCM isn't always available, in which case CTR and CBC are both fine, provided you MAC the ciphertext (and IV) to ensure integrity. Each mode has its own nuances (iv/nonce requirements, etc) so be sure read up on whichever mode you choose.

In case you haven't already, you should read up on some of the inherent weaknesses of javascript cryptography here. I'd be cautious about using any sort of automated tool to port a crypto library from one language to another... there's a lot that can go wrong.

Also, It's probably worth pointing out that as AES specifies a block size of 128 bits (regardless of whether the key is 128, 192, or 256 bits), the IV should also be 128 bits.

| improve this answer | |
  • 2
    $\begingroup$ "Gathering binary data from a webcam/microphone" - This is not a good solution for a web application (written in Javascript, and running in the browser). First, only modern browsers support access to the webcam/microphone from Javascript (without using Flash), but if the user has a modern browser, it'll probably support window.crypto.getRandomValues() too, and in that case you're better off using the latter. Second, even if the browser allows access to webcam/microphone, it'll prompt the user to grant access. Users may be reluctant to grant your website that access; then whatcha gonna do? $\endgroup$ – D.W. May 14 '13 at 4:51
  • $\begingroup$ hunter: Thanks for the link to matasano.com. I'll read that. $\endgroup$ – user6929 May 14 '13 at 9:21
  • 1
    $\begingroup$ D.W.: 1) not all browsers that support webcam recording also support window.crypto.getRandomValues(). 2) I don't know, maybe then the JS app should not work at all ;) $\endgroup$ – user6929 May 14 '13 at 9:22

window.crypto.getRandomValues() is the best you can do. Unfortunately, at the time of writing, too many browsers don't support window.crypto.getRandomValues(): see Compatibility of window.crypto.getRandomValues().

The alternative is to use fallback methods. However, those fallback methods are kind've hacky, of dubious security, slow, and have other limitations. For more on the available fallback methods, see Generate cryptographically strong pseudorandom numbers in Javascript?.

Therefore, life kinda sucks. Basically, the best you can do is test for the existence of window.crypto.getRandomValues() using feature testing. If it exists, great! use it. If it doesn't exist, fall back to one of the fallback methods -- in that case, life is unhappy, but what can you do, there's no better option.

| improve this answer | |
  • $\begingroup$ Speaking of hacky - it's possible to leverage flash APIs via javascript: code.google.com/p/jpegcam . It's more likely that flash will be available on a user's system (excluding iOS, which is a big exclusion) as opposed to window.crypto.getRandomValues(), but if that's the case, then using a webcam might be redundant anyway as flash offers (as of v11) CS random numbers which give direct access to '/dev/random' ... more info here. $\endgroup$ – hunter May 14 '13 at 12:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.