Insecure Random Number Generation for Cryptographic Use

High Risk Cryptographic Security
random-number-generationcryptographic-randomnesspseudo-randomsession-idstokensnoncesinitialization-vectorskey-generationpredictable-randomness

What it is

A critical vulnerability where applications use weak, predictable, or pseudo-random number generators for cryptographic operations like key generation, token creation, session IDs, nonces, or initialization vectors. Predictable randomness can lead to session hijacking, key prediction, and complete cryptographic system compromise.

<?php
// PHP - VULNERABLE: Weak session ID and token generation

class VulnerableSessionManager {
    private $sessionStore;
    
    public function __construct() {
        $this->sessionStore = [];
    }
    
    public function createSession($userId) {
        // VULNERABLE: Using predictable session ID generation
        $sessionId = $this->generateWeakSessionId($userId);
        
        $session = [
            'user_id' => $userId,
            'created_at' => time(),
            'csrf_token' => $this->generateWeakCsrfToken(),
            'api_key' => $this->generateWeakApiKey()
        ];
        
        $this->sessionStore[$sessionId] = $session;
        
        return $sessionId;
    }
    
    private function generateWeakSessionId($userId) {
        // VULNERABLE: Predictable session ID using mt_rand()
        $timestamp = time();
        $random1 = mt_rand(1000, 9999);
        $random2 = mt_rand(10000, 99999);
        
        // Predictable combination
        return md5($userId . $timestamp . $random1 . $random2);
    }
    
    private function generateWeakCsrfToken() {
        // VULNERABLE: Using mt_rand() for CSRF token
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $token = '';
        
        for ($i = 0; $i < 32; $i++) {
            $token .= $chars[mt_rand(0, strlen($chars) - 1)];
        }
        
        return $token;
    }
    
    private function generateWeakApiKey() {
        // VULNERABLE: Seeded random with predictable value
        mt_srand(time()); // Predictable seed!
        
        $key = 'ak_';
        for ($i = 0; $i < 40; $i++) {
            $key .= dechex(mt_rand(0, 15));
        }
        
        return $key;
    }
    
    public function generatePasswordResetToken($userId) {
        // VULNERABLE: Using user ID and timestamp
        $timestamp = microtime(true);
        $data = $userId . ':' . $timestamp;
        
        // Weak signing with predictable random
        $random = mt_rand(100000, 999999);
        $signature = hash('sha256', $data . $random);
        
        return base64_encode($data . ':' . $signature);
    }
    
    public function generateTwoFactorCode($userId) {
        // VULNERABLE: Seeded with user ID
        mt_srand($userId + time()); // Predictable!
        return str_pad(mt_rand(0, 999999), 6, '0', STR_PAD_LEFT);
    }
    
    public function generateEncryptionKey($algorithm = 'AES-256') {
        // VULNERABLE: Weak key generation
        $keyLength = ($algorithm === 'AES-256') ? 32 : 16;
        $key = '';
        
        for ($i = 0; $i < $keyLength; $i++) {
            $key .= chr(mt_rand(0, 255));
        }
        
        return base64_encode($key);
    }
    
    public function generateNonce($length = 16) {
        // VULNERABLE: Using rand() for cryptographic nonce
        $nonce = '';
        for ($i = 0; $i < $length; $i++) {
            $nonce .= chr(rand(0, 255)); // Even worse than mt_rand!
        }
        
        return $nonce;
    }
}
<?php
// PHP - SECURE: Cryptographically secure random generation

class SecureSessionManager {
    private $sessionStore;
    
    public function __construct() {
        $this->sessionStore = [];
        
        // Verify cryptographic random functions are available
        if (!function_exists('random_bytes')) {
            throw new Exception('random_bytes() function not available');
        }
        
        if (!function_exists('sodium_crypto_aead_aes256gcm_encrypt')) {
            throw new Exception('Sodium library not available');
        }
    }
    
    public function createSession($userId) {
        // Generate cryptographically secure session ID
        $sessionId = $this->generateSecureSessionId();
        
        $session = [
            'user_id' => $userId,
            'created_at' => time(),
            'csrf_token' => $this->generateSecureCsrfToken(),
            'api_key' => $this->generateSecureApiKey(),
            'nonce' => $this->generateNonce(12) // For AES-GCM
        ];
        
        $this->sessionStore[$sessionId] = $session;
        
        return $sessionId;
    }
    
    private function generateSecureSessionId() {
        // Use random_bytes() for cryptographic security
        $randomBytes = random_bytes(32); // 256 bits
        
        // Convert to URL-safe base64
        return rtrim(strtr(base64_encode($randomBytes), '+/', '-_'), '=');
    }
    
    private function generateSecureCsrfToken() {
        // Generate 256-bit CSRF token
        $tokenBytes = random_bytes(32);
        
        // Return hex-encoded token
        return bin2hex($tokenBytes);
    }
    
    private function generateSecureApiKey() {
        // Generate secure API key with prefix
        $randomBytes = random_bytes(30); // 240 bits
        $randomPart = rtrim(strtr(base64_encode($randomBytes), '+/', '-_'), '=');
        
        return 'ak_' . $randomPart;
    }
    
