2 पॉइंट द्वारा GN⁺ 2024-05-08 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Go 1.22 ने math/rand और math/rand/v2 के default random sources को cryptographically strong generator में बदल दिया है, जिससे जहां crypto/rand इस्तेमाल होना चाहिए था वहां गलती से दूसरा विकल्प इस्तेमाल करने पर होने वाला नुकसान काफी कम हो जाता है
  • पुराना Go 1 generator 607 uint64 states का उपयोग करने वाला linear feedback shift register है, इसलिए केवल 607 outputs देखकर भी past और future values को recover किया जा सकता है
  • math/rand/v2 का PCG-DXSM statistical random quality और state size को बेहतर बनाता है, लेकिन secret values के लिए जरूरी unpredictability की guarantee नहीं देता
  • नया ChaCha8Rand 32-byte seed, हर 16 blocks पर rekeying, और प्रति core 300-byte state का उपयोग करता है, और इसे math/rand/v2, math/rand के कुछ हिस्सों और map hash seeds में लागू किया गया है
  • performance cost सीमित है: ChaCha8Rand Go 1 generator से धीमा है, लेकिन अधिकतम 2x के भीतर रहता है, और सामान्य servers में अंतर 3ns से ज्यादा नहीं होता, इसलिए अधिकांश programs में security gain ज्यादा बड़ा है

Go 1.22 ने random defaults कैसे बदले

  • Go 1.22 ने math/rand और math/rand/v2 में default रूप से cryptographically strong pseudorandom number generator इस्तेमाल करने के लिए defaults बदल दिए हैं
  • इसका उद्देश्य तब होने वाले नुकसान को कम करना है जब developers गलती से उन जगहों पर math/rand इस्तेमाल कर लें जहां crypto/rand की जरूरत होती है
  • Go की random API परंपरागत रूप से दो categories में बंटी रही है
    • math/rand: simulations, sampling, numerical analysis, non-cryptographic randomized algorithms, fuzzing, shuffling, exponential backoff आदि के लिए इस्तेमाल होने वाले statistical random numbers
    • crypto/rand: keys और tokens जैसी चीजों के लिए, जहां unpredictability जरूरी होती है, इस्तेमाल होने वाले cryptographic random numbers

statistical random numbers पर्याप्त क्यों नहीं हैं

  • अगर statistical random number generators basic statistical tests pass कर लें, तो वे कई non-cryptographic use cases के लिए पर्याप्त हो सकते हैं
  • लेकिन कई मामलों में algorithm जानने वाला observer पर्याप्त outputs देखकर आगे की sequence predict कर सकता है
  • Unix V3 के srand और rand शुरुआती रूप थे जिन्होंने बाद में C और कई languages की random APIs को प्रभावित किया
    • एक single integer seed से state set की जाती थी
    • linear congruential generator (LCG) तरीके से next value calculate की जाती थी
    • internal state सरल होने के कारण सिर्फ एक output से भी future values आसानी से calculate की जा सकती थीं
  • LCG में constants ऐसे चुने जा सकते हैं कि possible output values repeat होने से पहले एक-एक बार निकलें, लेकिन इसकी कमजोरी यह है कि low bits छोटे cycle में repeat होते हैं

Go 1 generator की structure और vulnerability

  • Go 1 का math/rand generator linear feedback shift register family का है
  • internal state 607 uint64 वाली vec slice है
    • vec[606] “tap” है
    • vec[334] “feed” है
    • next value बनाते समय tap और feed को जोड़कर x बनाया जाता है, x को feed position में store किया जाता है और फिर return किया जाता है
  • actual implementation पूरी slice को move नहीं करता, बल्कि cost कम करने के लिए सिर्फ tap और feed positions को पीछे move करता है
    • next value generate करने के लिए दो subtractions, दो conditional additions, दो loads, एक addition और एक store की जरूरत होती है
  • return value internal state vector का एक element होता है, इसलिए 607 outputs पढ़ने पर पूरी state expose हो जाती है
    • वही vec भरकर algorithm चलाने पर future values predict की जा सकती हैं
    • algorithm उल्टा चलाने पर past values भी recover की जा सकती हैं
  • Go 1 generator security purpose के लिए नहीं है, और generated numbers की quality भी initial vec setup पर निर्भर करती है

