RandStorm is a Proof of Concept (PoC) that demonstrates the critical security vulnerability in Bitcoin wallets created between 2011 and 2015 using JavaScript-based applications. This vulnerability results from the use of the SecureRandom() function from the JSBN JavaScript library in combination with weaknesses in the Math.random() implementation of web browsers at that time.
WARNING: This project is for educational and research purposes only. The vulnerability demonstrated here affected millions of Bitcoin wallets and led to potential losses of over $2.1 billion USD. Do NOT use this code for malicious purposes.
- Background
- The Vulnerability
- Technical Details
- Affected Systems
- Impact
- Installation
- Usage
- Code Architecture
- Protection Measures
- References
The RandStorm vulnerability was publicly disclosed in 2023 and affects Bitcoin wallets created between 2011 and 2015. The problem lies in how cryptographic keys were generated:
- JSBN Library: Many Bitcoin wallet generators used the JavaScript Big Number (JSBN) library
- SecureRandom(): This library implemented a
SecureRandom()function that used RC4 (Arcfour) as a pseudorandom number generator - Math.random(): The entropy source was
Math.random(), which was cryptographically insecure in old browsers (2011-2015) - Time-based Seeds: Additionally, predictable timestamps were used as seeds
The combination of:
- Weak entropy source (
Math.random()in old browsers) - Predictable seed (timestamp)
- RC4/Arcfour as pseudorandom number generator
led to private keys being generated with significantly reduced entropy. Attackers could reconstruct private keys through brute-force attacks on the limited seed space.
- Seed Calculation: The seed is based on
Math.random()values and a timestamp - Limited Search Space: Timestamps are limited to a specific time period (e.g., 2011-2015)
- Brute-Force: Attackers can try all possible seed combinations
- Key Reconstruction: With a successful seed, the private key can be reconstructed
This project replicates the SecureRandom() function from JSBN in C++:
class SecureRandom {
std::vector<uint8_t> pool; // 256-byte pool
Arcfour* state; // RC4 state
uint32_t fixedSeed; // Time-based seed
};How it works:
- Pool Initialization: Fills a 256-byte pool with values from
Math.random() - Seed Integration: XOR operation with timestamp (Unix epoch)
- Arcfour Initialization: Uses the pool as key for RC4
- Byte Generation: RC4 produces the "random" bytes
class Arcfour {
std::vector<uint8_t> S; // 256-byte S-box
int i, j; // Indices
};Algorithm:
- KSA (Key Scheduling Algorithm): Initializes the S-box based on the pool
- PRGA (Pseudo-Random Generation Algorithm): Generates random bytes
Problem 1: Math.random() Entropy
- Old browsers (2011-2015) had weak
Math.random()implementations - Limited entropy led to predictable patterns
- Only a few thousand possible states instead of 2^256
Problem 2: Time-based Seed
uint64_t currentTime = static_cast<uint64_t>(time(nullptr)) * 1000;
seedInt(static_cast<uint32_t>(currentTime));- Timestamps are limited to a specific time period
- With known creation period: ~126 million seconds (2011-2015)
- Significantly reduces the search space
Problem 3: Pool Size
- Only 256 bytes of entropy in the pool
- After Arcfour initialization, the pool is cleared
- No additional entropy during generation
- 2011-2015: Main vulnerability period
- Early BitcoinJS library: Many wallet generators were based on it
- ~1.4 million Bitcoins in potentially vulnerable wallets
- ~$2.1 billion USD (as of 2023)
- Multiple cryptocurrencies: Bitcoin, Dogecoin, Litecoin, Zcash
- BitcoinJS-based wallet generators
- Web-based wallet creation tools
- Early browser wallet implementations
- Private keys can be reconstructed
- Funds can be stolen if the seed is known
- No recovery option after theft
- Loss of trust in web-based wallet generators
- Awareness of the importance of cryptographically secure random number generators
- Improved security standards in modern implementations
- Visual Studio 2019 or higher (Windows)
- C++17 or higher
- Windows SDK 10.0
- Clone the repository:
git clone https://github.com/[Your-Username]/RandStorm.git
cd RandStorm-
Open Visual Studio:
- Open
RandStorm.slnin Visual Studio
- Open
-
Compile the project:
- Select configuration: Debug x64 or Release x64
- Press
F7or select Build > Build Solution
-
Executable:
- The compiled
.exeis located inx64/Debug/orx64/Release/
- The compiled
cd x64/Debug
RandStorm.exeThe program generates:
- Console: Hexadecimal representation of generated bytes
- debug.txt: Detailed debug information about the entire process
The debug.txt file contains:
- Pool initialization with all 256 bytes
- Seed integration (XOR operations)
- Arcfour S-box after KSA
- Generated random bytes
=== Start der SecureRandom-Replikation ===
[Pool Initialisierung]
pool[0] (High Byte): 123
pool[1] (Low Byte): 45
...
[Seed Integration]
SeedTime aufgerufen mit currentTime: 1393635661000
SeedInt aufgerufen mit x: 1393635661
pool[0] nach XOR mit byte 77: 5
...
[Arcfour Initialisierung]
S-Box nach KSA: 139 158 254 156 ...
[Byte Generation]
Generierte Bytes: 35 4 55 3 15 14 e2 e6 d8 42
=== Ende der SecureRandom-Replikation ===
SecureRandom
βββ pool (256 bytes)
βββ pptr (pool pointer)
βββ state (Arcfour*)
βββ fixedSeed (uint32_t)
Arcfour
βββ S (256-byte S-box)
βββ i, j (indices)
βββ debugFile (ofstream*)
1. SecureRandom Constructor
β
2. initializePool()
βββ Fills pool with Math.random()-like values
βββ seedTime()
βββ seedInt() - XOR with timestamp
β
3. getByte()
β
4. initializeArcfour() (on first call)
βββ Arcfour::init(pool)
β βββ KSA Algorithm
βββ Pool is cleared
β
5. Arcfour::next()
βββ PRGA Algorithm
β
6. Random byte returned
| Function | Description |
|---|---|
initializePool() |
Fills the 256-byte pool with pseudorandom values |
seedTime() |
Integrates timestamp as seed |
seedInt() |
Performs XOR operation with pool |
initializeArcfour() |
Initializes RC4 with pool as key |
Arcfour::init() |
Key Scheduling Algorithm (KSA) |
Arcfour::next() |
Pseudo-Random Generation Algorithm (PRGA) |
getByte() |
Returns next random byte |
-
Use cryptographically secure random number generators:
crypto.getRandomValues()in JavaScript/dev/urandomorCryptGenRandom()in native applications- NEVER use
Math.random()for cryptographic purposes
-
Hardware Entropy:
- Use Hardware Random Number Generators (HRNG)
- Combine multiple entropy sources
-
Seed Management:
- Use sufficient entropy for seeds
- Avoid predictable seeds (timestamp alone)
-
Code Audits:
- Have cryptographic code reviewed by experts
- Use established libraries (e.g., OpenSSL, libsodium)
-
Wallet Migration:
- If you created a wallet between 2011-2015, migrate immediately
- Create a new wallet with modern, trusted software
- Transfer all funds to the new wallet
-
Wallet Software:
- Use current, audited wallet software
- Avoid web-based wallet generators (except from trusted sources)
- Prefer hardware wallets for larger amounts
-
Security Awareness:
- Educate yourself about cryptographic best practices
- Keep software up to date
- JSBN Library - Original JavaScript library
- RC4 Algorithm - Wikipedia article on RC4
- NIST SP 800-90A - Recommendations for random number generators
- RandstormBTC/randstorm - Original PoC repository
This project is for educational and research purposes only. The code is provided "as is" without any warranty. Use for malicious purposes is strictly prohibited.
The authors assume no responsibility for:
- Damages arising from the use of this code
- Illegal activities with this code
- Losses of cryptocurrencies or other assets
Use this code responsibly and for educational purposes only.
This project is a Proof of Concept to demonstrate the RandStorm vulnerability. Contributions to improve documentation and code are welcome.
For questions or comments, please open an issue on GitHub.
Created for Educational Purposes | 2024