    public function generatePasswordResetToken($userId) {
        // Generate secure password reset token
        $payload = [
            'user_id' => $userId,
            'timestamp' => time(),
            'nonce' => bin2hex(random_bytes(16))
        ];
        
        $payloadJson = json_encode($payload);
        
        // Get signing key from secure storage (environment variable)
        $signingKey = $this->getSigningKey();
        
        // Create HMAC signature
        $signature = hash_hmac('sha256', $payloadJson, $signingKey, true);
        
        // Combine payload and signature
        $token = base64_encode($payloadJson . $signature);
        
        return rtrim(strtr($token, '+/', '-_'), '=');
    }
    
    public function verifyPasswordResetToken($token, $userId, $maxAge = 3600) {
        try {
            // Decode token
            $decoded = base64_decode(strtr($token . str_repeat('=', 3 - strlen($token) % 4), '-_', '+/'));
            
            // Split payload and signature
            $signature = substr($decoded, -32);
            $payloadJson = substr($decoded, 0, -32);
            
            // Verify signature
            $signingKey = $this->getSigningKey();
            $expectedSignature = hash_hmac('sha256', $payloadJson, $signingKey, true);
            
            if (!hash_equals($signature, $expectedSignature)) {
                return false;
            }
            
            // Verify payload
            $payload = json_decode($payloadJson, true);
            
            if ($payload['user_id'] !== $userId) {
                return false;
            }
            
            if (time() - $payload['timestamp'] > $maxAge) {
                return false; // Token expired
            }
            
            return true;
            
        } catch (Exception $e) {
            return false;
        }
    }
    
    public function generateTwoFactorCode() {
        // Generate cryptographically secure 6-digit code
        $randomBytes = random_bytes(4);
        $randomInt = unpack('N', $randomBytes)[1];
        
        // Use modulo with bias mitigation
        $code = $randomInt % 1000000;
        
        return str_pad($code, 6, '0', STR_PAD_LEFT);
    }
    
    public function generateEncryptionKey($algorithm = 'AES-256-GCM') {
        $keyLengths = [
            'AES-128-GCM' => 16,
            'AES-256-GCM' => 32,
            'ChaCha20-Poly1305' => 32
        ];
        
        if (!isset($keyLengths[$algorithm])) {
            throw new InvalidArgumentException('Unsupported algorithm');
        }
        
        $keyLength = $keyLengths[$algorithm];
        $keyBytes = random_bytes($keyLength);
        
        return base64_encode($keyBytes);
    }
    
    public function generateNonce($length = 12) {
        // Generate cryptographically secure nonce
        if ($length <= 0 || $length > 32) {
            throw new InvalidArgumentException('Invalid nonce length');
        }
        
        return random_bytes($length);
    }
    
    public function encryptSessionData($data, $key) {
        // Use sodium for authenticated encryption
        $nonce = random_bytes(SODIUM_CRYPTO_AEAD_AES256GCM_NPUBBYTES);
        
        $ciphertext = sodium_crypto_aead_aes256gcm_encrypt(
            json_encode($data),
            '', // No additional data
            $nonce,
            $key
        );
        
        return [
            'nonce' => base64_encode($nonce),
            'ciphertext' => base64_encode($ciphertext)
        ];
    }
    
    public function decryptSessionData($encryptedData, $key) {
        $nonce = base64_decode($encryptedData['nonce']);
        $ciphertext = base64_decode($encryptedData['ciphertext']);
        
        $plaintext = sodium_crypto_aead_aes256gcm_decrypt(
            $ciphertext,
            '', // No additional data
            $nonce,
            $key
        );
        
        if ($plaintext === false) {
            throw new Exception('Decryption failed');
        }
        
        return json_decode($plaintext, true);
    }
    
    private function getSigningKey() {
        $key = $_ENV['SESSION_SIGNING_KEY'] ?? null;
        
        if (!$key) {
            throw new Exception('SESSION_SIGNING_KEY environment variable not set');
        }
        
        return base64_decode($key);
    }
    
    public function generateMasterKey() {
        // Generate 512-bit master key for key derivation
        $masterKey = random_bytes(64);
        
        return base64_encode($masterKey);
    }
    
    public function testRandomness() {
        // Basic sanity check for random number generator
        $test1 = random_bytes(32);
        $test2 = random_bytes(32);
        
        if ($test1 === $test2) {
            throw new Exception('Random number generator failure - identical sequences');
        }
        
        // Check for all-zero bytes (extremely unlikely but possible)
        if (strlen(trim($test1, "\0")) === 0) {
            throw new Exception('Random number generator produced all-zero sequence');
        }
        
        return true;
    }
}

💡 Why This Fix Works

The vulnerable implementation uses predictable pseudo-random functions like mt_rand() and rand() for cryptographic purposes, seeds generators with predictable values, and creates patterns that can be exploited. The secure version uses random_bytes() for cryptographic randomness, implements proper token verification with timing-safe comparisons, and uses authenticated encryption for sensitive data.