PCG ने क्या बेहतर किया और क्या limitations बचीं

  • math/rand/v2 ने एक ज्यादा modern statistical random number generator के रूप में Melissa O’Neill का PCG अपनाया
  • Go का PCG 128-bit LCG पर आधारित है, और scramble function से 128-bit state को 64-bit output में घटाता है
  • proposal discussion के दौरान Go ने O’Neill के proposal के आधार पर multiplication-based scramble इस्तेमाल किया
    • इस form को PCG-DXSM कहा जाता है
    • Numpy भी इसी PCG form का उपयोग करता है
  • PCG की state Go 1 generator की तुलना में बहुत छोटी है
    • Go 1 generator: 607 uint64
    • PCG: दो uint64
  • PCG initial state value के प्रति कम sensitive है और कई statistical tests pass करता है, लेकिन unpredictability की guarantee नहीं देता
    • PCG-XSL-RR reversible है
    • PCG-DXSM भी reversible हो तो यह आश्चर्यजनक नहीं माना जाएगा
  • secret values generate करने के लिए PCG नहीं, बल्कि किसी दूसरे generator की जरूरत होती है

cryptographic random numbers और operating system की भूमिका

  • cryptographic random numbers उन observers के लिए भी practically unpredictable होने चाहिए जो generation method जानते हों और बहुत सारे past output values देख चुके हों
  • cryptographic protocols, secret keys, modern commerce, online privacy आदि cryptographic random numbers पर निर्भर करते हैं
  • actual random supply operating system संभालता है
    • mouse, keyboard, disk, network timing जैसे physical devices से randomness collect की जाती है
    • हाल में CPU द्वारा सीधे measured electrical noise का भी इस्तेमाल होता है
  • जब operating system पर्याप्त randomness, जैसे कम से कम 256 bits, collect कर लेता है, तो वह hash या encryption algorithm से लंबी random sequence बनाता है
  • पहले /dev/random जैसी device files मुख्य रूप से इस्तेमाल होती थीं, लेकिन आज operating systems direct system calls provide करते हैं
  • Go का crypto/rand operating system-specific differences को hide करता है और समान interface rand.Read provide करता है

ChaCha8Rand design

  • Go 1.22 का नया generator ChaCha8Rand, Daniel J. Bernstein के ChaCha stream cipher का हल्का modified form है
  • ChaCha का ChaCha20 form, जो TLS और SSH में भी इस्तेमाल होता है, व्यापक रूप से इस्तेमाल किया जाता है
  • Jean-Philippe Aumasson की Too Much Crypto 8-round form ChaCha8 को भी सुरक्षित मानती है, और ChaCha8 लगभग 2.5 गुना तेज है
  • ChaCha8Rand, ChaCha8 को rand.Source के रूप में इस्तेमाल करने के लिए generated blocks को input के साथ XOR नहीं करता, बल्कि सीधे random stream के रूप में उपयोग करता है
    • यह सभी zero data को encrypt या decrypt करने जैसा है

ChaCha8Rand में बदलाव

  • ChaCha8Rand 32-byte seed को ChaCha8 key के रूप में इस्तेमाल करता है
  • ChaCha8 64-byte blocks generate करता है, और calculation blocks को 16 uint32 के रूप में treat करती है
  • general implementation SIMD instructions से 4 blocks एक साथ calculate कर सकती है, लेकिन XOR input में इस्तेमाल करने के लिए interleaved blocks को फिर से खोलना पड़ता है
    • ChaCha8Rand इसी interleaved block को random stream के रूप में define करता है, जिससे unshuffle cost खत्म हो जाती है
  • ChaCha8 के block finalization stage में हर uint32 में specific value जोड़ी जाती है
    • आधा key material है और आधा known constants हैं
    • ChaCha8Rand known constants को दोबारा नहीं जोड़ता, जिससे final additions का आधा हिस्सा हट जाता है
  • हर 16वें generated block पर आखिरी 32 bytes को अगले 16 blocks की key के रूप में इस्तेमाल किया जाता है
    • यह rekeying एक तरह की forward security provide करती है
    • generator की पूरी memory state expose हो जाए, तब भी केवल last rekeying के बाद की values recover की जा सकती हैं, past values तक पहुंच नहीं मिलती
  • Go ने ChaCha8Rand C2SP specification और test cases publish किए हैं, ताकि same seed के लिए दूसरे implementations भी Go implementation जैसी repeatability share कर सकें

