सामग्री पर जाएँ
HexaTransfer
ब्लॉग पर वापस
एन्क्रिप्शन और सुरक्षा

सुरक्षित रैंडम नंबर जेनरेशन: मजबूत क्रिप्टो की नींव

सुरक्षित रैंडम नंबर जेनरेशन एन्क्रिप्शन के लिए महत्वपूर्ण है। crypto.getRandomValues कैसे काम करता है और कमज़ोर रैंडमनेस सुरक्षा क्यों तोड़ती है।

JavaScript में crypto.getRandomValues(buffer) एकमात्र सही तरीका है क्रिप्टोग्राफ़िक रैंडम बाइट्स पाने का — यह ऑपरेटिंग सिस्टम के CSPRNG से भरता है: Linux/macOS पर /dev/urandom, Windows पर BCryptGenRandom, iOS/macOS पर SecRandomCopyBytesMath.random() का इस्तेमाल किसी भी सुरक्षा-संबंधी काम में बिल्कुल न करें — यह Mulberry32 या xorshift-स्टाइल PRNG है जो speed के लिए बना है, unpredictability के लिए नहीं, और कुछ आउटपुट देखने के बाद इसकी पूरी स्थिति का अनुमान लगाया जा सकता है। कमज़ोर RNG AES keys, TLS handshakes, GCM nonce uniqueness, token unguessability — हर उस security primitive को तोड़ता है जो unpredictable बिट्स पर निर्भर है।

PRNG और CSPRNG में अंतर

PRNG (pseudo-random number generator) एक seed से deterministic stream बनाता है। seed और algorithm दे दो, सारा output दोबारा बना सकते हैं। गेम्स, simulations और Monte Carlo methods के लिए ठीक है — क्रिप्टोग्राफ़ी के लिए घातक।

CSPRNG (cryptographically secure PRNG) एक सच्चे entropy source से seed होता है: thermal noise, interrupt timing, hardware RNG instructions जैसे Intel का RDSEED। इसका design सुनिश्चित करता है कि output computationally सच्ची रैंडमनेस से अप्रभेद्य हो, और पिछला output देखकर भविष्य का अनुमान न लगाया जा सके।

JavaScript दोनों देता है। Math.random() PRNG है। crypto.getRandomValues() OS के CSPRNG का wrapper है। कोड की एक लाइन का फ़र्क, सुरक्षा का बहुत बड़ा फ़र्क।

सही तरीके से उपयोग

// 256-bit AES key के लिए रैंडम बाइट्स
const keyBytes = crypto.getRandomValues(new Uint8Array(32));

// 96-bit GCM nonce
const nonce = crypto.getRandomValues(new Uint8Array(12));

// 128-bit salt
const salt = crypto.getRandomValues(new Uint8Array(16));

// URL-safe रैंडम token
const tokenBytes = crypto.getRandomValues(new Uint8Array(32));
const token = btoa(String.fromCharCode(...tokenBytes))
  .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');

crypto.getRandomValues() synchronous है, buffer in-place भरता है, buffer return करता है। एक call में अधिकतम 65,536 bytes (spec-imposed quota)। ज़्यादा रैंडम material के लिए बार-बार call करें।

Node.js में समतुल्य तरीके

const { randomBytes, randomFillSync, webcrypto } = require('crypto');

const keyBytes = randomBytes(32);  // Buffer return करता है
// या Web Crypto-compatible
const nonce = webcrypto.getRandomValues(new Uint8Array(12));

Node का randomBytes उसी underlying CSPRNG से लेता है जो Web Crypto उपयोग करता है। दोनों environments में चलने वाले isomorphic code के लिए webcrypto.getRandomValues browser से exactly match करता है।

Math.random क्यों फेल होता है

V8 (Chrome/Node), SpiderMonkey (Firefox), और JavaScriptCore (Safari) सभी Math.random() को fast PRNG के रूप में implement करते हैं, बिना किसी क्रिप्टोग्राफ़िक guarantee के। V8 xorshift128+ variant उपयोग करता है। शोधकर्ताओं ने दिखाया है कि ~5 outputs देखने के बाद attacker internal state recover कर सकता है और भविष्य के सारे outputs predict कर सकता है। 2015 में Mike Pound और colleagues ने real-world bug bounties में V8 का Math.random state reverse किया।

अगर आप Math.random() से session tokens, password reset links, encryption nonces, या share IDs बनाते हैं, तो जो attacker कुछ observe कर चुका है वह बाकी सब predict कर सकता है। यह सैद्धांतिक नहीं — audits में यह एक common bug class है।

आम गलतियाँ और उनसे बचाव

Math.random() से library PRNG seed करना:

// गलत
const seed = Math.floor(Math.random() * 2**32);

Downstream कुछ भी seed से ज़्यादा रैंडम नहीं हो सकता। इसकी जगह crypto.getRandomValues(new Uint32Array(1))[0] उपयोग करें।

Date.now() को entropy की तरह उपयोग करना: समय tight windows में guessable है। एक छोटे रैंडम factor के साथ भी, timestamps attackers को काफ़ी bits leak करते हैं।

अपना mixer XOR करके बनाना: OS CSPRNGs पहले से हर उपयोगी entropy source mix करते हैं। अपना stir जोड़ना entropy बढ़ाने की बजाय घटाता है।