// Go - VULNERABLE: Weak cryptographic key generation for cryptocurrency
package main

import (
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"math/rand"
	"time"
	"strconv"
)

type VulnerableWallet struct {
	PrivateKey string
	PublicKey  string
	Address    string
}

// VULNERABLE: Using math/rand for cryptographic key generation
func NewVulnerableWallet(userID int) *VulnerableWallet {
	// NEVER seed with predictable values!
	rand.Seed(time.Now().Unix() + int64(userID)) // Predictable seed!
	
	// Generate "private key" using weak random
	privateKey := generateWeakPrivateKey()
	
	// Generate public key (simplified)
	publicKey := generateWeakPublicKey(privateKey)
	
	// Generate address
	address := generateWeakAddress(publicKey)
	
	return &VulnerableWallet{
		PrivateKey: privateKey,
		PublicKey:  publicKey,
		Address:    address,
	}
}

func generateWeakPrivateKey() string {
	// VULNERABLE: Using math/rand for private key!
	// Real cryptocurrency private keys need 256 bits of entropy
	var key []byte
	for i := 0; i < 32; i++ {
		key = append(key, byte(rand.Intn(256)))
	}
	return hex.EncodeToString(key)
}

func generateWeakPublicKey(privateKey string) string {
	// Simplified public key generation (also weak)
	hash := sha256.Sum256([]byte(privateKey))
	return hex.EncodeToString(hash[:])
}

func generateWeakAddress(publicKey string) string {
	// Weak address generation
	hash := sha256.Sum256([]byte(publicKey))
	return "1" + hex.EncodeToString(hash[:20]) // Bitcoin-style address
}

func (w *VulnerableWallet) GenerateWeakSignature(message string) string {
	// VULNERABLE: Weak signature using predictable nonce
	nonce := rand.Int63() // Predictable nonce - can lead to private key recovery!
	
	// Simplified signature (real ECDSA would be more complex)
	signatureData := message + w.PrivateKey + strconv.FormatInt(nonce, 10)
	hash := sha256.Sum256([]byte(signatureData))
	
	return hex.EncodeToString(hash[:])
}

func generateWeakMnemonic() []string {
	// VULNERABLE: Weak mnemonic generation
	wordlist := []string{"abandon", "ability", "able", "about", "above", "absent", "absorb", "abstract", "absurd", "abuse"}
	
	var mnemonic []string
	for i := 0; i < 12; i++ {
		index := rand.Intn(len(wordlist))
		mnemonic = append(mnemonic, wordlist[index])
	}
	
	return mnemonic
}

func generateWeakSeed(userInput string) []byte {
	// VULNERABLE: Using user input as entropy source
	combined := userInput + strconv.FormatInt(time.Now().Unix(), 10)
	hash := sha256.Sum256([]byte(combined))
	return hash[:]
}

// Vulnerable HD wallet key derivation
func deriveWeakChildKey(parentKey string, index int) string {
	// VULNERABLE: Predictable child key derivation
	combined := parentKey + strconv.Itoa(index)
	hash := sha256.Sum256([]byte(combined))
	return hex.EncodeToString(hash[:])
}

func main() {
	// Create vulnerable wallet
	wallet := NewVulnerableWallet(12345)
	
	fmt.Printf("Private Key: %s\n", wallet.PrivateKey)
	fmt.Printf("Public Key: %s\n", wallet.PublicKey)
	fmt.Printf("Address: %s\n", wallet.Address)
	
	// Generate weak signature
	message := "Transfer 1 BTC to address xyz"
	signature := wallet.GenerateWeakSignature(message)
	fmt.Printf("Signature: %s\n", signature)
	
	// Generate weak mnemonic
	mnemonic := generateWeakMnemonic()
	fmt.Printf("Mnemonic: %v\n", mnemonic)
}
// Go - SECURE: Cryptographically secure key generation for cryptocurrency
package main

import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"crypto/ecdsa"
	"crypto/elliptic"
	"math/big"
	"errors"
	"golang.org/x/crypto/pbkdf2"
	"crypto/hmac"
)

type SecureWallet struct {
	PrivateKey *ecdsa.PrivateKey
	PublicKey  *ecdsa.PublicKey
	Address    string
	ChainCode  []byte // For HD wallet
}

// SECURE: Using crypto/rand for cryptographic key generation
func NewSecureWallet() (*SecureWallet, error) {
	// Use crypto/rand for cryptographically secure random generation
	privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		return nil, fmt.Errorf("failed to generate private key: %v", err)
	}
	
	// Generate chain code for HD wallet
	chainCode, err := generateSecureChainCode()
	if err != nil {
		return nil, fmt.Errorf("failed to generate chain code: %v", err)
	}
	
	// Generate address from public key
	address, err := generateSecureAddress(&privateKey.PublicKey)
	if err != nil {
		return nil, fmt.Errorf("failed to generate address: %v", err)
	}
	
	return &SecureWallet{
		PrivateKey: privateKey,
		PublicKey:  &privateKey.PublicKey,
		Address:    address,
		ChainCode:  chainCode,
	}, nil
}