standard library में कहां लागू हुआ

  • Go runtime operating system द्वारा supplied cryptographic random numbers से seeded per-core ChaCha8Rand state maintain करता है
    • हर core के लिए state size 300 bytes है
    • 16-core system में यह single shared Go 1 generator state 4,872 bytes के आसपास ही है
    • per-core state के कारण lock contention के बिना तेजी से random numbers बनाए जा सकते हैं
  • math/rand/v2 के package functions हमेशा ChaCha8Rand का उपयोग करते हैं
    • उदाहरण: rand.N, rand.Float64
  • math/rand के package functions, अगर rand.Seed call नहीं किया गया है, तो ChaCha8Rand का उपयोग करते हैं
    • उदाहरण: rand.Intn, rand.Float64
    • rand.Seed call होने पर compatibility के लिए Go 1 generator पर वापस जाना पड़ता है
  • runtime नए map के hash seed को पहले के wyrand-based generator की जगह ChaCha8Rand से चुनता है
    • अगर attacker map implementation का specific hash function जानता है, तो वह input तैयार करके map को quadratic-time behavior की ओर धकेल सकता है
    • global seed की जगह per-map seed इस्तेमाल करने से दूसरी degenerate behaviors भी टाली जा सकती हैं
    • map seed के लिए cryptographic random numbers अनिवार्य हैं या नहीं, यह स्पष्ट नहीं है, लेकिन यह बदलाव सरल और सावधानीपूर्ण choice था
  • अलग ChaCha8Rand instance की जरूरत वाले code सीधे rand.ChaCha8 बना सकते हैं

security mistakes का नुकसान कम करना

  • Go का लक्ष्य security problems पैदा करने वाली आम गलतियों को घटाकर या हटाकर safe by default code लिखने में मदद करना है
  • Go 1.20 में math/rand का Read deprecated होने पर कुछ developers को पता चला कि वे key material generation जैसी जगहों पर भी crypto/rand की जरूरत होने के बावजूद math/rand इस्तेमाल कर रहे थे
  • Go 1.20 में ऐसी गलती serious security issue थी
    • key कहां इस्तेमाल हुई
    • key कैसे expose हुई
    • क्या दूसरे random outputs ने attacker को key derive करने का clue दिया, इसकी जांच करनी पड़ती थी
  • Go 1.22 में वही गलती अब भी गलती है, लेकिन security disaster बनने की संभावना कम हो जाती है
  • फिर भी secret values के लिए crypto/rand इस्तेमाल करना बेहतर है
    • operating system kernel random values को बेहतर protect कर सकता है
    • kernel generator में नई entropy लगातार add करता है
    • kernel implementation की ज्यादा review हुई है

ऐसे cases जो cryptographic नहीं लगते

  • random UUID generation में UUID secret value नहीं होता, इसलिए math/rand पर्याप्त लग सकता है
  • लेकिन अगर math/rand को current time से seed किया जाए, तो अलग-अलग computers एक ही समय पर चलने पर same values बना सकते हैं
    • जिन systems में current time केवल millisecond precision देता है, वहां यह संभावना और बढ़ जाती है
  • Go 1.20 की OS entropy-based automatic seeding के बावजूद, Go 1 generator का seed सिर्फ 63-bit integer है
    • startup पर UUID बनाने वाले program का possible first UUID 2⁶³ तक सीमित होता है
    • लगभग 2³¹ UUIDs के बाद collision की संभावना बनती है
  • Go 1.22 का ChaCha8Rand 256-bit entropy से seeded है
    • possible first UUIDs 2²⁵⁶ हैं
    • collision की चिंता करने की जरूरत नहीं है
  • frontend server द्वारा requests को backend servers में randomly assign करने वाले load balancing में भी unpredictable random numbers की जरूरत हो सकती है
    • अगर attacker assignment observe करे और predictable algorithm जानता हो, तो वह expensive requests को किसी specific backend पर concentrate कर सकता है
    • Go 1 generator में यह rare लेकिन possible problem है
    • Go 1.22 में यह समस्या नहीं रहती

