Bitcoin Forum
July 31, 2024, 05:17:58 PM *
News: Help 1Dq create 15th anniversary forum artwork.
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: What is exactly Randstorm vulnerability?  (Read 199 times)
SamYezi (OP)
Newbie
*
Online Online

Activity: 28
Merit: 83


View Profile
July 21, 2024, 01:06:50 PM
Last edit: July 23, 2024, 05:01:26 PM by SamYezi
Merited by ABCbits (2), Pmalek (2)
 #1

I've read the article from Unciphered about it, multiple times, and still fail to understand it

It basically says that wallets generated by BitcoinJs front end library from 2011 to 2015 are vulnerable because of the poor randomness generation. Especially those generated between May 4, 2011 to March 2012

But it's really vague on explaining what the actual exploit is. It could be just summarized as: it used Math.random() for randomness before March 2014, and it is a bad function

Let's look at the initial commit from March 4, 2011 : eckey.js is used for generating the private key, while rng.js and prng4.js in the jsbn folder are used for harvesting randomness.

rng.js

If rng_pool is not already initialized, it is filled with random values from Math.random()

Code:
while(rng_pptr < rng_psize) {  // extract some randomness from Math.random()
    t = Math.floor(65536 * Math.random());
    rng_pool[rng_pptr++] = t >>> 8;
    rng_pool[rng_pptr++] = t & 255;
  }

Math.random() according to the article has the cycle of 2^60 values before they repeat. The article also mentions that it fails modern benchmark tests, but I'm not sure about them

Is Math.random() the whole weakness of the story? What is the weakness actually about?

Later, the time in milliseconds is seeded to the pool

Code:
function rng_seed_time() {
  rng_seed_int(new Date().getTime());
}

And later for

Code:
SecureRandom.prototype.nextBytes = rng_get_bytes;

we initialize the state, and pass the pool as the key into the RC4 cipher

Code:
rng_state = prng_newstate();
rng_state.init(rng_pool);

from prng4.js

prng4.js

which creates a 256 values array

Code:
this.S = new Array();

and fills it with the loop

Code:
for(i = 0; i < 256; ++i) {
    j = (j + this.S[i] + key[i % key.length]) & 255;
    t = this.S[i];
    this.S[i] = this.S[j];
    this.S[j] = t;
  }

eckey.js

eckey.js uses SecureRandom() and creates our private key

Code:
var rng = new SecureRandom();
....
this.priv = ECDSA.getBigRandom(n);

But again, this tells us next to nothing about the actual vulnerability and what attacks might be used. Unciphered's article suggests that if we have GUID or IV (I guess that's a public key?), then we can do the work with just 2^32 to 2^64 values (2^48 most commonly)

Also, not sure about the clicks being added in the entropy pool, apart from:

Code:
<body onClick='rng_seed_time();' onKeyPress='rng_seed_time();'>

comment.
In what way, other things are added into entropy pool apart from the initial timestamp seed?

Edit July 23, 2024:

Sorry, I forgot that ecdsa.js also has its own context

ecdsa.js

Basically, getBigRandom() method is realized in this file with rng = new SecureRandom();