func generateSecureChainCode() ([]byte, error) {
	// Generate 32 bytes of cryptographically secure randomness
	chainCode := make([]byte, 32)
	_, err := rand.Read(chainCode)
	if err != nil {
		return nil, err
	}
	return chainCode, nil
}

func generateSecureAddress(publicKey *ecdsa.PublicKey) (string, error) {
	// Serialize public key
	pubKeyBytes := elliptic.Marshal(publicKey.Curve, publicKey.X, publicKey.Y)
	
	// Hash public key
	hash := sha256.Sum256(pubKeyBytes)
	
	// Take first 20 bytes and create address
	addressHash := hash[:20]
	
	// Add version byte and checksum (simplified Bitcoin address)
	versioned := append([]byte{0x00}, addressHash...)
	checksum := sha256.Sum256(versioned)
	checksum = sha256.Sum256(checksum[:])
	
	fullAddress := append(versioned, checksum[:4]...)
	
	return "1" + hex.EncodeToString(fullAddress), nil
}

func (w *SecureWallet) GenerateSecureSignature(message string) (r, s *big.Int, err error) {
	// Hash the message
	msgHash := sha256.Sum256([]byte(message))
	
	// Generate cryptographically secure signature
	// ECDSA automatically uses secure random nonce generation
	r, s, err = ecdsa.Sign(rand.Reader, w.PrivateKey, msgHash[:])
	if err != nil {
		return nil, nil, fmt.Errorf("failed to sign message: %v", err)
	}
	
	return r, s, nil
}

func VerifySignature(publicKey *ecdsa.PublicKey, message string, r, s *big.Int) bool {
	msgHash := sha256.Sum256([]byte(message))
	return ecdsa.Verify(publicKey, msgHash[:], r, s)
}

// Secure mnemonic generation using BIP39 standard
func GenerateSecureMnemonic(bitLength int) ([]string, error) {
	if bitLength%32 != 0 || bitLength < 128 || bitLength > 256 {
		return nil, errors.New("invalid bit length: must be 128, 160, 192, 224, or 256")
	}
	
	// Generate cryptographically secure entropy
	entropyLength := bitLength / 8
	entropy := make([]byte, entropyLength)
	_, err := rand.Read(entropy)
	if err != nil {
		return nil, fmt.Errorf("failed to generate entropy: %v", err)
	}
	
	// Add checksum
	checksum := sha256.Sum256(entropy)
	checksumBits := bitLength / 32
	
	// Convert to mnemonic (simplified - real implementation would use BIP39 wordlist)
	// This is a demonstration - use a proper BIP39 library in production
	wordCount := (bitLength + checksumBits) / 11
	mnemonic := make([]string, wordCount)
	
	// Simplified word generation (use proper BIP39 in production)
	for i := 0; i < wordCount; i++ {
		mnemonic[i] = fmt.Sprintf("word%d", i) // Placeholder
	}
	
	return mnemonic, nil
}

// Secure seed generation from mnemonic
func GenerateSecureSeed(mnemonic []string, passphrase string) []byte {
	// Combine mnemonic words
	mnemonicString := ""
	for i, word := range mnemonic {
		if i > 0 {
			mnemonicString += " "
		}
		mnemonicString += word
	}
	
	// Use PBKDF2 for secure key derivation
	salt := "mnemonic" + passphrase
	seed := pbkdf2.Key([]byte(mnemonicString), []byte(salt), 2048, 64, sha256.New)
	
	return seed
}

// Secure HD wallet key derivation (BIP32)
func (w *SecureWallet) DeriveSecureChildKey(index uint32, hardened bool) (*SecureWallet, error) {
	if hardened {
		index += 0x80000000
	}
	
	// Serialize parent public key
	pubKeyBytes := elliptic.Marshal(w.PublicKey.Curve, w.PublicKey.X, w.PublicKey.Y)
	
	// Create HMAC input
	var hmacInput []byte
	if hardened {
		// Use private key for hardened derivation
		privKeyBytes := w.PrivateKey.D.Bytes()
		// Pad to 32 bytes
		for len(privKeyBytes) < 32 {
			privKeyBytes = append([]byte{0}, privKeyBytes...)
		}
		hmacInput = append([]byte{0}, privKeyBytes...)
	} else {
		// Use public key for non-hardened derivation
		hmacInput = pubKeyBytes
	}
	
	// Add index
	indexBytes := make([]byte, 4)
	indexBytes[0] = byte(index >> 24)
	indexBytes[1] = byte(index >> 16)
	indexBytes[2] = byte(index >> 8)
	indexBytes[3] = byte(index)
	hmacInput = append(hmacInput, indexBytes...)
	
	// Compute HMAC
	mac := hmac.New(sha256.New, w.ChainCode)
	mac.Write(hmacInput)
	hmacResult := mac.Sum(nil)
	
	// Split result
	childPrivKeyInt := new(big.Int).SetBytes(hmacResult[:32])
	childChainCode := hmacResult[32:]
	
	// Derive child private key
	curve := elliptic.P256()
	childPrivKeyInt.Add(childPrivKeyInt, w.PrivateKey.D)
	childPrivKeyInt.Mod(childPrivKeyInt, curve.Params().N)
	
	// Create child private key
	childPrivKey := &ecdsa.PrivateKey{
		PublicKey: ecdsa.PublicKey{Curve: curve},
		D:         childPrivKeyInt,
	}
	childPrivKey.PublicKey.X, childPrivKey.PublicKey.Y = curve.ScalarBaseMult(childPrivKeyInt.Bytes())
	
	// Generate address
	childAddress, err := generateSecureAddress(&childPrivKey.PublicKey)
	if err != nil {
		return nil, err
	}
	
	return &SecureWallet{
		PrivateKey: childPrivKey,
		PublicKey:  &childPrivKey.PublicKey,
		Address:    childAddress,
		ChainCode:  childChainCode,
	}, nil
}