performance characteristics

  • ChaCha8Rand के security benefits की छोटी cost है, लेकिन performance Go 1 generator और PCG जैसी ही range में है
  • तुलना के लिए दो operations हैं
    • Uint64: random stream से next uint64 return करना
    • N(1000): [0, 1000) range का random number return करना
  • 64-bit x86 chip पर GOARCH=386 से build कर 32-bit mode में चलाने पर PCG की 128-bit multiplication के कारण PCG, ChaCha8Rand से धीमा होता है
    • ChaCha8Rand 32-bit SIMD arithmetic का उपयोग करता है
  • कुछ systems में Go 1: Uint64, PCG: Uint64 से तेज है, लेकिन Go 1: N(1000), PCG: N(1000) से धीमा है
    • Go 1 का N(1000) range reduction के लिए 64-bit integer division दो बार इस्तेमाल करता है
    • PCG और ChaCha8 का N(1000) ज्यादा तेज math/rand/v2 algorithm इस्तेमाल करता है, जो ज्यादातर division से बचता है
  • कुल मिलाकर ChaCha8Rand Go 1 generator से धीमा है, लेकिन 2x से ज्यादा धीमा नहीं होता
  • सामान्य servers में अंतर 3ns से अधिक नहीं होता, और बहुत कम programs में यह अंतर bottleneck बनेगा

निष्कर्ष

  • Go 1.22 बिना code changes के programs की security बढ़ाता है
  • core तरीका यह है कि crypto/rand के बजाय गलती से math/rand इस्तेमाल करने की common problem कम करने के लिए math/rand को ही मजबूत किया गया है
  • npm keypair package जैसे examples भी हैं, जहां Web Crypto API न होने पर JavaScript Math.random से RSA key pair generate करने की कोशिश की गई
  • system security इस assumption पर निर्भर नहीं रह सकती कि developers गलती नहीं करेंगे
  • Go 1.22 का ChaCha8Rand दिखाता है कि “mathematical” random numbers के लिए भी cryptographically strong pseudorandom number generator इस्तेमाल करने का approach दूसरे generators से competitive performance दे सकता है

