Vulnerabilities in Numerous Javascript Cryptographic Libraries

Some concerns were raised on bitcoin-dev regarding potential vulnerabilities with some Javascript based crypto applications, more precisely the use of SecureRandom() function which collects entropy and includes a PRNG (Pseudo Random Number Generator).

TL;DR

The conclusion seems to be that at least all wallets generated by js tools inside browsers since bitcoin exists until 2011 are impacted by the Math.random weakness if applicable to the related implementations, the Math.random or RC4 (Chrome) weakness between 2011 and 2013, and RC4 weakness for Chrome users until end of 2015

Entropy and PRNGs are used to generate Private Keys for your wallet and sign transactions using ECDSA. A weak entropy genration and PRNG means a third party could recovery the private key and gain access to the Bitcoins secured by the key. Quote:

A significant number of past and current cryptocurrency products contain a JavaScript class named SecureRandom(), containing both entropy collection and a PRNG. The entropy collection and the RNG itself are both deficient to the degree that key material can be recovered by a third party with medium complexity. There are a substantial number of variations of this SecureRandom() class in various pieces of software, some with bugs fixed, some with additional bugs added. Products that aren’t today vulnerable due to moving to other libraries may be using old keys that have been previously compromised by usage of SecureRandom().

The most common variations of the library attempts to collect entropy from window.crypto’s CSPRNG, but due to a type error in a comparison this function is silently stepped over without failing. Entropy is subsequently gathered from math.Random (a 48bit linear congruential generator, seeded by the time in some browsers), and a single execution of a medium resolution timer. In some known configurations this system has substantially less than 48 bits of entropy.

The core of the RNG is an implementation of RC4 (“arcfour random”), and the output is often directly used for the creation of private key material as well as cryptographic nonces for ECDSA signatures. RC4 is publicly known to have biases of several bits, which are likely sufficient for a lattice solver to recover a ECDSA private key given a number of signatures. One popular Bitcoin web wallet re-initialized the RC4 state for every signature which makes the biases bit-aligned, but in other cases the Special K would be manifest itself over multiple transactions.

Mustafa Al-Bassam replied with more clarification:

I think that the vulnerability disclosure is referring to a pre-2013 version of jsbn, a JavaScript crypto library. Before it used the CSRNG in the Web Crypto API, it tried to use nsIDOMCrypto, but incorrectly did a string comparison when checking the browser version.

In practice though, this doesn’t really matter, because navigator.appVersion < “5” returns true anyway for old browsers. The real issue is that modern browsers don’t have window.crypto.random defined, so Bitcoin wallets using a pre-2013 version of jsbn may not be using a CSPRNG, when run on a modern browser.

As is noted though, even if a CSPRNG is used, the library passes the output of the CSPRNG through RC4, which generates some biased bits, leading to possible private key recovery.

Follwed by a more detailed analysis by Aymeric Vitte:

Apparently window.crypto.getRandomValues was introduced in jsbn mid 2012 (according to the wayback machine, but 20122013 does not make any difference, see below), was available in Chrome since 2011 (but indeed see “window.crypto.getRandomValues() uses a weak CSPRNG” https://bugs.chromium.org/p/chromium/issues/detail?id=552749 fixed end of 2015, funny to see that those that did specify the Webcrypto API did not implement it correctly…), in FF in 2013 (https://website-archive.mozilla.org/www.mozilla.org/firefox_releasenotes/en-US/firefox/21.0/releasenotes/) , in IE in 2013 and Safari ~20122013, at least that’s the official dates for the Webcrypto API implementation, maybe something existed before, but it’s not so easy to seek for the history

The window.crypto.random check is in jsbn since the begining (2006) and only returns true for Netscape browsers before Netscape 56, ie Firefox (2000), see https://books.google.fr/books?id=UooAblGoGN8C&pg=PA85&lpg=PA85&dq=browser+appversion+4&source=bl&ots=dVijsOR0ov&sig=6SnElm56-bAvmGlKqUAdoGLAs2A&hl=fr&sa=X&ved=2ahUKEwirhtaqva_aAhUFchQKHQ4JCk4Q6AEwBXoECAAQcQ#v=onepage&q=browser%20appversion%204&f=false)

From the existing tools, there was not only jsbn, everybody was using Math.random (sjcl, cryptoJS, forge, etc) with different implementations and everybody did put a note stating that it might be insecure with an “improvement to come” comment

We can probably assume that nobody was using Netscape any longer when Bitcoin started

The conclusion seems to be that at least all wallets generated by js tools inside browsers since bitcoin exists until 2011 are impacted by the Math.random weakness if applicable to the related implementations, the Math.random or RC4 (Chrome) weakness between 2011 and 2013, and RC4 weakness for Chrome users until end of 2015

And all wallets using jsbn are impacted by Math.random and RC4 until 2013 (or end 2015 for Chrome), then still by the RC4 fallback step after

Support us and the authors of this article by donating to the following address:

34wrhMdEauGeJWAiP3aXarg7Y9Mkfu9eac

Comments powered by Talkyard.