func validateEntropy(entropy []byte) error {
	// Check for all-zero entropy
	var isAllZero = true
	for _, b := range entropy {
		if b != 0 {
			isAllZero = false
			break
		}
	}
	
	if isAllZero {
		return errors.New("entropy is all zeros")
	}
	
	// Basic entropy check (real implementation would be more sophisticated)
	if len(entropy) < 16 {
		return errors.New("insufficient entropy")
	}
	
	return nil
}

func main() {
	// Create secure wallet
	wallet, err := NewSecureWallet()
	if err != nil {
		fmt.Printf("Error creating wallet: %v\n", err)
		return
	}
	
	fmt.Printf("Address: %s\n", wallet.Address)
	
	// Generate secure signature
	message := "Transfer 1 BTC to address xyz"
	r, s, err := wallet.GenerateSecureSignature(message)
	if err != nil {
		fmt.Printf("Error signing message: %v\n", err)
		return
	}
	
	fmt.Printf("Signature (r): %s\n", r.String())
	fmt.Printf("Signature (s): %s\n", s.String())
	
	// Verify signature
	isValid := VerifySignature(wallet.PublicKey, message, r, s)
	fmt.Printf("Signature valid: %t\n", isValid)
	
	// Generate secure mnemonic
	mnemonic, err := GenerateSecureMnemonic(256)
	if err != nil {
		fmt.Printf("Error generating mnemonic: %v\n", err)
		return
	}
	
	fmt.Printf("Mnemonic: %v\n", mnemonic)
	
	// Derive child key
	childWallet, err := wallet.DeriveSecureChildKey(0, true)
	if err != nil {
		fmt.Printf("Error deriving child key: %v\n", err)
		return
	}
	
	fmt.Printf("Child Address: %s\n", childWallet.Address)
}

💡 Why This Fix Works

The vulnerable implementation uses math/rand with predictable seeds for cryptocurrency key generation, creates weak signatures with predictable nonces (leading to private key recovery), and uses insufficient entropy sources. The secure version uses crypto/rand for all cryptographic operations, implements proper ECDSA with secure nonce generation, follows BIP32/BIP39 standards for HD wallets, and includes entropy validation.

Why it happens

Developers use standard library random functions (like Math.random(), random.randint(), or System.Random) for generating cryptographic material. These functions are designed for general-purpose use and are not cryptographically secure - they can be predicted if an attacker observes a few outputs.

Root causes

Using Language Built-in Random Functions for Cryptography

Developers use standard library random functions (like Math.random(), random.randint(), or System.Random) for generating cryptographic material. These functions are designed for general-purpose use and are not cryptographically secure - they can be predicted if an attacker observes a few outputs.

Preview example – JAVASCRIPT
// JavaScript - VULNERABLE: Using Math.random() for cryptographic purposes
class VulnerableTokenGenerator {
    generateSessionId() {
        // Math.random() is NOT cryptographically secure!
        return Math.random().toString(36).substring(2, 15) + 
               Math.random().toString(36).substring(2, 15);
    }
    
    generateApiKey() {
        const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        let result = '';
        
        // Predictable random key generation
        for (let i = 0; i < 32; i++) {
            result += chars.charAt(Math.floor(Math.random() * chars.length));
        }
        return result;
    }
    
    generateCsrfToken() {
        // Weak CSRF token using timestamp + random
        return Date.now().toString() + Math.random().toString();
    }
}

Seeded Pseudo-Random Generators with Predictable Seeds

Using pseudo-random number generators with predictable seeds like timestamps, user IDs, or sequential counters. Even with cryptographically strong PRNGs, a predictable seed makes the entire sequence deterministic and exploitable by attackers.

Preview example – PYTHON
// Python - VULNERABLE: Predictable seeding of random generators
import random
import time
import os