Range के लिए modulo bias: randomBytes[0] % 10 uniformly 0-9 में distributed नहीं है क्योंकि 256, 10 का multiple नहीं है। Uniform random integers के लिए rejection sampling उपयोग करें:

function randomInt(max) {
  const range = new Uint32Array(1);
  const threshold = 2**32 - (2**32 % max);
  do {
    crypto.getRandomValues(range);
  } while (range[0] >= threshold);
  return range[0] % max;
}

Entropy Sources और Boot-Time चिंताएं

Linux पर /dev/urandom early boot के बाद हमेशा safe है। hardware RNG के बिना सिस्टम पर boot के पहले कुछ seconds में kernel pool under-seeded हो सकता है। यही 2008 Debian OpenSSL bug में exploit हुआ — एक patch ने entropy mixing हटाया और केवल process ID बचा। इस window में बनी keys में केवल 2^15 possible values थे, seconds में enumerate होते।

Modern सिस्टम kernel CSPRNG को seed करते हैं: x86-64 पर RDSEED, ARMv8.5-A RNG instructions, thermal noise, interrupt timing से। Intel Ice Lake या AMD Zen 3+ वाले सर्वर पर CSPRNG boot के microseconds के भीतर seeded हो जाता है।

Docker containers में host का /dev/urandom by default pass-through होता है। Serverless (AWS Lambda, Cloudflare Workers) के लिए runtime प्रति invocation entropy seeding संभालता है।

Session Tokens और Share IDs

फाइल ट्रांसफर सर्विस के लिए रैंडम identifiers चाहिए:

  • URLs में file IDs — attackers valid IDs guess न कर सकें
  • password-protected links के लिए share tokens
  • CSRF tokens
  • Encryption keys (per-file AES keys)
  • GCM के लिए nonces

न्यूनतम लंबाई: collision और unguessability के लिए 128 bits (16 bytes), keys के लिए 256 bits (32 bytes)। base64url encoding ~33% लंबाई बढ़ाती है; hex 100%।

32-byte base64url-encoded token 43 characters का होता है और 2^256 पर essentially collision-free है।

कमज़ोर RNG की पहचान

आपका RNG टूटा या कमज़ोर है अगर:

  • अलग-अलग requests से identical tokens बनें
  • Output visual tests pass करे लेकिन dieharder या PractRand statistical batteries fail करे
  • Process restart के बाद seed reuse — हर deploy एक ही initial state उपयोग करे
  • Generated keys patterns में पड़ें (जैसे पहले 4 bytes बदलें लेकिन last 28 एक जैसे हों)

Production में ये तब तक दिखेंगे नहीं जब तक कुछ catastrophically गलत न हो। failure mode आमतौर पर silent होता है। Audit करें: codebase में हर Math.random() call review होनी चाहिए। Source tree पर Math.random के लिए grep एक अच्छा weekly hygiene check है।

Random Strings और UUIDs

Human-facing identifiers के लिए, crypto.randomUUID() standard format में v4 UUID (122 bits of randomness) return करता है:

const id = crypto.randomUUID();
// "f47ac10b-58cc-4372-a567-0e02b2c3d479"

Chrome 92+, Firefox 95+, Safari 15.4+, Node 14.17+ में supported। Database primary keys, API request IDs, और non-security-critical unique identifiers के लिए उत्तम। Custom formats या higher entropy के लिए explicit getRandomValues उपयोग करें।

सर्वर पर Custom RNG Pools से बचें

कुछ server frameworks अपने रैंडम pools offer करते हैं जो system CSPRNG को application-level entropy के साथ "mix" करने का दावा करते हैं। इस पर संदेह करें। Custom mixing शायद ही kernel के output में सुधार करे और बग होने पर चुपचाप entropy घटा सकता है।

Node या किसी major runtime पर हैं तो builtin crypto.randomBytes सही और fast है। Third-party mixers से न बदलें।

सार: boring ही सही है

फाइल ट्रांसफर app में क्रिप्टोग्राफ़ी का हर हिस्सा unpredictable रैंडम bytes पर निर्भर है। AES keys, GCM nonces, PBKDF2 salts, share tokens, anti-CSRF tokens, session IDs — सभी को एक ही primitive चाहिए: browser में crypto.getRandomValues(), Node में crypto.randomBytes() या webcrypto.getRandomValues। इन्हें ही उपयोग करें। कभी Math.random() नहीं। कभी timestamps नहीं। कभी अपना mixer नहीं।

DPDP Act 2023 के अंतर्गत personal data की सुरक्षा के लिए cryptographically sound randomness एक baseline requirement है। HexaTransfer हर per-file AES key, nonce, और URL identifier को client पर crypto.getRandomValues() से derive करता है। Server-side share IDs crypto.randomBytes से आते हैं — एक consistent, audit-ready approach।

hexatransfer.com पर आज़माएं — मुफ्त, बिना अकाउंट, 10 GB तक।

एंड-टू-एंड एन्क्रिप्शन के साथ बड़ी फ़ाइलें सुरक्षित रूप से भेजें

एंड-टू-एंड एन्क्रिप्शन के साथ 10 GB तक की फ़ाइलें मुफ़्त में ट्रांसफ़र करें। अकाउंट की आवश्यकता नहीं। अपलोड से पहले आपकी फ़ाइलें ब्राउज़र में एन्क्रिप्ट की जाती हैं — कोई और उन्हें पढ़ नहीं सकता।

फ़ाइल भेजें