1 टिप्पणियां

 
GN⁺ 2024-05-08
Hacker News की राय
  • लेख में बताए गए अनुसार, rclone में ठीक यही गलती हुई थी
    crypto/rand के Read का इस्तेमाल करने वाले कोड को refactor करते समय import अपने-आप बदल गया, और शायद math/rand इस्तेमाल करने वाले कोड के साथ मिल जाने पर goimports ने इसे math/rand में बदल दिया
    नतीजतन secure random number generator की जगह, rclone ने समय से seed किया गया deterministic generator इस्तेमाल करना शुरू कर दिया, और यह diff में पकड़ में नहीं आया :-(
    https://www.cvedetails.com/cve/CVE-2020-28924/
    इसलिए मैं इस बदलाव का पूरी तरह समर्थन करता हूँ

    • दुखद है, माफ़ कीजिए. 2016 में goimports को crypto/rand को प्राथमिकता देने के लिए बदला गया था, इसलिए refactor के दौरान वास्तव में क्या हुआ यह पक्का नहीं है
      शायद उसी फ़ाइल में math/rand-विशेष API इस्तेमाल करने वाला कोड आ गया होगा
      https://go-review.googlesource.com/24847
      वैसे भी, अच्छा है कि अब इस हिस्से को साफ़ किया जा रहा है
    • मुझे भी एक बार यह सोचकर vulnerability report मिली थी कि math/rand इस्तेमाल हुआ है. असल में ऐसा नहीं था, बस कई फ़ाइलों में भ्रम हो गया था, इसलिए कोई बड़ा नुकसान नहीं हुआ, लेकिन इससे पता चलता है कि पूरी चीज़ कितनी उलझाऊ है
      text/template और html/template भी ऐसे ही हैं. पीछे मुड़कर देखें तो इस तरह की package name shadowing बुरा विचार था
    • "secure password generation golang" खोजने पर मैंने देखा कि लगभग हर example math/rand का उपयोग करता है
      इससे भी बुरी बात यह कि सब password बनाने से ठीक पहले current time से seed initialize करते हैं
      हमारे कोड में किसी को math/rand इस्तेमाल करते देखकर, यह जानने के लिए कि उसने कहाँ से copy किया, मैंने खोजा और तब यह दिखा
    • goimports ने लगभग शुरुआत से ही math/rand.Read और crypto/rand.Read को special-case किया है
      लेकिन 2016 के https://github.com/golang/tools/commit/0835c735343e0d8e375f0... को देखें तो उस समय का ज़िक्र है जब "rand.Read" को "math/rand" के रूप में resolve किया जा सकता था
      शायद यह उसी दौर में हुआ होगा
    • "PredictableRand" जैसे नाम वाला API call देना इतना मुश्किल नहीं लगता
  • पिछले हफ़्ते भी spacey ने https://news.ycombinator.com/item?id=40237491 पर इसे पोस्ट किया था, लेकिन लगता है वह पोस्ट गलती से https://news.ycombinator.com/item?id=40224864 की duplicate मानकर दब गई
    go.dev ब्लॉग की ये दोनों पोस्ट एक ही series की दो कड़ियाँ हैं, लेकिन काफ़ी अलग हैं. यह पोस्ट efficient secure random number generation algorithm के बारे में है, जबकि पिछली पोस्ट Go API design के बारे में थी

  • Russell Cox लगातार बेहतरीन technical blog posts, proposals और काम प्रकाशित करते हैं
    अगर आप अपनी writing और thinking की clarity बढ़ाना चाहते हैं, तो Russell Cox से शुरू करना अच्छा रहेगा

    • उनकी finite-state automata और regular expressions series की वजह से मैं उस क्षेत्र में गहराई से रुचि लेने लगा
      उस समय मुझे यह भी नहीं पता था कि Russ Cox कौन हैं, लेकिन वह लेख-श्रृंखला सचमुच शानदार थी
      regular expression implementation पर मुफ्त में उपलब्ध सामग्री में शायद वह सबसे उच्च गुणवत्ता की है, और उसके बाद कई compiler-केंद्रित किताबें आती हैं, लेकिन वे न तो मुफ्त हैं और न ही वेब पर आसानी से खोजी जा सकती हैं
    • वे video demo भी अच्छे बनाते हैं https://research.swtch.com/acme
  • मैंने भी एक बार वहाँ math/rand इस्तेमाल कर दिया था जहाँ crypto/rand अनिवार्य था
    नतीजतन dnscrypt-proxy2 के शुरुआती versions में static keys इस्तेमाल हुईं
    कारण था import अपने-आप जोड़ने वाला VSCode extension. जिन सभी source files में secure random की ज़रूरत थी, उनमें मैंने सावधानी से crypto/rand import किया था, लेकिन एक फ़ाइल में यह छूट गया, सब कुछ compile भी हो गया और ठीक चला, और मैं यह नहीं देख पाया कि उस खास फ़ाइल में extension ने चुपचाप math/rand import जोड़ दिया था
    उसके बाद से, गलत rand के auto-import से बचने के लिए मैं crypto/rand को cryptorand alias के साथ import करता हूँ
    वैसे, Zig भी ChaCha8-आधारित random generator इस्तेमाल करता है, और cryptographic operations में user अपना generator नहीं दे सकता; हमेशा सुरक्षित generator ही उपयोग होता है. testing के लिए कुछ functions explicit seed लेते हैं
    constrained environments के लिए standard library में Ascon permutation और Reverie construction पर आधारित एक छोटा generator भी शामिल है

    • आपके मामले में ठीक क्या हुआ था, यह तो नहीं जानता, लेकिन संभव है कि यह आपके बताए से अलग रहा हो
      2016 में goimports को math/rand पर crypto/rand को प्राथमिकता देने के लिए बदला गया था(https://go-review.googlesource.com/24847), और उस समय Go के लिए VSCode support आया भी नहीं था
    • किसी और ने भी यही बात कही. सच कहूँ तो import को अपने-आप जोड़ने की यह प्रथा पूरी तरह अजीब लगती है, और यह नामों को अलग-अलग namespace में बाँटने के मूल उद्देश्य को ही कमज़ोर कर देती है
  • 2020 के दशक में भी मैं अक्सर सोचता रहा हूँ कि कई programming languages के default random implementations अब भी LFSR, MT जैसे तेज random generators क्यों इस्तेमाल करती हैं
    मुझे लगता है कि बेहतर यह होगा कि conservative approach अपनाई जाए—यह मानकर कि लोगों को यह नहीं पता होता कि उन्हें pseudo-random generator चाहिए या cryptographically secure pseudo-random generator—और default को बाद वाले पर बदला जाए, जबकि पहले वाले की ज़रूरत वाले लोग उसे explicitly चुनें

    • PHP 8.2 के नए object-oriented random API में ठीक ऐसा ही किया गया है
      अगर developer इस्तेमाल होने वाला random engine explicitly नहीं चुनता, तो उसे cryptographically secure generator मिलता है
      अब मुश्किल हिस्सा लोगों को नए API पर migrate करने के लिए मनाना है। इससे भी आगे, global Mt19937 instance का इस्तेमाल करने वाले mt_rand() से, PHP 7.0 से पहले से उपलब्ध CSPRNG-आधारित random_int() पर ले जाना भी आसान नहीं है
      [1] https://www.php.net/releases/8.2/en.php#random_extension
    • हाल ही में मैंने एक नई Go library इस्तेमाल करनी शुरू की जो complex data structures के कई components के लिए random IDs generate करती है
      मेरे use case में components की संख्या कई दसियों हज़ार थी, और profiling करने पर पता चला कि data structure initialization time का बड़ा हिस्सा crypto/rand की Read() में जा रहा था, और मेरे MacBook पर वह system calls कर रही थी
      library को patch करके math/rand की Read() इस्तेमाल करवाई, तो performance काफ़ी बेहतर हो गई
      math/rand के तेज होने के अलावा, मुझे यह चिंता भी थी कि कहीं बिना वजह system का entropy pool खत्म न हो जाए। इस मामले में IDs के random होने की एकमात्र वजह यह थी कि data structure को serialize/deserialize करने के बाद बाद में और components जोड़े जा सकें, और मेरा ऐसा करने का इरादा नहीं था
      इस ब्लॉग में बताए गए बदलाव का timing मेरे अनुभव से ठीक कैसे मेल खाता है, यह मुझे नहीं पता। शायद मैंने library का पुराना version इस्तेमाल किया था, और अगर अब crypto/rand व्यवहारिक रूप से math/rand से अलग पहचान में नहीं आता, तो ठीक ही है :-)
    • CSPRNG, यहाँ ChaCha8, के पक्ष में एक और मज़बूत तर्क यह है कि benchmarks में यह PCG की तुलना में 2x के भीतर है
      state size अब भी काफ़ी बड़ी है (64 bytes बनाम 16 bytes), लेकिन mt19937 या पुराने Go PRNG जैसी चीज़ों से कहीं बेहतर है
      अगर CSPRNG बहुत धीमा होता, जैसा कि reduced-round ChaCha variants के बजाय सामान्य CSPRNG में अक्सर होता है, तो default के रूप में उसका आकर्षण कम हो जाता
    • और किन मामलों में पहले वाले की ज़रूरत पड़ सकती है? मेरे दिमाग में बस fixed seed आता है, जहाँ reproducible results चाहिए होते हैं। जैसे tests या validation
      एक और छोटा कारण है कि लोग seed की ज़रूरत न होने पर भी PRNG की तरफ़ धकेले जाते हैं। CSPRNG API में हमेशा ऐसी errors होती हैं जिन्हें system call failure या entropy shortage के लिए handle करना पड़ता है
      crypto/rand reads वास्तव में कितनी बार fail होती हैं? आधुनिक systems में entropy खत्म करने के लिए कितना ज़्यादा पढ़ना पड़ता है? मैंने अरबों requests में कभी failure नहीं देखा, और dd भी ठीक काम करता है
      मुझे यह भी जिज्ञासा है कि ज़्यादातर use cases के लिए Must/panic style API ही शायद default होनी चाहिए
      वैसे, मैंने Python का secrets package (https://docs.python.org/3/library/secrets.html) देखा, और उसमें exceptions throw होने की कोई बात ही नहीं है। क्या व्यावहारिक रूप से ऐसा होता ही नहीं?
    • मुझे यह approach पसंद है कि “system के सभी random values CSPRNG से आने चाहिए, जब तक कि कोई explicit opt-out न करे”
      थोड़ी performance खोने के बदले यह कहीं ज़्यादा मज़बूत गारंटी मिलती है कि गलत random generator इस्तेमाल करके कोई disaster नहीं होगा
      अफ़सोस की बात है कि लगभग हर language में developers को अब भी इस sharp edge का ध्यान रखना पड़ता है
  • जो लोग नहीं जानते, उनके लिए: gosec और उसका extension golangci-lint, math/rand के इस्तेमाल पर warning देते हैं
    https://github.com/securego/gosec/blob/d3b2359ae29fe344f4df5...

    • math/rand/v2 की जो बात मुझे सबसे ज़्यादा पसंद है, उनमें से एक यह है कि इसे कंपनी में nolint directive और उसके बाद होने वाली PR discussion के बिना इस्तेमाल किया जा सकता है
  • मैं अभी भी security और नए v2 option के बारे में recommendation को समझने की कोशिश कर रहा हूँ
    ब्लॉग पोस्ट में “secret values के लिए कुछ और चाहिए” जैसी पंक्तियाँ हैं, और फिर वह cryptographic randomness, ChaCha8, और system randomness से seeding तक विस्तार से बात करती है, इसलिए कुल मिलाकर बहुत “safe” होने का impression बनता है
    लेकिन package docs में यह लिखा है
    ... but it should not be used for security-sensitive work ... This package's outputs might be easily predictable regardless of how it's seeded. For random numbers suitable for security-sensitive work, see the crypto/rand package.
    तो फिर ब्लॉग पोस्ट ऐसा संकेत क्यों देती है मानो math/rand/v2 को “secret values” के लिए इस्तेमाल किया जा सकता हो?
    क्या संक्षेप में मतलब यह है कि sensitive चीज़ों के लिए अब भी हर हाल में crypto/rand ही इस्तेमाल करना चाहिए, और यहाँ बताए गए improvements बस एक safety net हैं, अगर कोई math/rand/v2 का गलत इस्तेमाल कर बैठे?

    • हाँ। math/rand/v2 best choice नहीं है, लेकिन अब ऐसा नहीं रहा कि जहाँ crypto/rand इस्तेमाल होना चाहिए था, वहाँ गलती से इसे इस्तेमाल करने पर तुरंत घातक security flaw बन जाए
      लेख में भी यही कहा गया है
      crypto/rand इस्तेमाल करना अब भी बेहतर है। operating system kernel कई snooping attacks से random values को secret रखने का बेहतर काम कर सकता है, kernel generator में लगातार नई entropy जोड़ता रहता है, और उस पर अधिक समीक्षा हो चुकी है। लेकिन गलती से math/rand इस्तेमाल करना अब सुरक्षा आपदा नहीं रहा
  • सबसे खराब benchmark में भी नई strategy, unsafe random number generator की तुलना में लगभग आधी ही धीमी थी, और ज़्यादातर benchmark में अंतर इससे कहीं कम था
    Go, standard library और उसके ऊपर बनने वाले apps के लिए सुरक्षा और performance के संतुलन को अच्छी तरह बनाए रखता है। अच्छा होगा अगर दूसरे ecosystem भी इसका अनुसरण करें
    अगर किसी application को तेज़ लेकिन unsafe random numbers चाहिए, तो उसे अपना internal generator खुद implement करना होगा
    आसानी से उपलब्ध unsafe random numbers रखना एक ऐसा खुद के पैर पर कुल्हाड़ी मारने वाला tool है जिसे हटाया जा सकता है

    • सच कहें तो यह और भी खराब लगता है
      लोगों को यह मानने के लिए प्रोत्साहित करना कि "random" primitive cryptographically safe है, खराब practice को बढ़ावा देना है
      math/rand/v2 को cryptographically safe बनाना एक समस्या का समाधान कर सकता है, लेकिन अब वह चीज़ भी “ठीक” मानी जाने लगेगी जो देखने में security का वादा करती हुई नहीं लगती
      सामान्य तौर पर math/rand functions के बारे में यह परंपरा नहीं रही है कि वे cryptographically safe हों। इसे बदलकर खराब code को संयोग से सही तरह काम करने देना, यह छिपा सकता है कि अगर हम ऐसी स्पष्ट गलती कर रहे हैं, तो और कौन-सी गलतियाँ भी कर रहे होंगे
  • Go 1 का math/rand, ज़्यादा सटीक रूप से, additive lagged Fibonacci generator कहलाना चाहिए
    इसका पहला परिचय Green, Smith, Klem के paper में हुआ था
    [1] https://doi.org/10.1145/320998.321006

    • उस paper में “lagged” वाले हिस्से का ज़िक्र नहीं दिखता। या शायद मैंने ही मिस कर दिया हो
      https://www.leviathansecurity.com/blog/attacking-gos-lagged-... में भी इसे lagged Fibonacci generator कहा गया है
      कुछ महीने पहले Rob Pike और मैंने Go 1 generator के मूल C version के लेखक Don Mitchell से email पर बात की और पूछा कि वह इस algorithm को कैसे describe करेंगे, तो उनका जवाब था, “जहाँ तक मुझे याद है, Jim और मैंने Marsaglia जैसे LFSR generator को implement किया था”
      दोनों विवरण—lagged Fibonacci और LFSR-जैसा generator—अलग-अलग दृष्टिकोण से सही लगते हैं। दोनों में से कोई भी ठीक है, लेकिन लेख में मूल लेखक का विवरण इस्तेमाल करने का फैसला किया गया
  • अगर एक छोटी-सी कमी बतानी हो, तो यहाँ statistical randomness और pseudo-random number generator को शायद मिलाकर इस्तेमाल किया गया है
    Wikipedia पर statistical randomness की परिभाषा है: “जब किसी number sequence में पहचानने योग्य pattern या regularity न हो, तो उसे statistically random कहा जाता है”
    क्या यह परिभाषा true random number generator (TRNG) पर भी लागू होती है? उम्मीद तो यही होनी चाहिए। कम-से-कम लंबे समय में या चरम सीमा पर तो ऐसा होना ही चाहिए। नहीं तो वह TRNG नहीं है
    TRNG को लंबे समय में “ऐसी number sequence” बनानी चाहिए जिसमें “पहचानने योग्य pattern या regularity न हो”
    इसलिए statistical randomness का मतलब PRNG नहीं होता, लेकिन यह कहा जा सकता है कि यह TRNG पर भी लागू हो सकता है
    समस्या शायद इस वजह से आती है कि PRNG में सीमित रूप की statistical randomness की जाँच करने के लिए statistical randomness tests बहुत हैं
    इसलिए PRNG की पहचान करने के लिए “statistical randomness” की जगह “pseudo-random number generator” कहना ज़्यादा उचित होता। फिर भी यह बहुत छोटी-सी कमी है