class InsecureRandomGenerator:
    def __init__(self, user_id):
        # VULNERABLE: Using predictable seed
        seed = int(time.time()) + user_id  # Predictable seed!
        random.seed(seed)
        
        # Even worse - using user_id as seed
        self.user_rng = random.Random(user_id)
    
    def generate_password_reset_token(self):
        # Predictable token generation
        return ''.join(random.choices('abcdefghijklmnopqrstuvwxyz0123456789', k=32))
    
    def generate_encryption_iv(self):
        # NEVER use predictable IV generation!
        return bytes([random.randint(0, 255) for _ in range(16)])
    
    def generate_session_key(self):
        # Weak session key using sequential seed
        seed = int(time.time() * 1000)  # Millisecond timestamp
        temp_rng = random.Random(seed)
        return temp_rng.getrandbits(256).to_bytes(32, 'big')
    
    def generate_otp(self):
        # Predictable OTP generation
        return str(random.randint(100000, 999999))

Linear Congruential Generators for Security

Using Linear Congruential Generators (LCGs) or other predictable algorithms for cryptographic random number generation. LCGs have short periods and can be easily predicted once the internal state is known, making them completely unsuitable for security purposes.

Preview example – CSHARP
// C# - VULNERABLE: Using System.Random for cryptographic operations
using System;
using System.Text;

public class WeakRandomCrypto
{
    private readonly Random random;
    
    public WeakRandomCrypto()
    {
        // System.Random uses LCG - predictable!
        random = new Random();
    }
    
    public WeakRandomCrypto(int seed)
    {
        // Even worse - deterministic seed
        random = new Random(seed);
    }
    
    public string GenerateJwtSecret()
    {
        // NEVER use System.Random for JWT secrets!
        var bytes = new byte[64];
        random.NextBytes(bytes);
        return Convert.ToBase64String(bytes);
    }
    
    public byte[] GenerateEncryptionKey(int keySize)
    {
        // Weak encryption key generation
        var key = new byte[keySize / 8];
        random.NextBytes(key);
        return key;
    }
    
    public string GeneratePasswordSalt()
    {
        // Predictable password salt
        var saltBytes = new byte[32];
        random.NextBytes(saltBytes);
        return Convert.ToBase64String(saltBytes);
    }
    
    public int GenerateTwoFactorCode()
    {
        // Weak 2FA code generation
        return random.Next(100000, 999999);
    }
}

Insufficient Entropy Sources

Relying on low-entropy sources like system time, process IDs, or user-provided data for random number generation. These sources don't provide enough unpredictability for cryptographic security and can be influenced or predicted by attackers.

Preview example – JAVA
// Java - VULNERABLE: Low entropy random number generation
import java.security.SecureRandom;
import java.util.concurrent.ThreadLocalRandom;
import java.time.Instant;

public class LowEntropyRandom {
    
    public byte[] generateWeakKey() {
        // VULNERABLE: Using current time as entropy source
        long currentTime = System.currentTimeMillis();
        int processId = (int) ProcessHandle.current().pid();
        
        // Combining predictable values
        long seed = currentTime ^ processId;
        
        // Even SecureRandom becomes weak with predictable seed
        SecureRandom sr = new SecureRandom();
        sr.setSeed(seed);  // NEVER manually seed SecureRandom!
        
        byte[] key = new byte[32];
        sr.nextBytes(key);
        return key;
    }
    
    public String generateSessionId(String username) {
        // VULNERABLE: Using username as part of randomness
        long userHash = username.hashCode();
        long timestamp = Instant.now().getEpochSecond();
        
        // Predictable combination
        long seed = userHash ^ timestamp;
        
        return Long.toHexString(seed) + Long.toHexString(System.nanoTime());
    }
    
    public byte[] generateNonce() {
        // VULNERABLE: Using ThreadLocalRandom for cryptographic nonce
        byte[] nonce = new byte[12];
        
        // ThreadLocalRandom is NOT cryptographically secure
        for (int i = 0; i < nonce.length; i++) {
            nonce[i] = (byte) ThreadLocalRandom.current().nextInt(256);
        }
        
        return nonce;
    }
    
    public String generateApiToken(int userId) {
        // VULNERABLE: Using user ID and timestamp
        StringBuilder token = new StringBuilder();
        
        // Predictable token structure
        token.append(Integer.toHexString(userId));
        token.append("-");
        token.append(Long.toHexString(System.currentTimeMillis()));
        token.append("-");
        
        // Adding weak random component
        ThreadLocalRandom random = ThreadLocalRandom.current();
        for (int i = 0; i < 16; i++) {
            token.append(Integer.toHexString(random.nextInt(16)));
        }
        
        return token.toString();
    }
}

Fixes

1

Use Cryptographically Secure Random Number Generators

Replace all weak random number generators with cryptographically secure alternatives like crypto.getRandomValues(), os.urandom(), SecureRandom, or RNGCryptoServiceProvider. These generators use entropy from the operating system and are suitable for cryptographic purposes.

View implementation – JAVASCRIPT
// JavaScript - SECURE: Using crypto.getRandomValues()
class SecureTokenGenerator {
    generateSessionId() {
        // Use crypto.getRandomValues() for cryptographic randomness
        const array = new Uint8Array(16);
        crypto.getRandomValues(array);
        
        // Convert to hex string
        return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
    }
    