Code:
Bitcoin.ECDSA = (function () {
var ecparams = getSECCurveByName("secp256k1");
var rng = new SecureRandom();
....
var ECDSA = {
getBigRandom: function (limit) {
return new BigInteger(limit.bitLength(), rng)
.mod(limit.subtract(BigInteger.ONE))
.add(BigInteger.ONE)
;
},
.
gmaxwell
Moderator
Legendary
*
expert
Offline Offline

Activity: 4228
Merit: 8549



View Profile WWW
July 21, 2024, 05:30:15 PM
Merited by pooya87 (5), Pmalek (2), SamYezi (2), Wind_FURY (1), vjudeu (1)
 #2

Weird post. This isn't a new issue, here is a talk I gave in 2015 describing exactly this vulnerability https://youtu.be/TYQ-3VvNCHE?t=3072 (including that it never uses window.crypto in that code).  At the time of my presentation the code in question was already widely known to be insecure and deprecated. So it's pretty weird that they're attributing the discovery to 2018, years later.

As far as what attacks might be used-- the state space is simply too small: an attacker can throw computing power at it to search the possible random numbers, generate the resulting keys, and check the blockchain for them.

But I think the specific issue is a distraction. It's simple:  DO NOT USE JAVASCRIPT FOR CRYPTOGRAPHY.   If you've used JS with any private key, assume it compromised.


No programmer, no matter how skilled can write JS code that doesn't leave secrets laying around in memory. No programmer, no matter how skilled can write JS code that is sure to not leak secrets via side channels.

Protecting against memory leaks and timing sidechannels are basic steps that any competent author will take.

Thus, by definition, no JS cryptography software is competently written.

You shouldn't use crypto software that wasn't competently written even if at the moment no one knows anything specifically wrong with it.

With this handy rule of thumb at hand you don't have to worry about the RNG embarrassment discussed in that post.


SamYezi (OP)
Newbie
*
Online Online

Activity: 28
Merit: 83


View Profile
July 23, 2024, 07:35:56 PM
 #3

Let me get this straight. In rng.js , our pool rng_pool is seeded first with the time the browser starts in the line 37 like

Code:
t = Math.floor(65536 * Math.random());

with 48 bits of entropy
and then it is seeded in with the time in milliseconds whenever the rng_seed_time() is called

Code:
rng_seed_int(new Date().getTime());

(does it bring any new bits of entropy?)

The rng_pool is an array that is used to initialize our state rng_state in the line 52

Code:
rng_state.init(rng_pool);

and rng_pool is the input for that initialization. It is being inputted into Arcfour() from prng4.js which in line 32 returns

 
Code:
return this.S[(t + this.S[this.i]) & 255];

and this is what is being assigned to rng_state at the end of it

Then in ecdsa.js it becomes just rng in the line 128 like:

Code:
var rng = new SecureRandom(); 

and in the line 180 we construct an integer value from that array with BigInteger(...). After this, the integer is passed to eckey.js for generating the private key? (i.e. after BigInteger(...) we already got our private key. Its output is essentially our private key)

On the development side, on cryptography in JavaScript, yeah. Your point is understandable. Even Mozilla developer doc recommends instead to use Web crypto API

stilichovandal
Jr. Member
*
Offline Offline

Activity: 31
Merit: 5


View Profile
July 24, 2024, 03:36:58 AM
 #4

I spent some time on it and here is what I understand.

Indeed Math. Random is called when a private key is generated, however, it's called many times in a loop. The result of math.random() varies because of the state variable used in Math.Random varies every time it's called. (The implementation of math.random depends on the browser)

 while(rng_pptr < rng_psize) {  // extract some randomness from Math.random()
    t = Math.floor(65536 * Math.random());
    rng_pool[rng_pptr++] = t >>> 8;
    rng_pool[rng_pptr++] = t & 255;


This in turn is mixed with the time millisecond when the key is generated, I think there could be a small space to search when we know the exact time of key generation otherwise, I am assuming that the keyspace is large to search.

gmaxwell
Moderator
Legendary
*
expert
Offline Offline

Activity: 4228
Merit: 8549



View Profile WWW
July 24, 2024, 04:23:38 PM
 #5

Indeed Math. Random is called when a private key is generated, however, it's called many times in a loop. The result of math.random() varies because of the state variable used in Math.Random varies every time it's called. (The implementation of math.random depends on the browser)
Yes, it is in the browser. But you cannot just ignore it.  Classically-- as in when this code was actively used--  math.random was a 48bit lcg seeded by the browser time at start.  It doesn't matter how many times you call it because math random itself only had 48-bits of state.
NotATether
Legendary
*
Offline Offline

Activity: 1680
Merit: 7087


In memory of o_e_l_e_o


View Profile WWW
July 25, 2024, 06:33:47 AM
 #6

But I think the specific issue is a distraction. It's simple:  DO NOT USE JAVASCRIPT FOR CRYPTOGRAPHY.   If you've used JS with any private key, assume it compromised.

It's not only because of that, but also because (node)JS likes to create oodles of files when it installs dependencies, and any one of these packages can be bugged, even if you pin all your dependencies to a specific version.

Because there might be a dep of a dep of your dep that is not pinned, and someone takes control of the project and publishes a malicious code to steal keys in your code, and hence everybody else's code.

Plain JS also has this problem, because most of the time you are relying on minified bundles that are hard to read and might be hiding a malicious code.
gmaxwell
Moderator
Legendary
*
expert
Offline Offline

Activity: 4228
Merit: 8549



View Profile WWW
July 30, 2024, 08:44:33 PM
 #7

But I think the specific issue is a distraction. It's simple:  DO NOT USE JAVASCRIPT FOR CRYPTOGRAPHY.   If you've used JS with any private key, assume it compromised.

It's not only because of that, but also because (node)JS likes to create oodles of files when it installs dependencies, and any one of these packages can be bugged, even if you pin all your dependencies to a specific version.

Because there might be a dep of a dep of your dep that is not pinned, and someone takes control of the project and publishes a malicious code to steal keys in your code, and hence everybody else's code.

Plain JS also has this problem, because most of the time you are relying on minified bundles that are hard to read and might be hiding a malicious code.

Yes, JS has a dependency culture which is pretty much incompatible with security, though it's not alone-- Rust is also in that boat  (and so I find it a bit alarming to see rust promoted as a solution to security problems.)
Wind_FURY
Legendary
*
Offline Offline

Activity: 2996
Merit: 1871



View Profile
Today at 10:12:18 AM
Merited by vjudeu (1)
 #8

But I think the specific issue is a distraction. It's simple:  DO NOT USE JAVASCRIPT FOR CRYPTOGRAPHY.   If you've used JS with any private key, assume it compromised.

It's not only because of that, but also because (node)JS likes to create oodles of files when it installs dependencies, and any one of these packages can be bugged, even if you pin all your dependencies to a specific version.

Because there might be a dep of a dep of your dep that is not pinned, and someone takes control of the project and publishes a malicious code to steal keys in your code, and hence everybody else's code.

Plain JS also has this problem, because most of the time you are relying on minified bundles that are hard to read and might be hiding a malicious code.


Yes, JS has a dependency culture which is pretty much incompatible with security, though it's not alone-- Rust is also in that boat  (and so I find it a bit alarming to see rust promoted as a solution to security problems.)


 👀

Ser, I merely want to ask a simple question.

You said that,

Quote

No programmer, no matter how skilled can write JS code that doesn't leave secrets laying around in memory. No programmer, no matter how skilled can write JS code that is sure to not leak secrets via side channels.


and that Rust is also "in that boat", does that actually mean that all of those new, "more modern" blockchains with clients that were written wholly and/or party in Rust are also vulnerable to such leaks, and that users should avoid holding any assets in those blockchains?

██████████████████████
█████████████████████████
█████████████████████████
█████████████████████████
█████████████████████████
█████████████████████████
█████████████████████████
█████████████████████████
█████████████████████████
█████████████████████████
█████████████████████████
█████████████████████████
██████████████████████
.SHUFFLE.COM..███████████████████████
███████████████████████
███████████████████████
███████████████████████
███████████████████████
█████████████████████
████████████████████
██████████████████████
████████████████████
██████████████████████
███████████████████████
███████████████████████
███████████████████████
███████████████████████
███████████████████████
███████████████████████
██████████████████████
██████████████████████
██████████████████████
███████████████████████
███████████████████████
███████████████████████
███████████████████████
███████████████████████
███████████████████████
███████████████████████
.
...Next Generation Crypto Casino...
davidlawson001
Newbie
*
Offline Offline

Activity: 1
Merit: 0


View Profile
Today at 11:03:10 AM
 #9

Such an excellent and insightful piece of information! I’m grateful for the valuable content you’ve shared about [url https://sunnyendoscope.com/product-category/automotive-borescope-camera/]automotive borescope camera[/url]. Please continue to update us. Thank you!
vjudeu
Hero Member
*****
Offline Offline

Activity: 791
Merit: 1882



View Profile
Today at 11:13:30 AM
 #10

Quote
does that actually mean that all of those new, "more modern" blockchains with clients that were written wholly and/or party in Rust are also vulnerable to such leaks
Of course. If you use unsafe cryptography, then it will bite you. For example:
Code:
#include <cstdint>
#include <ctime>
#include <iostream>

int main()
{
    std::srand(std::time(nullptr));
    for(std::size_t i=0;i<32;++i)
    {
        int value=std::rand()%256;
        std::cout.width(2);
        std::cout.fill('0');
        std::cout<<std::hex<<value;
    }
}
Does it mean that C++ is unsafe? No. It means, that if you use "std::rand()" from the standard library, then it will be unsafe, because then your seed is only some 32-bit timestamp, and all keys, generated in this way, can be sweeped in a moment. And the same is true for other languages and tools: if you use built-in randomness from many languages, and it uses small seeds, then it will hurt you. That's why Satoshi included OpenSSL, instead of generating private keys in some unsafe way, as shown above.

Edit: example straight from Rust: in a standard library, you have this function: https://docs.rs/rand/latest/rand/trait.SeedableRng.html#method.seed_from_u64
Quote
Code:
fn seed_from_u64(state: u64) -> Self
Create a new PRNG using a u64 seed.

This is a convenience-wrapper around from_seed to allow construction of any SeedableRng from a simple u64 value. It is designed such that low Hamming Weight numbers like 0 and 1 can be used and should still result in good, independent seeds to the PRNG which is returned.

This is not suitable for cryptography, as should be clear given that the input size is only 64 bits.

Implementations for PRNGs may provide their own implementations of this function, but the default implementation should be good enough for all purposes. Changing the implementation of this function should be considered a value-breaking change.
Guess what: if you use it, then your private key will be as weak, as the puzzle #64, if not weaker. And guess what people might do: they can fill this value with the current timestamp, and boom, everyone using it to create private keys is doomed.

█▀▀▀











█▄▄▄
▀▀▀▀▀▀▀▀▀▀▀
e
▄▄▄▄▄▄▄▄▄▄▄
█████████████
████████████▄███
██▐███████▄█████▀
█████████▄████▀
███▐████▄███▀
████▐██████▀
█████▀█████
███████████▄
████████████▄
██▄█████▀█████▄
▄█████████▀█████▀
███████████▀██▀
████▀█████████
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
c.h.
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▀▀▀█











▄▄▄█
▄██████▄▄▄
█████████████▄▄
███████████████
███████████████
███████████████
███████████████
███░░█████████
███▌▐█████████
█████████████
███████████▀
██████████▀
████████▀
▀██▀▀
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!