    generateApiKey(length = 32) {
        const array = new Uint8Array(length);
        crypto.getRandomValues(array);
        
        // Convert to base64url for API key format
        return btoa(String.fromCharCode(...array))
            .replace(/\+/g, '-')
            .replace(/\//g, '_')
            .replace(/=/g, '');
    }
    
    generateCsrfToken() {
        // Strong CSRF token
        const array = new Uint8Array(32);
        crypto.getRandomValues(array);
        return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
    }
    
    generateNonce(length = 12) {
        // Cryptographically secure nonce for AES-GCM
        const nonce = new Uint8Array(length);
        crypto.getRandomValues(nonce);
        return nonce;
    }
    
    generateSecurePassword(length = 16) {
        const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*';
        const array = new Uint8Array(length);
        crypto.getRandomValues(array);
        
        return Array.from(array, byte => charset[byte % charset.length]).join('');
    }
}
2

Implement Proper Entropy Sources

Use operating system entropy sources and never manually seed cryptographic random number generators. Allow the system to manage entropy collection from hardware random number generators, keyboard/mouse timing, disk seek times, and other unpredictable sources.

View implementation – PYTHON
# Python - SECURE: Using os.urandom() and secrets module
import secrets
import os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
import base64

class SecureRandomGenerator:
    def __init__(self):
        # No seeding required - let OS handle entropy
        pass
    
    def generate_password_reset_token(self):
        # Use secrets module for cryptographic randomness
        return secrets.token_urlsafe(32)  # 256 bits of entropy
    
    def generate_encryption_iv(self, algorithm='AES'):
        if algorithm == 'AES':
            # 128-bit IV for AES
            return os.urandom(16)
        elif algorithm == 'ChaCha20':
            # 96-bit nonce for ChaCha20
            return os.urandom(12)
        else:
            raise ValueError(f"Unknown algorithm: {algorithm}")
    
    def generate_encryption_key(self, key_size=256):
        # Generate cryptographically secure key
        key_bytes = key_size // 8
        return os.urandom(key_bytes)
    
    def generate_session_key(self):
        # Strong session key generation
        return secrets.token_bytes(32)  # 256-bit session key
    
    def generate_otp(self, digits=6):
        # Secure OTP generation
        max_value = 10 ** digits
        # Use rejection sampling to avoid modulo bias
        while True:
            value = secrets.randbits(32)
            if value < max_value:
                return str(value).zfill(digits)
    
    def generate_salt(self, length=32):
        # Random salt for password hashing
        return os.urandom(length)
    
    def generate_csrf_token(self):
        # CSRF token with timestamp and random component
        random_part = secrets.token_bytes(24)
        return base64.urlsafe_b64encode(random_part).decode('ascii').rstrip('=')
    
    def generate_api_key(self):
        # Secure API key generation
        prefix = 'sk_'  # API key prefix
        random_part = secrets.token_urlsafe(40)  # ~320 bits
        return prefix + random_part
    
    def generate_jwt_secret(self):
        # JWT signing secret (should be stored securely)
        return secrets.token_bytes(64)  # 512-bit secret
3

Use Platform-Specific Secure Random APIs

Leverage platform-specific cryptographic random number generators that are designed for security. These APIs typically use hardware random number generators when available and maintain proper entropy pools.

View implementation – CSHARP
// C# - SECURE: Using RNGCryptoServiceProvider and RandomNumberGenerator
using System;
using System.Security.Cryptography;
using System.Text;

public class SecureRandomCrypto
{
    private readonly RandomNumberGenerator rng;
    
    public SecureRandomCrypto()
    {
        // Use cryptographically secure RNG
        rng = RandomNumberGenerator.Create();
    }
    
    public string GenerateJwtSecret()
    {
        // Generate 512-bit JWT secret
        byte[] secretBytes = new byte[64];
        rng.GetBytes(secretBytes);
        return Convert.ToBase64String(secretBytes);
    }
    
    public byte[] GenerateEncryptionKey(int keySize)
    {
        // Generate secure encryption key
        byte[] key = new byte[keySize / 8];
        rng.GetBytes(key);
        return key;
    }
    
    public string GeneratePasswordSalt()
    {
        // Generate 256-bit salt
        byte[] saltBytes = new byte[32];
        rng.GetBytes(saltBytes);
        return Convert.ToBase64String(saltBytes);
    }
    
    public string GenerateTwoFactorCode()
    {
        // Secure 6-digit 2FA code generation
        byte[] randomBytes = new byte[4];
        rng.GetBytes(randomBytes);
        
        // Convert to int and use modulo with proper bias handling
        uint randomInt = BitConverter.ToUInt32(randomBytes, 0);
        int code = (int)(randomInt % 1000000);
        
        return code.ToString("D6");
    }
    
    public byte[] GenerateNonce(int length)
    {
        // Generate cryptographic nonce
        byte[] nonce = new byte[length];
        rng.GetBytes(nonce);
        return nonce;
    }
    
    public string GenerateSessionId()
    {
        // Generate 256-bit session ID
        byte[] sessionBytes = new byte[32];
        rng.GetBytes(sessionBytes);
        
        // Convert to hex string
        StringBuilder sb = new StringBuilder();
        foreach (byte b in sessionBytes)
        {
            sb.Append(b.ToString("x2"));
        }
        
        return sb.ToString();
    }
    
    public string GenerateApiToken()
    {
        // Generate secure API token
        byte[] tokenBytes = new byte[40]; // 320 bits
        rng.GetBytes(tokenBytes);
        
        return Convert.ToBase64String(tokenBytes)
            .Replace('+', '-')
            .Replace('/', '_')
            .TrimEnd('=');
    }
    
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            rng?.Dispose();
        }
    }
    
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}
4

Implement Secure Random with Proper Error Handling

Always check for errors when generating random numbers and implement fallback strategies. Monitor entropy levels on systems where this information is available, and fail securely when insufficient entropy is detected.

View implementation – JAVA
// Java - SECURE: Comprehensive secure random implementation
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import java.nio.ByteBuffer;
import java.time.Instant;

public class EnterpriseSecureRandom {
    private final SecureRandom secureRandom;
    private final String algorithm;
    
    public EnterpriseSecureRandom() throws NoSuchAlgorithmException {
        // Use strongest available algorithm
        try {
            // Try to use NativePRNG on Unix systems
            secureRandom = SecureRandom.getInstance("NativePRNG");
            algorithm = "NativePRNG";
        } catch (NoSuchAlgorithmException e) {
            try {
                // Fallback to SHA1PRNG
                secureRandom = SecureRandom.getInstance("SHA1PRNG");
                algorithm = "SHA1PRNG";
            } catch (NoSuchAlgorithmException e2) {
                // Use default implementation
                secureRandom = new SecureRandom();
                algorithm = "Default";
            }
        }
        
        // Let SecureRandom self-seed - NEVER manually seed!
        // secureRandom.setSeed() should NEVER be called
    }
    
    public byte[] generateSecureKey(int keySize) throws SecurityException {
        if (keySize <= 0 || keySize % 8 != 0) {
            throw new IllegalArgumentException("Key size must be positive and divisible by 8");
        }
        
        byte[] key = new byte[keySize / 8];
        
        try {
            secureRandom.nextBytes(key);
            
            // Verify we got non-zero bytes (extremely rare but possible)
            if (isAllZeros(key)) {
                throw new SecurityException("Generated all-zero key - entropy may be exhausted");
            }
            
            return key;
        } catch (Exception e) {
            throw new SecurityException("Failed to generate secure key: " + e.getMessage(), e);
        }
    }
    
    public String generateSessionId() throws SecurityException {
        byte[] sessionBytes = generateSecureKey(256); // 32 bytes
        
        // Use URL-safe base64 encoding
        return Base64.getUrlEncoder().withoutPadding().encodeToString(sessionBytes);
    }
    
    public byte[] generateNonce(int length) throws SecurityException {
        if (length <= 0) {
            throw new IllegalArgumentException("Nonce length must be positive");
        }
        
        byte[] nonce = new byte[length];
        secureRandom.nextBytes(nonce);
        
        return nonce;
    }
    
    public String generateApiToken(String prefix) throws SecurityException {
        if (prefix == null) {
            prefix = "sk_";
        }
        
        // Generate 40 bytes (320 bits) of randomness
        byte[] tokenBytes = generateSecureKey(320);
        String randomPart = Base64.getUrlEncoder().withoutPadding().encodeToString(tokenBytes);
        
        return prefix + randomPart;
    }
    
    public int generateSecureOTP(int digits) throws SecurityException {
        if (digits < 4 || digits > 10) {
            throw new IllegalArgumentException("OTP digits must be between 4 and 10");
        }
        
        int maxValue = (int) Math.pow(10, digits);
        
        // Use rejection sampling to avoid modulo bias
        int attempts = 0;
        while (attempts < 100) { // Prevent infinite loops
            int randomInt = secureRandom.nextInt();
            
            // Ensure positive value
            randomInt = Math.abs(randomInt);
            
            if (randomInt < maxValue) {
                return randomInt;
            }
            attempts++;
        }
        
        throw new SecurityException("Failed to generate OTP after 100 attempts");
    }
    
    public void testRandomness() {
        // Basic randomness test - check for obvious patterns
        byte[] test1 = new byte[32];
        byte[] test2 = new byte[32];
        
        secureRandom.nextBytes(test1);
        secureRandom.nextBytes(test2);
        
        if (java.util.Arrays.equals(test1, test2)) {
            throw new SecurityException("Random number generator produced identical sequences");
        }
        
        if (isAllZeros(test1) || isAllZeros(test2)) {
            throw new SecurityException("Random number generator produced all-zero sequence");
        }
    }
    
    private boolean isAllZeros(byte[] array) {
        for (byte b : array) {
            if (b != 0) {
                return false;
            }
        }
        return true;
    }
    
    public String getAlgorithmInfo() {
        return String.format("Algorithm: %s, Provider: %s", 
                           algorithm, 
                           secureRandom.getProvider().getName());
    }
}

Detect This Vulnerability in Your Code

Sourcery automatically identifies insecure random number generation for cryptographic use and many other security issues in your codebase.