এই পর্বে যা শিখবেন
- One-way আর trapdoor function কী, আর public key-এর ধারণা কোন সমস্যার সমাধান করে
- হাতে RSA key তৈরি (p = 61, q = 53), extended Euclid দিয়ে d, আর repeated squaring-এ encryption ও decryption
- RSA-এর সঠিকতার পূর্ণ প্রমাণ, এমনকি n-এর সঙ্গে সহমৌলিক নয় এমন বার্তার জন্যও
- Digital signature আর hash-then-sign, আর factoring-এর কঠিনতার সঙ্গে RSA-এর সম্পর্ক
- Textbook RSA-এর তিনটি গাণিতিক দুর্বলতা, padding-এর প্রয়োজন, আর CRT দিয়ে দ্রুত decryption
শুরুতেই একটি জরুরি কথা: এই পর্বের সব RSA উদাহরণ শুধু গণিত বোঝার জন্য। ছোট সংখ্যার “textbook RSA” নিরাপদ নয়, আর কোনো আসল তথ্য রক্ষায় এটি কখনো ব্যবহার করবেন না। বাস্তব ব্যবস্থায় যাচাই-করা লাইব্রেরি, যথাযথ padding, বড় key আর authenticated encryption লাগে; তার ব্যবহারিক দিক Cybersecurity কোর্সের পর্ব ১০ আর পর্ব ১৪-এ আছে। এখানে দেখানো প্রতিটি “আক্রমণ” শুধু আমাদের নিজেদের বানানো ছোট খেলনা key-এর ওপর, যাতে বোঝা যায় বাস্তবে সংখ্যা কেন বিশাল রাখতে হয়।
১ · গোপন বার্তা, খোলা রাস্তা — public key-এর ধারণা
কাল্পনিক অনলাইন দোকান বাজারঘর প্রতিদিন রাজশাহীর গুদামে একটি গোপন অর্ডার কোড পাঠায়। বার্তা যায় ইন্টারনেটের খোলা রাস্তা দিয়ে, যেখানে পথের যেকোনো যন্ত্র তা পড়তে পারে। পর্ব ২৭ “Classical cipher — shift, affine আর frequency analysis”-এর সব cipher-এ একটি সমস্যা আছে: প্রেরক আর প্রাপকের কাছে একই গোপন key থাকতে হয়। সেই key প্রথমবার পৌঁছাবে কীভাবে? খোলা রাস্তায় পাঠালে তো সেটিও চুরি হয়ে যায়। এটিকে বলে key বণ্টনের সমস্যা।
একটি দৈনন্দিন উপমা ভাবুন। গুদামের ম্যানেজার শতখানেক খোলা তালা বানিয়ে সবাইকে বিলিয়ে দিলেন, কিন্তু চাবি রাখলেন নিজের পকেটে। বাজারঘর একটি বাক্সে কাগজ রেখে একটি খোলা তালা “খট” করে লাগিয়ে দিল। তালা লাগাতে চাবি লাগে না, কিন্তু খুলতে লাগে। এখন বাক্সটি খোলা রাস্তায় পাঠানো যায়; পথে কেউ তালা দেখলেও খুলতে পারবেন না, এমনকি বাজারঘর নিজেও না। আগে থেকে কোনো গোপন কথা ভাগ না করেই গোপনীয়তা পাওয়া গেল। এটিই public-key cryptography-র মূল ধারণা: খোলা তালাটি public key, আর চাবিটি private key, দুটি মিলে একটি key pair.
শব্দভান্ডার আর ফাংশনের ভাষা
মূল বার্তাকে বলে plaintext, আর লুকানো রূপকে ciphertext. গণিতের ভাষায় encryption একটি ফাংশন E: M → C, আর decryption একটি ফাংশন D: C → M, যাতে প্রতিটি বার্তা m-এ D(E(m)) = m. অর্থাৎ E অবশ্যই one-to-one হতে হবে, নইলে দুটি ভিন্ন বার্তা একই ciphertext দিত আর প্রাপক বুঝতেন না কোনটি পাঠানো হয়েছিল (পর্ব ১৬-এর bijection আর inverse function). RSA-তে M = C = {0, 1, …, n − 1}, আর আমরা প্রমাণ করব E এই সেটের একটি permutation.
একটি ফাংশন f হলো one-way function, যদি f(x) হিসাব করা সহজ (polynomial সময়ে), কিন্তু এলোমেলোভাবে বাছা x-এর জন্য শুধু y = f(x) দেখে এমন কোনো x′ বের করা, যাতে f(x′) = y, বাস্তবে অসম্ভব রকম কঠিন। f হলো trapdoor function, যদি এটি one-way হয়, কিন্তু একটি গোপন তথ্য (trapdoor) জানা থাকলে উল্টো দিকও সহজ হয়ে যায়।
সতর্কতা: কোনো ফাংশন সত্যিই one-way কি না, তা আজও প্রমাণিত নয়; প্রমাণ হলে P ≠ NP প্রমাণ হয়ে যেত (DSA কোর্সের পর্ব ৬৪). আমরা যা ব্যবহার করি, তা হলো কয়েক দশকের চেষ্টার পরও যাদের উল্টো দিক দ্রুত করার উপায় পাওয়া যায়নি, এমন ফাংশন। RSA-র প্রার্থী হলো m ↦ me mod n: পর্ব ২২-এর repeated squaring-এ এটি সহজ, কিন্তু n-এর উৎপাদক না জেনে উল্টো দিকে (e-তম মূল mod n) যাওয়ার কোনো দ্রুত পদ্ধতি জানা নেই। trapdoor হলো n-এর উৎপাদক p আর q.
ইতিহাস: Whitfield Diffie আর Martin Hellman ১৯৭৬ সালে “New Directions in Cryptography” প্রবন্ধে public key-এর ধারণা আর একটি key বিনিময় পদ্ধতি প্রকাশ করেন (পর্ব ২৯ “Discrete logarithm আর Diffie–Hellman key exchange”-এর বিষয়), কিন্তু একটি ব্যবহারযোগ্য trapdoor function তাঁদের হাতে ছিল না। ১৯৭৭ সালে MIT-র Ron Rivest, Adi Shamir আর Leonard Adleman তা দেন; তাঁদের নামের আদ্যক্ষর থেকে RSA. ধারণাটি ১৯৭৭ সালে Martin Gardner-এর Scientific American কলামে জনপ্রিয় হয়, আর পূর্ণ প্রবন্ধ ১৯৭৮ সালে Communications of the ACM-এ প্রকাশিত হয় বলে সাধারণত উল্লেখ করা হয়। পরে জানা যায়, যুক্তরাজ্যের গোয়েন্দা সংস্থা GCHQ-তে Clifford Cocks ১৯৭৩ সালেই প্রায় একই পদ্ধতি বের করেছিলেন (James Ellis-এর আগের “non-secret encryption” ধারণার ভিত্তিতে), কিন্তু তা গোপন রাখা হয় আর ১৯৯৭ সালে প্রকাশ্যে আনা হয়। RSA-র মার্কিন patent ২০০০ সালে মেয়াদোত্তীর্ণ হয় বলে উল্লেখিত।
পুরো পর্বে একটিই ছোট উদাহরণ চলবে, নিচের ছবিতে যার সারসংক্ষেপ: গুদাম নিজের key বানায়, public অংশ প্রকাশ করে, বাজারঘর তা দিয়ে অর্ডার কোড m = 65 লুকায়, আর খোলা রাস্তায় শুধু ciphertext যায়।
খোলা রাস্তায় RSA: কে কী জানেন
নীল: প্রেরকের হিসাব; সবুজ: প্রাপকের গোপন তথ্য; লাল: আড়িপাতা ব্যক্তি শুধু প্রকাশ্য সংখ্যা দেখেন।
২ · Key তৈরি — p, q থেকে (n, e) আর d
- দুটি ভিন্ন মৌলিক সংখ্যা p আর q বাছুন (বাস্তবে এলোমেলো, প্রায় সমান মাপের, শত শত অঙ্কের)।
- n = pq হিসাব করুন। n-কে বলে modulus.
- φ(n) = (p − 1)(q − 1) হিসাব করুন (Euler-এর totient, পর্ব ২৪)।
- একটি পূর্ণসংখ্যা e বাছুন, যাতে 1 < e < φ(n) আর gcd(e, φ(n)) = 1. e-কে বলে public exponent.
- d = e−1 mod φ(n) বের করুন, অর্থাৎ 0 < d < φ(n) আর ed ≡ 1 (mod φ(n)). d হলো private exponent.
Public key: (n, e), সবাইকে দেওয়া হয়। Private key: d (আর p, q, φ(n)), যা গোপন থাকে।
প্রতিটি ধাপের কারণ আছে। ধাপ ৪-এর শর্ত gcd(e, φ(n)) = 1 না থাকলে ধাপ ৫-এর modular inverse থাকতই না: পর্ব ২১-এর Bézout অনুযায়ী ax ≡ 1 (mod m)-এর সমাধান আছে ঠিক তখন, যখন gcd(a, m) = 1, আর extended Euclid সেটি বের করে। আর ধাপ ৩-এর সূত্রটি দুটি ভিন্ন মৌলিকের জন্যই সত্য।
p ≠ q মৌলিক হলে φ(pq) = (p − 1)(q − 1).
প্রমাণ:
- 1 থেকে pq পর্যন্ত একটি সংখ্যা x, pq-এর সঙ্গে সহমৌলিক নয় ⇔ p ∣ x বা q ∣ x, কারণ pq-এর মৌলিক উৎপাদক শুধু p আর q. — মৌলিক উৎপাদকে বিশ্লেষণ
- p-এর গুণিতক আছে q-টি (p, 2p, …, qp), আর q-এর গুণিতক p-টি। দুটোরই গুণিতক মানে lcm(p, q) = pq-এর গুণিতক, এই সীমায় শুধু pq নিজে। — গণনা
- অন্তর্ভুক্তি-বর্জনে সহমৌলিক নয় এমন সংখ্যা q + p − 1টি, তাই φ(pq) = pq − p − q + 1 = (p − 1)(q − 1). ∎ — বীজগণিত
এবার হাতে একটি key বানানো যাক। বইয়ে বহুল প্রচলিত উদাহরণ p = 61, q = 53, e = 17; নিচের stepper প্রতিটি সংখ্যা দেখায়, আর d বের করে extended Euclid দিয়ে।
1p = 61, q = 532n = 61 · 53 = 32333φ = 60 · 52 = 312043120 = 17 · 183 + 9517 = 9 · 1 + 869 = 8 · 1 + 171 = 2 · 3120 − 367 · 178d = −367 + 3120 = 2753
| n | |
| φ(n) | |
| gcd-এর জোড়া | |
| d |
- মৌলিক বাছাই। p = 61 আর q = 53 দুটি ভিন্ন মৌলিক। গুণফল n = 3233 প্রকাশ্য হবে, কিন্তু p আর q গোপন।
- Totient. Lemma ২.২ অনুযায়ী φ(3233) = (61 − 1)(53 − 1) = 60 · 52 = 3120.
- Euclid শুরু। e = 17 নিলাম। gcd(3120, 17) বের করতে ভাগ: 3120 = 17 · 183 + 9.
- Euclid শেষ। 17 = 9 · 1 + 8, তারপর 9 = 8 · 1 + 1. শেষ শূন্য-নয় ভাগশেষ 1, তাই gcd(17, 3120) = 1 আর e বৈধ।
- পেছনে বসানো। 1 = 9 − 8 = 9 − (17 − 9) = 2 · 9 − 17 = 2(3120 − 183 · 17) − 17 = 2 · 3120 − 367 · 17. তাই 17 · (−367) ≡ 1 (mod 3120).
- d. −367 + 3120 = 2753. যাচাই: 17 · 2753 = 46801 = 15 · 3120 + 1 ✓. Public key (3233, 17), private key 2753.
বাস্তবে e প্রায় সবসময় 65537 = 216 + 1 নেওয়া হয়: এটি মৌলিক, আর এর binary রূপে মাত্র দুটি 1, তাই encryption আর signature যাচাই দ্রুত। p আর q খোঁজা হয় পর্ব ২৫-এর Miller–Rabin পরীক্ষা দিয়ে এলোমেলো বড় বিজোড় সংখ্যার মধ্যে; প্রায় সমান মাপের দুটি মৌলিকের গুণফল n একটি semiprime. key তৈরির পর φ(n) আর p, q-কে private key-এর অংশ হিসেবে গোপন রাখতে হয়, কারণ যেকোনো একটি ফাঁস হলে d বেরিয়ে আসে (§৬).
৩ · Encryption আর decryption — বিশাল ঘাত, দ্রুত হিসাব
বার্তা একটি পূর্ণসংখ্যা m, যেখানে 0 ≤ m < n. তাহলে
E(m) = me mod n, D(c) = cd mod n
লেখা বার্তাকে আগে byte-এ, তারপর একটি পূর্ণসংখ্যায় রূপান্তর করা হয় (যেমন Python-এ int.from_bytes). padding ছাড়া এই সরাসরি রূপকে বলে textbook RSA.
me-কে সরাসরি হিসাব করা অসম্ভব: 2048-bit n আর 2048-bit d-তে cd-এর অঙ্কসংখ্যা মহাবিশ্বের পরমাণুর সংখ্যাকেও ছাড়িয়ে যায়। সমাধান পর্ব ২২-এর binary exponentiation, বা repeated squaring: ঘাতকে binary-তে লিখে বারবার বর্গ করুন আর প্রতি ধাপে mod n নিন, যাতে কোনো মধ্যবর্তী সংখ্যা n2-এর চেয়ে বড় না হয়। k-bit ঘাতে লাগে k − 1টি বর্গ আর বড়জোর k − 1টি গুণ, অর্থাৎ O(log d) গুণ। এই modular exponentiation-ই RSA-র প্রতিটি কাজের ইঞ্জিন। নিচে আমাদের key দিয়ে m = 65 লুকানো আর ফেরত আনা।
1e = 17 = 10001₂265² = 4225 ≡ 992365⁴ ≡ 992² ≡ 1232465⁸ ≡ 1232² ≡ 1547565¹⁶ ≡ 1547² ≡ 7896c ≡ 789 · 65 ≡ 27907d = 2753 = 2¹¹+2⁹+2⁷+2⁶+182790→1295→3177→2195→65
| এখনকার ঘাত | |
| মান mod 3233 | |
| গুণের সংখ্যা |
- ঘাত binary-তে। 17 = 16 + 1 = 10001₂, তাই 6517 = 6516 · 65. শুধু বারবার বর্গ আর একটি গুণ লাগবে।
- প্রথম দুটি বর্গ। 65² = 4225 = 3233 + 992, তাই ≡ 992. তারপর 992² = 984064 = 304 · 3233 + 1232, তাই 65⁴ ≡ 1232.
- আরও দুটি বর্গ। 1232² = 1517824 ≡ 1547 (ভাগফল 469), আর 1547² = 2393209 ≡ 789 (ভাগফল 740). এখন 65¹⁶ ≡ 789.
- Ciphertext. 789 · 65 = 51285 = 15 · 3233 + 2790. তাই c = 2790. মাত্র ৫টি গুণ, কোনো মধ্যবর্তী সংখ্যা 3233²-এর বেশি নয়।
- Decryption-এর প্রস্তুতি। d = 2753 = 101011000001₂ (১২ bit). 2790-কে ১১ বার বর্গ করে k = 0, 6, 7, 9, 11-এর মান রাখা হয়: 2790, 632, 1765, 134, 545.
- গুণ করে ফেরত। 2790 · 632 ≡ 1295, · 1765 ≡ 3177, · 134 ≡ 2195, · 545 ≡ 65. প্রাপক ঠিক আসল অর্ডার কোড 65 পেলেন।
এবার Python-এ পুরো খেলনা RSA. নিচের ব্লক ৩ অঙ্কের দুটি মৌলিক এলোমেলোভাবে (স্থির seed-এ) বেছে key বানায়, একটি অর্ডার কোড encrypt আর decrypt করে, একটি অর্ডারে সই দেয় ও যাচাই করে (§৫-এ বিস্তারিত), আর শেষে stepper-এর key-এ 0 থেকে 3232 পর্যন্ত প্রতিটি বার্তা পরীক্ষা করে। Python-এর pow(a, b, m) নিজেই repeated squaring চালায়, আর pow(e, -1, phi) extended Euclid দিয়ে inverse দেয় (Python 3.8 থেকে)। প্রথমবার চালালে ব্রাউজারে Python (Pyodide) নামতে কয়েক সেকেন্ড লাগে।
import random, hashlib
from math import gcd
random.seed(28) # toy demo: never generate real keys like this
primes = [x for x in range(100, 1000) if all(x % k for k in range(2, int(x**0.5) + 1))]
p, q = random.sample(primes, 2) # two different 3-digit primes
n, phi = p * q, (p - 1) * (q - 1)
e = next(k for k in (17, 5, 7, 11, 13, 19, 23) if gcd(k, phi) == 1)
d = pow(e, -1, phi) # e*d = 1 (mod phi), extended Euclid inside
print(f"p={p} q={q} n={n} phi={phi} e={e} d={d} (e*d mod phi = {e * d % phi})")
m = 4207 # Bazarghar's secret order code, 0 <= m < n
c = pow(m, e, n) # encrypt with the PUBLIC key (n, e)
print("plaintext", m, "-> ciphertext", c, "-> decrypted", pow(c, d, n))
def digest(text): # toy: SHA-256 squeezed into 0..n-1
return int.from_bytes(hashlib.sha256(text.encode()).digest(), "big") % n
order = "ORDER-42: 3 kg chal to Rajshahi"
s = pow(digest(order), d, n) # sign with the PRIVATE exponent d
print("signature", s, "valid:", pow(s, e, n) == digest(order))
fake = "ORDER-42: 30 kg chal to Rajshahi"
print("same signature on changed order valid:", pow(s, e, n) == digest(fake))
N, D = 61 * 53, 2753 # the stepper key: check EVERY message
bad = [x for x in range(N) if pow(pow(x, 17, N), D, N) != x]
shared = sum(gcd(x, N) > 1 for x in range(N))
print(f"n=3233: {N} messages checked, failures {len(bad)}, "
f"messages sharing a factor with n: {shared}")আসল আউটপুট (ব্রাউজারের Python):
p=251 q=277 n=69527 phi=69000 e=17 d=24353 (e*d mod phi = 1)
plaintext 4207 -> ciphertext 15669 -> decrypted 4207
signature 63895 valid: True
same signature on changed order valid: False
n=3233: 3233 messages checked, failures 0, messages sharing a factor with n: 113
Seed 28 থেকে p = 251, q = 277 এসেছে; e = 17 এখানেও বৈধ, আর d = 24353. অর্ডার কোড 4207 লুকিয়ে 15669 হয়েছে, আর d দিয়ে হুবহু ফিরে এসেছে। সই করা অর্ডারটি যাচাইয়ে পাস করেছে, কিন্তু “3 kg” বদলে “30 kg” করলে একই সই আর মেলে না। শেষ লাইনটি সবচেয়ে গুরুত্বপূর্ণ: n = 3233-এর সব 3233টি বার্তায় একটিও ব্যর্থতা নেই, যদিও তাদের 113টি (0, আর 61 বা 53-এর গুণিতক) n-এর সঙ্গে সহমৌলিক নয়। 113 = 53 + 61 − 1, ঠিক Lemma ২.২-এর গণনা। পরের অংশ এই পরীক্ষাকে প্রমাণে পরিণত করবে।
৪ · কেন কাজ করে — সঠিকতার প্রমাণ
দাবি করতে হবে D(E(m)) = (me)d mod n = med mod n = m. মূল তথ্য ed ≡ 1 (mod φ(n)), অর্থাৎ কোনো পূর্ণসংখ্যা k ≥ 0-এর জন্য ed = 1 + k·φ(n). (k ≥ 0, কারণ e, d ≥ 1 বলে ed ≥ 1.) প্রথমে সহজ ক্ষেত্র, যেখানে পর্ব ২৪-এর Euler-এর উপপাদ্য সরাসরি খাটে।
n = pq, ed ≡ 1 (mod φ(n)), আর gcd(m, n) = 1 হলে med ≡ m (mod n).
প্রমাণ:
- ed = 1 + kφ(n), k ≥ 0. তাই med = m · (mφ(n))k. — ঘাতের নিয়ম
- gcd(m, n) = 1, তাই Euler-এর উপপাদ্যে mφ(n) ≡ 1 (mod n). — Euler, পর্ব ২৪
- অতএব med ≡ m · 1k = m (mod n). ∎ — congruence-এর গুণ
কিন্তু m যদি p বা q-এর গুণিতক হয়? তখন gcd(m, n) > 1, আর Euler-এর শর্ত ভেঙে যায়। এমন বার্তা বিরল (n = 3233-এ 113টি, বড় n-এ প্রায় শূন্য অনুপাত), তবু একটি এনক্রিপশন পদ্ধতিকে প্রতিটি বার্তায় কাজ করতে হয়; “প্রায় সবসময় ঠিক” পদ্ধতি গণিতে ভুল পদ্ধতি। পূর্ণ প্রমাণে n-এর বদলে আলাদাভাবে p আর q দেখা হয়, তারপর জোড়া লাগানো হয়, ঠিক পর্ব ২৩-এর Chinese Remainder Theorem-এর ভাবনায়।
p ≠ q মৌলিক, n = pq, আর e, d ধনাত্মক পূর্ণসংখ্যা যাতে ed ≡ 1 (mod (p − 1)(q − 1)). তাহলে প্রতিটি পূর্ণসংখ্যা m-এর জন্য med ≡ m (mod n). ফলে 0 ≤ m < n হলে D(E(m)) = m.
প্রমাণ: ed = 1 + k(p − 1)(q − 1), k ≥ 0.
- দাবি: med ≡ m (mod p). ক্ষেত্র (ক) p ∤ m: Fermat-এর ছোট উপপাদ্যে mp−1 ≡ 1 (mod p), তাই med = m · (mp−1)k(q−1) ≡ m · 1 = m (mod p). — Fermat, পর্ব ২৪
- ক্ষেত্র (খ) p ∣ m: তখন m ≡ 0, আর ed ≥ 1 বলে med ≡ 0 (mod p). দুই পাশই 0, তাই med ≡ m (mod p). — সরাসরি
- একই যুক্তিতে (p আর q-এর ভূমিকা বদলে) med ≡ m (mod q). — প্রতিসাম্য
- অর্থাৎ X = med − m-কে p ভাগ করে আর q ভাগ করে। p আর q ভিন্ন মৌলিক, তাই সহমৌলিক, আর তখন pq ∣ X (পর্ব ২১-এর Euclid-এর lemma থেকে; এটিই CRT-এর অনন্যতার অংশ)। — সহমৌলিক ভাজকের গুণফল
- তাই med ≡ m (mod n). 0 ≤ m < n হলে m নিজেই তার ভাগশেষ, অর্থাৎ D(E(m)) = m. ∎ — least residue-এর অনন্যতা
এখান থেকে একটি সুন্দর ফল আসে: E হলো {0, 1, …, n − 1}-এর একটি permutation, আর D তার inverse function. কারণ D ∘ E = identity, তাই E one-to-one (পর্ব ১৬), আর একটি সসীম সেট থেকে নিজের মধ্যে one-to-one ফাংশন onto-ও (pigeonhole). একই প্রমাণে de = ed, তাই E ∘ D = identity-ও সত্য, যা §৫-এর signature-কে সম্ভব করে।
প্রমাণের শর্তগুলো খেয়াল করুন: ধাপ ৪-এ লেগেছে p ≠ q. p = q হলে n = p2, φ(n) = p(p − 1) (আর (p − 1)2 নয়), আর p-এর গুণিতক বার্তায় দাবিটি সত্যিই ভাঙে (§৯-এর ভুল প্রমাণ আর অনুশীলন ৪ দেখুন)। Python-এর পরীক্ষা (ব্লক ১-এর শেষ লাইন) একটি নির্দিষ্ট n-এ সব বার্তা মিলিয়েছিল; প্রমাণটি সব n = pq-তে একসঙ্গে বলে।
৫ · Digital signature — d দিয়ে সই, e দিয়ে যাচাই
গোপনীয়তা ছাড়াও খোলা রাস্তায় আরেকটি প্রশ্ন আছে: গুদাম কীভাবে নিশ্চিত হবে যে অর্ডারটি সত্যিই বাজারঘর পাঠিয়েছে, আর পথে কেউ “3 kg” বদলে “30 kg” করেনি? কাগজে এর উত্তর হাতের সই। গণিতে উত্তর digital signature: এমন একটি মান, যা শুধু private key-এর মালিক বানাতে পারেন, কিন্তু public key দিয়ে যে কেউ যাচাই করতে পারেন। এবার বাজারঘরের নিজের key pair (n, e, d) লাগবে, আর সে নিজের d দিয়ে সই করবে।
একটি hash function H বার্তা M-কে একটি ছোট সংখ্যা h = H(M), 0 ≤ h < n-এ নেয়। সই: s = hd mod n. যাচাই: যে কেউ se mod n হিসাব করে দেখেন সেটি H(M)-এর সমান কি না; সমান হলে সই গ্রহণ, নইলে বাতিল।
সঠিকতা উপপাদ্য ৪.২ থেকেই আসে: se = hde = hed ≡ h (mod n). কিন্তু সরাসরি M-এ সই না করে আগে hash কেন? তিনটি কারণ। প্রথমত, বার্তা যত লম্বাই হোক, hash ছোট আর n-এর চেয়ে ছোট রাখা যায়। দ্বিতীয়ত, §৭-এ দেখবেন textbook RSA গুণ মানে: দুটি সই s1, s2 থেকে s1s2 mod n হয় h1h2-এর বৈধ সই (প্রমাণ অনুশীলন ১-এ)। h যদি বার্তা নিজেই হতো, তবে দুটি সই দেখে কেউ তৃতীয় একটি বার্তার সই বানিয়ে ফেলতেন। তৃতীয়ত, যে কেউ যেকোনো s নিয়ে h = se mod n বানিয়ে “সই-সহ বার্তা” দাবি করতে পারেন; hash থাকলে সেই h-এর পেছনে অর্থপূর্ণ বার্তা খোঁজা কঠিন। এই রীতিকে বলে hash-then-sign. Hash function-এর বাস্তব নিরাপত্তা-শর্ত Cybersecurity কোর্সের পর্ব ০৯-এ আছে।
নিচের stepper আমাদের ছোট key-এ (n = 3233, e = 17, d = 2753) একটি অর্ডারে সই দেয়। খেলনা হিসেবে SHA-256-এর ২৫৬-bit hash-কে mod 3233 নিয়ে ১২ bit-এ নামানো হয়েছে; বাস্তবে এটি কখনো করা হয় না। সই দেওয়া হয়েছে CRT দিয়ে (দুটি ছোট ঘাত, §৮-এ পূর্ণ ব্যাখ্যা), আর যাচাই repeated squaring-এ।
1M = "ORDER-42: 3 kg chal"2h = H(M) mod 3233 = 13003s_p = 19⁵³ mod 61 = 464s_q = 28⁴⁹ mod 53 = 165s = 16 + 53 · 42 = 224262242→2482→1459→1367→15715 · 2242 ≡ 1300 = h ✓8"30 kg": h′ = 72 ≠ 1300 ✗
| h | |
| s | |
| s^e mod n |
- Hash. বার্তার SHA-256 শুরু হয় bcb1f703… দিয়ে; পুরো ২৫৬-bit সংখ্যাটি mod 3233 নিলে h = 1300 (খেলনা সংক্ষেপ).
- দুটি অর্ধেক। 1300 mod 61 = 19 আর 1300 mod 53 = 28. d mod 60 = 53, d mod 52 = 49. তাই sp = 1953 mod 61 = 46, sq = 2849 mod 53 = 16.
- জোড়া লাগানো। 53−1 mod 61 = 38. t = 38 · (46 − 16) mod 61 = 1140 mod 61 = 42, আর s = 16 + 53 · 42 = 2242. বাজারঘর পাঠায় (M, 2242).
- যাচাই: বর্গ। গুদাম শুধু public (3233, 17) জানে। 2242² ≡ 2482, 2482² ≡ 1459, 1459² ≡ 1367, 1367² ≡ 15, তাই s16 ≡ 15.
- যাচাই: শেষ গুণ। s17 ≡ 15 · 2242 = 33630 = 10 · 3233 + 1300. ফল 1300 = h, তাই সই গ্রহণ।
- বদলানো বার্তা। কেউ পথে “30 kg” করলে নতুন hash mod 3233 = 72. কিন্তু s17 এখনো 1300 ≠ 72, তাই সই বাতিল। নতুন বার্তার সই বানাতে d লাগত।
একটি প্রচলিত ভুল ধারণা: “সই করা মানে private key দিয়ে encrypt করা” কথাটি শুধু textbook RSA-র সমীকরণে খাটে, আর এটি ভাবনায় বিভ্রান্তি আনে। বাস্তবে signature আর encryption আলাদা padding (PSS বনাম OAEP) ব্যবহার করে, আর একই key pair দুই কাজে ব্যবহার না করাই নিয়ম। Certificate আর বিশ্বাসের শিকলে signature কীভাবে কাজে লাগে, তা Cybersecurity কোর্সের পর্ব ১১-এ।
৬ · নিরাপত্তা কিসের ওপর দাঁড়িয়ে — factoring আর তার চেয়েও বেশি
আড়িপাতা ব্যক্তি জানেন n, e আর c. d পেলেই সব শেষ। d বের করার সবচেয়ে সোজা পথ: n-কে factor করে p, q বের করা, তারপর φ(n) আর একটি inverse. উল্টো দিকেও কিছু সত্য: φ(n) জানা আর factor জানা আসলে সমান।
n = pq (p ≠ q মৌলিক) আর φ(n) জানা থাকলে p আর q দ্রুত বের করা যায়।
প্রমাণ:
- φ(n) = (p − 1)(q − 1) = pq − (p + q) + 1 = n − (p + q) + 1, তাই S = p + q = n − φ(n) + 1 জানা। — Lemma ২.২ খুলে লেখা
- p আর q হলো x2 − Sx + n = 0-এর দুটি মূল, কারণ (x − p)(x − q) = x2 − (p + q)x + pq. — Vieta-র সম্পর্ক
- দ্বিঘাত সূত্রে p, q = (S ± √(S2 − 4n)) / 2; এখানে শুধু একটি পূর্ণসংখ্যার বর্গমূল লাগে, যা বড় সংখ্যাতেও দ্রুত। ∎ — দ্বিঘাত সমীকরণ
উদাহরণ: n = 3233, φ = 3120 হলে S = 114, S2 − 4n = 12996 − 12932 = 64, √64 = 8, তাই p, q = (114 ± 8)/2 = 61, 53. আরও জানা আছে যে d (e-সহ) জানলেও একটি randomized পদ্ধতিতে n দ্রুত factor করা যায়; প্রমাণটি এখানে বাদ। তাই “d গোপন রাখা” আর “p, q গোপন রাখা” একই দাবি। কিন্তু একটি প্রশ্ন আজও খোলা: d ছাড়াই শুধু c-এর e-তম মূল mod n বের করার (একে RSA problem বলে) কোনো সহজ পথ আছে কি না, যা factoring-এর চেয়ে সহজ। এমন পথ জানা নেই, আবার দুটি সমান কঠিন বলে প্রমাণও নেই।
নিচের ব্লকে আমাদের নিজেদের খেলনা key (ব্লক ১-এর n = 69527) একজন আড়িপাতা ব্যক্তির চোখে ভাঙা হয়েছে: trial division-এ factor, তারপর d, তারপর আটকানো ciphertext-এর বার্তা। তারপর φ(n) থেকে উপপাদ্য ৬.১, আর শেষে n বড় হলে trial division-এর খরচ কীভাবে বাড়ে।
import time
from math import isqrt
def smallest_factor(n): # trial division: about sqrt(n) steps
for k in range(3, isqrt(n) + 1, 2):
if n % k == 0: return k
return n
# 1) the eavesdropper's view of a toy key: only n, e and one ciphertext
n, e, c = 69527, 17, 15669
p = smallest_factor(n); q = n // p
d = pow(e, -1, (p - 1) * (q - 1)) # with p and q, d is one inverse away
print(f"n = {p} * {q}, recovered d = {d}, order code = {pow(c, d, n)}")
# 2) phi(n) alone also gives p and q: p + q = n - phi + 1
phi = (p - 1) * (q - 1)
s = n - phi + 1; r = isqrt(s * s - 4 * n)
print("from n and phi:", (s - r) // 2, (s + r) // 2)
# 3) cost of trial division as n grows (both primes about half the bits)
def prime_near(x):
while smallest_factor(x) != x: x += 2
return x
for bits in (24, 32, 40, 48):
h = bits // 2
a, b = prime_near(2**(h - 1) + 2**(h - 3) + 1), prime_near(2**h - 2**(h - 3) + 1)
t = time.perf_counter(); f = smallest_factor(a * b)
ms = (time.perf_counter() - t) * 1000
print(f"{(a * b).bit_length()}-bit n: found {f}, about {f // 2:,} divisions, {ms:.1f} ms")আসল আউটপুট (ব্রাউজারের Python; সময়ের সংখ্যা আপনার যন্ত্রে আলাদা হবে):
n = 251 * 277, recovered d = 24353, order code = 4207
from n and phi: 251 277
24-bit n: found 2579, about 1,289 divisions, 0.1 ms
32-bit n: found 40961, about 20,480 divisions, 1.0 ms
40-bit n: found 655373, about 327,686 divisions, 18.5 ms
48-bit n: found 10485767, about 5,242,883 divisions, 289.3 ms
৫ অঙ্কের n ভাঙতে এক মুহূর্তও লাগেনি, আর গোপন অর্ডার কোড 4207 বেরিয়ে এসেছে: ছোট n-এ RSA কোনো সুরক্ষাই দেয় না। φ(n) থেকেও ঠিক একই p, q এসেছে। শেষ চার লাইনে n প্রতি ৮ bit বাড়লে ভাগের সংখ্যা প্রায় ১৬ গুণ (24) বাড়ছে, কারণ trial division-এর খরচ প্রায় √n = 2bits/2. এই হারে 2048-bit n-এ লাগত প্রায় 21023টি ভাগ, যা কোনো কম্পিউটারের নাগালে নয়। তবে মনে রাখুন, trial division সবচেয়ে দুর্বল পদ্ধতি; পর্ব ২৫-এর Pollard rho আর number field sieve অনেক দ্রুত, আর key-এর মাপ ঠিক হয় সেই সেরা পদ্ধতির খরচ দেখে।
Key-এর মাপ: তারিখসহ নির্দেশনা
পর্ব ২৫-এ দেখেছেন, প্রকাশ্যে factor করা সবচেয়ে বড় RSA challenge সংখ্যা RSA-250 (৮২৯ bit), ২০২০ সালে। key-এর মাপের পরামর্শ তাই সংখ্যা ভাঙার সেরা জানা খরচ থেকে আসে, আর সময়ের সঙ্গে বদলায়। মার্কিন NIST-এর SP 800-57 Part 1 (Rev. 5, ২০২০) নির্দেশিকায় প্রচলিত তুলনা নিচের মতো; নিরাপত্তা “bit”-এ মাপা মানে মোটামুটি এতগুলো bit-এর key সব চেষ্টা করার সমান কাজ।
| RSA n-এর মাপ | আনুমানিক নিরাপত্তা | মন্তব্য (NIST SP 800-57, ২০২০) |
|---|---|---|
| 1024 bit | ≈ 80 bit | নতুন কাজে আর অনুমোদিত নয় |
| 2048 bit | ≈ 112 bit | ২০৩০ পর্যন্ত গ্রহণযোগ্য ধরা হয় |
| 3072 bit | ≈ 128 bit | দীর্ঘমেয়াদি সুরক্ষার জন্য প্রস্তাবিত |
| 7680 / 15360 bit | ≈ 192 / 256 bit | খুব ধীর; বাস্তবে কম ব্যবহৃত |
এর বাইরে একটি বড় অনিশ্চয়তা আছে: পর্ব ২৫-এর Shor-এর algorithm একটি বড়, ত্রুটি-সংশোধিত quantum কম্পিউটারে RSA-কে ভেঙে দেবে। এ কারণে NIST ২০২৪ সালের শেষে একটি খসড়া পরিকল্পনায় (NIST IR 8547) RSA আর elliptic curve থেকে post-quantum পদ্ধতিতে সরার সময়রেখা প্রস্তাব করেছে, যেখানে ২০৩৫ সালের মধ্যে এদের বাদ দেওয়ার কথা বলা হয়েছে; চূড়ান্ত রূপ বদলাতে পারে। পর্ব ৩০ “Finite field আর elliptic curve-এর পরিচয়”-এ এ নিয়ে আরও কথা আছে।
৭ · Textbook RSA-এর তিন ফাঁদ — আর কেন padding
বড় n নিলেই কি textbook RSA নিরাপদ? না। n যত বড়ই হোক, সূত্রটির নিজের কাঠামো থেকে তিনটি দুর্বলতা আসে, আর প্রতিটি একটি সরল গাণিতিক সত্য।
ফাঁদ ১: একই বার্তা, একই ciphertext
E(m) = me mod n-এ কোনো এলোমেলো অংশ নেই, তাই এটি deterministic: একই m সবসময় একই c দেয়। আর public key সবার কাছে আছে, তাই যে কেউ নিজে E(m) হিসাব করতে পারেন। বার্তার সম্ভাব্য মান কম হলে (হ্যাঁ/না, ডেলিভারির ঘণ্টা 0–23, একটি ৪ অঙ্কের PIN) আক্রমণকারী সব সম্ভাব্য m encrypt করে আটকানো c-এর সঙ্গে মিলিয়ে নেন, d ছাড়াই। আধুনিক সংজ্ঞায় একটি নিরাপদ encryption-কে semantic security দিতে হয়: ciphertext দেখে বার্তা সম্পর্কে কোনো আংশিক তথ্যও যেন না মেলে। Deterministic কোনো public-key পদ্ধতি তা পারে না, তাই encryption-এ এলোমেলোতা লাগে।
ফাঁদ ২: গুণের সঙ্গে মানিয়ে চলা
একই public key (n, e)-তে যেকোনো m1, m2-এর জন্য E(m1) · E(m2) ≡ E(m1m2) (mod n).
প্রমাণ: m1e · m2e = (m1m2)e, আর mod n-এ গুণ congruence মানে (পর্ব ২২)। ∎
এর অর্থ: বার্তা না জেনেই কেউ ciphertext-কে এমনভাবে বদলাতে পারেন যাতে বার্তা নিয়ন্ত্রিতভাবে বদলায়। ধরুন একটি নিলামে দর 125 টাকা encrypt হয়ে যাচ্ছে; পথে কেউ c-কে E(2) = 2e mod n দিয়ে গুণ করলেন, আর প্রাপক decrypt করে পেলেন 250. এই ধর্মকে বলে malleability. Encryption শুধু গোপনীয়তা দেয়, অখণ্ডতা নয়; তাই বাস্তব ব্যবস্থায় authenticated encryption লাগে।
ফাঁদ ৩: ছোট e আর ছোট বার্তা
দ্রুততার জন্য কেউ e = 3 নিলেন। বার্তা m যদি এত ছোট হয় যে m3 < n, তবে mod n-এ কোনো “ঘোরা” ঘটে না: c = m3 একটি সাধারণ পূর্ণসংখ্যা। তখন c-এর সাধারণ ঘনমূলই m, আর ঘনমূল বের করতে কোনো key লাগে না, শুধু binary search. একই বার্তা e = 3 দিয়ে তিনজন আলাদা প্রাপককে (আলাদা n) পাঠালে, তিনটি ciphertext পর্ব ২৩-এর CRT দিয়ে জুড়ে m3 mod n1n2n3 পাওয়া যায়, আর m < প্রতিটি ni বলে m3 < n1n2n3, তাই আবার সাধারণ ঘনমূল যথেষ্ট। এই পর্যবেক্ষণ Johan Håstad-এর ১৯৮০-এর দশকের কাজ থেকে পরিচিত।
নিচের ব্লক তিনটি ফাঁদ আমাদের নিজেদের খেলনা key-এ দেখায়। ঘনমূলের পরীক্ষায় একটি ৬০০-bit n বানানো হয়েছে দুটি মৌলিক থেকে (একাধিক ভিত্তিতে Fermat পরীক্ষা দিয়ে খোঁজা; scratch-এ sympy.isprime দিয়েও দুটিকে মৌলিক নিশ্চিত করা হয়েছে), যাতে দেখা যায় সমস্যাটি n-এর মাপের নয়, কাঠামোর।
n, e, d = 69527, 17, 24353 # toy key (p = 251, q = 277)
enc = lambda m: pow(m, e, n)
# 1) deterministic: equal plaintexts give equal ciphertexts
c = enc(19) # secret delivery hour, 0..23
guess = [h for h in range(24) if enc(h) == c] # try all 24 with the PUBLIC key
print("intercepted", c, "-> delivery hour", guess)
# 2) malleable: E(m1) * E(m2) = E(m1 * m2) (mod n)
m1, m2 = 125, 2 # a bid of 125 taka, a factor 2
c = enc(m1) * enc(m2) % n # made WITHOUT knowing m1 or d
print("E(125)*E(2) decrypts to", pow(c, d, n), "| E(250) == c:", enc(250) == c)
# 3) small e and small m: c = m^3 never wraps around n
def is_probable_prime(x):
return all(pow(a, x - 1, x) == 1 for a in (2, 3, 5, 7, 11, 13))
def prime_2mod3(x): # need gcd(3, p - 1) = 1, so p = 2 (mod 3)
while not (x % 3 == 2 and is_probable_prime(x)): x += 1
return x
P, Q = prime_2mod3(2**300 + 7), prime_2mod3(3 * 2**298 + 1)
N = P * Q # about 600 bits
m = int.from_bytes(b"PIN 4821", "big") # a short secret, about 64 bits
c3 = pow(m, 3, N)
def icbrt(x): # integer cube root by bisection
lo, hi = 0, 1 << (x.bit_length() // 3 + 2)
while lo < hi:
mid = (lo + hi + 1) // 2
lo, hi = (mid, hi) if mid**3 <= x else (lo, mid - 1)
return lo
print(N.bit_length(), "bit n; m^3 < n:", m**3 < N)
print("cube root of c, no key used:", icbrt(c3).to_bytes(8, "big"))আসল আউটপুট (ব্রাউজারের Python):
intercepted 22324 -> delivery hour [19]
E(125)*E(2) decrypts to 250 | E(250) == c: True
600 bit n; m^3 < n: True
cube root of c, no key used: b'PIN 4821'
প্রথম লাইনে মাত্র ২৪টি চেষ্টায় গোপন ঘণ্টা 19 বেরিয়েছে, কোনো factoring ছাড়া। দ্বিতীয় লাইনে দুটি ciphertext গুণ করে 250-এর বৈধ ciphertext বানানো গেছে, ঠিক উপপাদ্য ৭.১. শেষ দুই লাইন সবচেয়ে শিক্ষণীয়: ৬০০-bit n-ও কাজে আসেনি, কারণ ৬৪-bit বার্তার ঘন মাত্র প্রায় ১৯২ bit, n-এর অনেক নিচে, আর সাধারণ ঘনমূলেই “PIN 4821” ফিরে এসেছে।
প্রতিকার: padding, আর তারপরও লাইব্রেরি
তিনটি ফাঁদের সাধারণ প্রতিকার padding: encrypt করার আগে বার্তার সঙ্গে এলোমেলো byte আর একটি নির্দিষ্ট কাঠামো জুড়ে n-এর প্রায় সমান মাপের একটি সংখ্যা বানানো। এলোমেলো অংশ ciphertext-কে প্রতিবার আলাদা করে (ফাঁদ ১), বড় মাপ ঘনমূলের পথ বন্ধ করে (ফাঁদ ৩), আর কাঠামোটি গুণ করে বানানো ciphertext-কে decryption-এর সময় অবৈধ করে দেয় (ফাঁদ ২). Encryption-এর জন্য প্রচলিত মান OAEP (Mihir Bellare আর Phillip Rogaway, ১৯৯৪), আর signature-এর জন্য RSA-PSS (একই দুজন, ১৯৯৬); দুটিই PKCS #1 মানে আছে, যার বর্তমান সংস্করণ RFC 8017 (২০১৬). পুরোনো PKCS #1 v1.5 encryption padding-এ ১৯৯৮ সালে Daniel Bleichenbacher একটি আক্রমণ দেখান, যেখানে সার্ভারের “padding ঠিক নেই” ধরনের ত্রুটি-বার্তা থেকেই ধীরে ধীরে তথ্য বেরিয়ে আসে; এর রূপভেদ বহু বছর পরেও বাস্তব সার্ভারে পাওয়া গেছে বলে প্রতিবেদন আছে।
শিক্ষাটি পরিষ্কার: সঠিক গণিত আর বড় key থাকলেও ছোট বাস্তবায়ন-ভুলে পুরো ব্যবস্থা ভেঙে যায়। আধুনিক সিস্টেম তাই সাধারণত RSA দিয়ে সরাসরি বার্তা encrypt করে না; RSA (বা key exchange) দিয়ে একটি এলোমেলো symmetric key পাঠায়, আর বার্তা যায় সেই key-এর authenticated encryption-এ, যাকে hybrid encryption বলে। নিজে RSA লিখে কোনো আসল কাজে ব্যবহার করবেন না; Cybersecurity কোর্সের পর্ব ১০ আর পর্ব ১৪-এ এর ব্যবহারিক নিয়ম আছে।
৮ · CRT দিয়ে দ্রুত decryption — আর ডেস্কটপে সত্যিকারের run
Encryption সস্তা, কারণ e = 65537-এ মাত্র ১৭টি গুণ। কিন্তু decryption আর সই ধীর, কারণ d প্রায় n-এর মাপের, অর্থাৎ ২০৪৮ bit-এ প্রায় ২০৪৮টি বর্গ। গুদাম কিন্তু p আর q জানে, আর পর্ব ২৩-এ দেখেছেন, mod n-এর একটি হিসাব mod p আর mod q-এর দুটি ছোট হিসাবে ভাঙা যায়।
আগে থেকে রাখা হয় dp = d mod (p − 1), dq = d mod (q − 1) আর qinv = q−1 mod p. তারপর প্রতিটি c-এর জন্য
mp = cdp mod p, mq = cdq mod q, m = mq + q · (qinv(mp − mq) mod p)
কেন ঠিক: d = dp + j(p − 1) কোনো j ≥ 0-এর জন্য। p ∤ c হলে Fermat-এ cd = cdp(cp−1)j ≡ cdp (mod p); p ∣ c হলে দুই পাশই 0 (dp ≥ 1, কারণ gcd(d, p − 1) = 1 বলে dp ≠ 0). তাই mp ≡ cd ≡ m (mod p), একইভাবে mq ≡ m (mod q). শেষ সূত্রটি পর্ব ২৩-এর back-substitution (Garner-এর রূপ): এটি mod q-তে mq, আর mod p-তে mq + (mp − mq) = mp, আর 0 ≤ m < pq. CRT-এর অনন্যতায় এটিই m.
হাতে, আমাদের key-এ: c = 2790, dp = 2753 mod 60 = 53, dq = 2753 mod 52 = 49, qinv = 53−1 mod 61 = 38. c mod 61 = 45 আর c mod 53 = 34; mp = 4553 mod 61 = 4, mq = 3449 mod 53 = 12. তারপর 38 · (4 − 12) = −304 ≡ 1 (mod 61), আর m = 12 + 53 · 1 = 65 ✓.
কত দ্রুত: p আর q, n-এর অর্ধেক মাপের। স্কুলের পদ্ধতির গুণে অর্ধেক মাপের দুটি সংখ্যা গুণ করতে খরচ প্রায় এক-চতুর্থাংশ, আর ঘাত dp-ও অর্ধেক bit-এর, তাই একটি অর্ধেক-ঘাত প্রায় এক-অষ্টমাংশ খরচ; দুটি মিলে প্রায় এক-চতুর্থাংশ। তত্ত্বে প্রায় ৪ গুণ দ্রুত; বাস্তবে গুণের algorithm আর অন্যান্য খরচের কারণে সাধারণত একটু কম। নিচের ব্লক ১০২৪-bit একটি খেলনা key বানিয়ে (Miller–Rabin দিয়ে, পর্ব ২৫) দুই পদ্ধতির সময় মাপে। d কখনো ছাপা হয় না।
import random, time
random.seed(2028) # toy timing only: NOT a secure key
def is_prime(x, rounds=20): # Miller-Rabin, as in lesson 25
if x % 2 == 0 or any(x % s == 0 for s in (3, 5, 7, 11, 13)): return False
d, s = x - 1, 0
while d % 2 == 0: d, s = d // 2, s + 1
for _ in range(rounds):
y = pow(random.randrange(2, x - 1), d, x)
if y in (1, x - 1): continue
for _ in range(s - 1):
y = y * y % x
if y == x - 1: break
else: return False
return True
def big_prime(bits):
while True:
x = random.getrandbits(bits) | (1 << bits - 1) | 1
if (x - 1) % 65537 and is_prime(x): return x # need gcd(e, p - 1) = 1
p, q, e = big_prime(512), big_prime(512), 65537
n = p * q; d = pow(e, -1, (p - 1) * (q - 1))
dp, dq, q_inv = d % (p - 1), d % (q - 1), pow(q, -1, p) # precomputed once
c = pow(123456789, e, n)
def plain(): return pow(c, d, n)
def crt(): # two half-size powers + Garner's step
mp, mq = pow(c, dp, p), pow(c, dq, q)
return mq + q * (q_inv * (mp - mq) % p)
for f in (plain, crt):
t = time.perf_counter(); r = [f() for _ in range(40)][0]
print(f"{f.__name__:5}: {(time.perf_counter() - t) / 40 * 1000:.2f} ms per decryption, m = {r}")
print("n has", n.bit_length(), "bits; d has", d.bit_length(), "bits (not printed)")আসল আউটপুট (ব্রাউজারের Python; সময় প্রতিবার আর প্রতিটি যন্ত্রে একটু আলাদা হবে):
plain: 2.75 ms per decryption, m = 123456789
crt : 0.99 ms per decryption, m = 123456789
n has 1024 bits; d has 1022 bits (not printed)
দুই পদ্ধতিই একই বার্তা 123456789 ফেরত দিয়েছে, কিন্তু CRT-তে প্রতিটি decryption প্রায় ২.৮ গুণ দ্রুত, তত্ত্বের “প্রায় ৪ গুণ”-এর কাছাকাছি। এ কারণে বাস্তব লাইব্রেরি private key-এর সঙ্গে p, q, dp, dq আর qinv-ও রাখে। এই গতির একটি নিরাপত্তা-মূল্যও আছে: দুই অর্ধেকের একটিতে hardware-এর ভুল ঢুকলে n-এর উৎপাদক ফাঁস হতে পারে, যা পর্ব ২৩-এর ভাবনার প্রশ্নে আলোচিত।
ডেস্কটপে সত্যিকারের run: নিজের key-তৈরি বনাম পেশাদার লাইব্রেরি
ব্রাউজারে বড় key বানানো ধীর, তাই এই পর্ব লেখার সময় একটি সাধারণ Windows ডেস্কটপে সত্যিকারের run করা হয়েছে: Python 3.12.13, cryptography 50.0.2 (Apache-2.0 বা BSD লাইসেন্স; ভেতরে OpenSSL) আর sympy 1.14.0 (BSD), uv দিয়ে বানানো একটি ছোট প্রজেক্টে। ৫১২-bit key শুধু সময় মাপার জন্য; এটি সম্পূর্ণ অনিরাপদ। নিজে চালাতে চাইলে:
cd ~/bazarghar-dm
uv add cryptography sympy
uv run python keygen_timing.pyস্ক্রিপ্টের মূল অংশ নিচে। probably_prime হলো ব্লক ৪-এর is_prime-এর মতো Miller–Rabin (৪০ round), তাই বাদ দেওয়া হলো। প্রতিটি কাজ কয়েকবার চালিয়ে মধ্যমা (median) সময় নেওয়া হয়েছে। লক্ষ করুন, n-এর শুধু প্রথম ১২টি অঙ্ক ছাপা হয়, আর private key কখনো ছাপা হয় না।
import random, time, statistics
from math import gcd
import sympy, cryptography
from cryptography.hazmat.primitives.asymmetric import rsa
rng = random.Random(2026) # toy only: NOT a secure random source
# probably_prime(n): Miller-Rabin with 40 rounds, same idea as block 4
def toy_keygen(bits, e=65537):
while True:
p, q = (next(c for c in iter(lambda: rng.getrandbits(bits // 2) | (3 << (bits // 2 - 2)) | 1, None)
if probably_prime(c)) for _ in range(2))
phi = (p - 1) * (q - 1)
if p != q and gcd(e, phi) == 1:
return p * q, e, pow(e, -1, phi)
def timed(f, k):
ts = []
for _ in range(k):
t = time.perf_counter(); r = f(); ts.append(time.perf_counter() - t)
return r, statistics.median(ts)
for bits, k in ((512, 10), (2048, 5)):
(n, e, d), t = timed(lambda: toy_keygen(bits), k)
# ... print bits, median time and the first 12 digits of n
key, t = timed(lambda: rsa.generate_private_key(public_exponent=65537, key_size=2048), 5)
# ... sympy.randprime(2**1023, 2**1024) timed the same way; four print lines$ uv run python keygen_timing.py
cryptography 50.0.2 | sympy 1.14.0
own Python keygen 512-bit: median 17.9 ms n.bit_length()=512 n=113772880175...
own Python keygen 2048-bit: median 2217.2 ms n.bit_length()=2048 n=199252508797...
sympy.randprime 1024-bit prime: median 160.9 ms
cryptography 2048-bit: median 33.9 ms e=65537 n=233617329970...
textbook check with the library's numbers: True
আমাদের নিজের Python কোডে ২০৪৮-bit key বানাতে লেগেছে প্রায় ২.২ সেকেন্ড, যেখানে cryptography লাইব্রেরির লেগেছে প্রায় ৩৪ মিলিসেকেন্ড, অর্থাৎ প্রায় ৬৫ গুণ দ্রুত। কারণ লাইব্রেরি C আর assembly-তে লেখা বড়-সংখ্যার গণিত, ছোট মৌলিক দিয়ে আগে ছাঁকা আর সতর্কভাবে বাছা পরীক্ষা ব্যবহার করে। মৌলিক খোঁজায় ভাগ্যও আছে, তাই এই সময়গুলো এক run থেকে আরেক run-এ বেশ ওঠানামা করে। শেষ লাইনে লাইব্রেরির বানানো key-এর সংখ্যা দিয়ে আমাদের textbook সূত্র m = 65-কে ফেরত এনেছে: গণিত একই, পার্থক্য গতি, এলোমেলোতার উৎস, padding আর বাস্তবায়নের যত্নে। লাইব্রেরি key বানায় অপারেটিং সিস্টেমের নিরাপদ এলোমেলো উৎস থেকে; আমাদের random.Random(2026) স্থির seed-এ চলে, তাই কেউ seed জানলে আমাদের key হুবহু আবার বানাতে পারবেন।
৯ · পরীক্ষার অঙ্ক আর একটি ভুল প্রমাণ
বিশ্ববিদ্যালয়, চাকরি বা ইন্টারভিউর লিখিত পরীক্ষায় RSA-এর যে ধাঁচের অঙ্ক আসে, তার দুটি পূর্ণ সমাধান। প্রতিটি সংখ্যা scratch-এ Python দিয়ে মেলানো।
অঙ্ক ১: p = 17, q = 11, e = 7. d বের করুন, আর m = 88 encrypt করুন।
- n = 17 · 11 = 187, φ(n) = 16 · 10 = 160. gcd(7, 160) = 1, কারণ 160 = 7 · 22 + 6 আর 7 = 6 · 1 + 1.
- পেছনে বসানো: 1 = 7 − 6 = 7 − (160 − 22 · 7) = 23 · 7 − 160. তাই d = 23. যাচাই: 7 · 23 = 161 = 160 + 1 ✓.
- 7 = 111₂, তাই 887 = 884 · 882 · 88. 882 = 7744 ≡ 77 (7744 − 41 · 187), 884 ≡ 772 = 5929 ≡ 132 (mod 187).
- 132 · 77 = 10164 ≡ 66, আর 66 · 88 = 5808 ≡ 11 (mod 187). তাই c = 11. (d = 23 দিয়ে 1123 mod 187 = 88 ফিরে আসে।)
অঙ্ক ২: public key (n, e) = (143, 7), আটকানো c = 48. বার্তা কী?
- খেলনা n ছোট, তাই trial division: 143 = 11 · 13. φ = 10 · 12 = 120.
- 120 = 7 · 17 + 1, তাই 1 = 120 − 17 · 7, আর d ≡ −17 ≡ 103 (mod 120). যাচাই: 7 · 103 = 721 = 6 · 120 + 1 ✓.
- CRT দিয়ে: dp = 103 mod 10 = 3, dq = 103 mod 12 = 7. 48 mod 11 = 4, আর 43 = 64 ≡ 9 (mod 11). 48 mod 13 = 9; 92 = 81 ≡ 3, 94 ≡ 9, 97 = 94 · 92 · 9 ≡ 9 · 3 · 9 = 243 ≡ 9 (mod 13).
- m ≡ 9 (mod 11) আর m ≡ 9 (mod 13), তাই m = 9. যাচাই: 97 mod 143 = 48 ✓. শিক্ষা: ছোট n মানে বার্তা উন্মুক্ত।
প্রমাণের ভুল ধরুন: “Euler দিয়েই সব বার্তা”
একজন লিখলেন: “দাবি: n = pq-তে ed ≡ 1 (mod φ(n)) হলে প্রতিটি m-এ med ≡ m (mod n). প্রমাণ: ed = 1 + kφ(n). Euler-এর উপপাদ্যে mφ(n) ≡ 1 (mod n), তাই med = m · (mφ(n))k ≡ m. এটি p = q হলেও খাটে। ∎” পড়ে ভুলটি নিজে খুঁজুন।
ভুল কোথায়: দ্বিতীয় বাক্যে Euler-এর উপপাদ্য তার শর্ত ছাড়া ব্যবহার হয়েছে: mφ(n) ≡ 1 শুধু gcd(m, n) = 1 হলে সত্য। Counterexample: n = 3233, m = 61-এ 613120 mod 3233 = 1220 ≠ 1. p ≠ q হলে দাবিটি তবু সত্য, কিন্তু তার জন্য উপপাদ্য ৪.২-এর Fermat-আর-CRT প্রমাণ লাগে; এই “প্রমাণ” অসম্পূর্ণ। আর শেষ বাক্যটি সরাসরি মিথ্যা: p = q = 3, n = 9, φ(9) = 6, e = d = 5 (25 ≡ 1 mod 6) নিলে m = 3-এ 325 mod 9 = 0 ≠ 3. শর্ত বাদ দেওয়া প্রমাণ শুধু অসম্পূর্ণ নয়, মিথ্যা দাবিকেও “প্রমাণ” করে ফেলতে পারে।
আরও গভীরে: উপপাদ্য ৪.২-এর প্রমাণ আসলে দুর্বলতর শর্তেও চলে: ed ≡ 1 (mod λ(n)), যেখানে λ(n) = lcm(p − 1, q − 1) হলো Carmichael ফাংশন; FIPS 186-এর মতো মান d-কে mod λ(n)-এ নেওয়ার কথা বলে বলে উল্লেখিত, আর তখন d ছোট হতে পারে। একই প্রমাণ squarefree n = p1p2⋯pk-এ চলে, যা multi-prime RSA-র ভিত্তি। d খুব ছোট হলে (মোটামুটি n1/4-এর নিচে) Michael Wiener ১৯৯০ সালে continued fraction দিয়ে তা বের করার পদ্ধতি দেখান, আর Dan Boneh-এর ১৯৯৯ সালের সমীক্ষা “Twenty Years of Attacks on the RSA Cryptosystem” এমন বহু গাণিতিক ফাঁদের তালিকা দেয়।
পরীক্ষা ও ইন্টারভিউতে: বিশ্ববিদ্যালয়, চাকরি বা ইন্টারভিউর পরীক্ষায় এই ধরনের প্রশ্ন প্রায়ই আসে:
- p = 61, q = 53, e = 17 হলে d কত? φ = 3120, extended Euclid-এ d = 2753.
- RSA কেন কাজ করে? ed ≡ 1 (mod φ(n)), তাই প্রতিটি m-এ med ≡ m (mod n); gcd = 1-এ Euler, বাকিগুলো mod p, mod q আলাদা করে Fermat, তারপর CRT.
- কোনটি public, কোনটি private? (n, e) public; d, p, q, φ(n) private.
- φ(n) ফাঁস হলে কী হয়? p + q = n − φ(n) + 1, তাই একটি দ্বিঘাত সমীকরণে p, q বেরিয়ে আসে।
- Textbook RSA কেন অনিরাপদ? deterministic, malleable (E(m1)E(m2) = E(m1m2)), আর ছোট e-তে me < n হলে সাধারণ মূলই যথেষ্ট; প্রতিকার OAEP/PSS.
১০ · AI-এর যুগে — RSA-এর হিসাব আর দাবি যাচাই
RSA এমন একটি বিষয়, যেখানে AI সহকারী আত্মবিশ্বাসী আর প্রায়-সঠিক উত্তর দেয়, আর “প্রায়” অংশটিই বিপজ্জনক। কয়েকটি ভুল নিয়মিত দেখা যায়:
| AI-এর ভুল | কীভাবে ধরবেন |
|---|---|
| বড় সংখ্যায় mod-এর হিসাব ভুল, যেমন ভুল d বা ভুল ciphertext, কিন্তু আত্মবিশ্বাসী ভঙ্গিতে | Python-এ e * d % phi == 1 আর pow(pow(m, e, n), d, n) == m চালিয়ে দেখুন |
| d-কে mod n-এ নেওয়া, বা φ(n) = n − 1 লেখা (যা শুধু মৌলিক n-এ সত্য) | φ(pq) = (p − 1)(q − 1) নিজে হিসাব করুন; ছোট উদাহরণে চালিয়ে দেখুন |
| সঠিকতার প্রমাণে শর্ত ছাড়া Euler ব্যবহার, বা p = q-তেও “কাজ করে” বলা | প্রতিটি ধাপে ব্যবহৃত উপপাদ্যের শর্ত চেয়ে নিন; m = p বা n = 9-এর মতো counterexample দিয়ে পরীক্ষা করুন |
| “RSA ভাঙা factoring-এর সমান কঠিন বলে প্রমাণিত” বা “2048-bit চিরকাল নিরাপদ” জাতীয় দাবি | খোলা প্রশ্ন আর তারিখসহ নির্দেশিকা আলাদা করুন; মূল উৎস (NIST, RFC) দেখুন |
padding ছাড়া RSA কোড, নিজের বানানো crypto, বা random দিয়ে key তৈরি সুপারিশ | বাস্তব কাজে শুধু পরীক্ষিত লাইব্রেরি আর OAEP/PSS; অনুরোধে “padding কোনটি?” জিজ্ঞেস করুন |
| বানানো ইতিহাস বা উৎস: ভুল সাল, ভুল আবিষ্কারক, অস্তিত্বহীন প্রবন্ধ | Diffie–Hellman ১৯৭৬, RSA ১৯৭৭ এর মতো তথ্য বিশ্বস্ত উৎসে মিলিয়ে নিন |
AI-এর কাছে RSA-এর হিসাব বা প্রমাণ চাইলে এমন কাঠামো দিন, যাতে প্রতিটি দাবি আলাদা করে পরীক্ষা করা যায়:
AI-এর উত্তর হাতে পেলে — যাচাইয়ের চেকলিস্ট
RSA-র প্রায় প্রতিটি দাবি ৪ অঙ্কের n-এ এক সেকেন্ডে brute force করা যায়। AI-এর “সবসময় কাজ করে” বা “প্রমাণিতভাবে নিরাপদ” দাবি পেলে আগে ছোট উদাহরণে চালান, তারপর শর্তগুলো খুঁজুন।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন, তারপর “→ উত্তর” চাপুন।
প্র ০১Clifford Cocks RSA-র মতো পদ্ধতি ১৯৭৩ সালেই পেয়েছিলেন, কিন্তু তা গোপন ছিল। প্রকাশ্য আর গোপন আবিষ্কারের এই গল্প বিজ্ঞান আর নিরাপত্তা সম্পর্কে কী শেখায়?
প্রকাশিত বিবরণ অনুযায়ী, যুক্তরাজ্যের GCHQ-তে James Ellis ১৯৭০ সালের দিকে প্রশ্ন তোলেন, আগে থেকে গোপন key ভাগ না করেও কি গোপন বার্তা পাঠানো সম্ভব। তিনি নাম দেন “non-secret encryption”, কিন্তু ব্যবহারযোগ্য গাণিতিক ফাংশন খুঁজে পাননি। ১৯৭৩ সালে নতুন যোগ দেওয়া গণিতবিদ Clifford Cocks অল্প সময়ের মধ্যে দুটি মৌলিকের গুণফল আর ঘাত দিয়ে একটি পদ্ধতি দেন, যা মূলত RSA-র মতো; পরে Malcolm Williamson Diffie–Hellman-এর মতো একটি key বিনিময়ের ধারণা দেন বলে উল্লেখ করা হয়। এই কাজ গোপন রাখা হয়, আর ১৯৯৭ সালে প্রকাশ্যে আনা হয়, ততদিনে RSA বিশ্বজুড়ে ব্যবহৃত।
কয়েকটি শিক্ষা এখানে আছে। প্রথমত, একই গাণিতিক ধারণা স্বাধীনভাবে একাধিকবার আবিষ্কৃত হয়, কারণ উপকরণ (Fermat, Euler, মৌলিক সংখ্যার তত্ত্ব) শত বছর ধরে সবার হাতে ছিল; প্রশ্নটি ঠিকভাবে তোলাই ছিল আসল ধাপ। দ্বিতীয়ত, গোপন আবিষ্কার সমাজে প্রায় কোনো প্রভাব ফেলেনি: সেই সময়ের কম্পিউটারে এটি ব্যয়বহুল মনে হয়েছিল বলে জানা যায়, আর কেউ এর ওপর কাজ এগিয়ে নিতে পারেননি। অন্যদিকে প্রকাশ্য RSA প্রবন্ধ হাজারো গবেষকের হাতে পড়ে, যাঁরা এর দুর্বলতা খুঁজেছেন, প্রতিকার দিয়েছেন, মান তৈরি করেছেন। তৃতীয়ত, এটি Kerckhoffs-এর নীতির সঙ্গে মেলে (পর্ব ২৭ আর Cybersecurity কোর্সের পর্ব ০৭): একটি পদ্ধতির নিরাপত্তা নির্ভর করা উচিত শুধু key-এর গোপনীয়তার ওপর, পদ্ধতির গোপনীয়তার ওপর নয়। প্রকাশ্য বিশ্লেষণে টিকে থাকা পদ্ধতিতেই বেশি আস্থা রাখা যায়।
একটি সাবধানতাও আছে: গোয়েন্দা সংস্থার ইতিহাসের সব বিবরণ বাইরের মানুষ যাচাই করতে পারেন না, তাই সালগুলো প্রকাশিত দলিলের ভিত্তিতে বলা, আর কৃতিত্ব নিয়ে দাবি সাবধানে করা উচিত।
মূল উপলব্ধি: গণিতের একটি ধারণা প্রকাশ্য আলোচনা, আক্রমণ আর সংশোধনের মধ্য দিয়ে গিয়েই নির্ভরযোগ্য প্রযুক্তি হয়ে ওঠে; গোপন আবিষ্কার প্রথম হলেও প্রভাবে পিছিয়ে থাকে।
প্র ০২Factoring কঠিন বলে প্রমাণ নেই, আর RSA ভাঙা factoring-এর সমান কঠিন বলেও প্রমাণ নেই। তবু প্রায় পঞ্চাশ বছর ধরে RSA-র ওপর আস্থা কেন, আর এই আস্থার সীমা কোথায়?
আস্থাটি গাণিতিক প্রমাণ থেকে নয়, অভিজ্ঞতা থেকে আসে। ১৯৭৭ সালের পর থেকে বিশ্বের সেরা গণিতবিদ আর কম্পিউটার বিজ্ঞানীরা factoring দ্রুত করার চেষ্টা করেছেন। অগ্রগতি হয়েছে, কিন্তু ধীরে আর অনুমানযোগ্যভাবে: quadratic sieve থেকে number field sieve, যার খরচ subexponential, কিন্তু polynomial নয় (পর্ব ২৫). ১৯৭৭ সালে Gardner-এর কলামের ১২৯ অঙ্কের challenge ভাঙা হয় ১৯৯৪ সালে, আর ২০২০ সালে ২৫০ অঙ্কের RSA-250. সংখ্যাটি দ্বিগুণের কাছাকাছি হলেও ২০৪৮-bit (প্রায় ৬১৭ অঙ্ক) এখনো অনেক দূরে বলে ধরা হয়। এই স্থির ইতিহাসই key-এর মাপের নির্দেশিকার ভিত্তি।
সীমা কয়েকটি। প্রথমত, তাত্ত্বিক: RSA problem (e-তম মূল বের করা) factoring-এর চেয়ে সহজ কি না, তা খোলা প্রশ্ন; কিছু গবেষণা ইঙ্গিত দেয় যে ছোট e-এর ক্ষেত্রে সাধারণ ধরনের প্রমাণ দিয়ে সমতা দেখানো কঠিন হতে পারে। দ্বিতীয়ত, প্রযুক্তিগত: Shor-এর algorithm (১৯৯৪) দেখায় যে একটি বড়, ত্রুটি-সংশোধিত quantum কম্পিউটার factoring-কে polynomial সময়ে নামাবে। তেমন যন্ত্র আজ নেই, আর কবে আসবে তার নির্ভরযোগ্য সময়রেখা নেই; তবু “আজ রেকর্ড করো, পরে ভাঙো” ঝুঁকির কারণে NIST ২০২৪ সালে post-quantum মান প্রকাশ করেছে আর RSA থেকে সরার খসড়া সময়রেখা দিয়েছে। তৃতীয়ত, বাস্তব: বেশিরভাগ বাস্তব ব্যর্থতা factoring থেকে আসেনি, এসেছে দুর্বল এলোমেলোতা (একই মৌলিক ভাগাভাগি করা key, পর্ব ২১-এর gcd), ভুল padding আর side channel থেকে।
অর্থাৎ RSA-র নিরাপত্তা একটি স্তরবদ্ধ দাবি: “সেরা জানা algorithm-এ এই মাপের n ভাঙতে অসম্ভব খরচ লাগবে” এবং “বাস্তবায়ন সঠিক”। প্রথম অংশ গণিত আর ইতিহাস দেখে, দ্বিতীয়টি প্রকৌশল দেখে।
মূল উপলব্ধি: cryptography-র নিরাপত্তা সাধারণত “প্রমাণিত” নয়, “কঠিনতার অনুমানের সাপেক্ষে”; তাই অনুমানটি কী, তার পক্ষে প্রমাণ কতটা, আর কখন তা ভাঙতে পারে, সবসময় স্পষ্ট রাখতে হয়।
প্র ০৩Bleichenbacher-এর ১৯৯৮ সালের আক্রমণ RSA-র গণিত না ভেঙেই কাজ করেছিল। এটি “padding” আর “ত্রুটি-বার্তা” সম্পর্কে কী শেখায়?
১৯৯০-এর দশকে SSL-এ RSA encryption-এর সঙ্গে PKCS #1 v1.5 padding ব্যবহৃত হতো: বার্তার আগে কয়েকটি নির্দিষ্ট byte (শুরুতে 00 02), তারপর এলোমেলো শূন্য-নয় byte, তারপর বার্তা। সার্ভার decrypt করে দেখত শুরুর byte ঠিক আছে কি না। Daniel Bleichenbacher ১৯৯৮ সালে দেখান, সার্ভার যদি কোনোভাবে জানিয়ে দেয় “padding ঠিক নেই” (আলাদা ত্রুটি-বার্তা, বা আলাদা সাড়ার সময়), তবে সেটিই একটি oracle: আক্রমণকারী উপপাদ্য ৭.১-এর গুণনীয় ধর্ম ব্যবহার করে c-কে se দিয়ে গুণ করে অনেক প্রশ্ন পাঠান, আর প্রতিটি “হ্যাঁ/না” উত্তর m-এর সম্ভাব্য পরিসর একটু ছোট করে। বহু হাজার বা লক্ষ প্রশ্নের পর পুরো বার্তা বেরিয়ে আসে, d না জেনেই।
এখানে তিনটি ধারণা মিলেছে, যা এই পর্বের গণিত থেকেই আসে। malleability: ciphertext বদলালে plaintext অনুমানযোগ্যভাবে বদলায়। কাঠামোর পরীক্ষা: padding আছে বলেই “বৈধ/অবৈধ” প্রশ্নের অর্থ আছে। আর তথ্যের ফাঁক: একটি bit-এর উত্তরও বারবার পাওয়া গেলে অনেক তথ্য হয়। প্রতিকার দুই স্তরে এসেছে। গাণিতিক স্তরে OAEP, যার নিরাপত্তার যুক্তি একটি আনুষ্ঠানিক মডেলে দেওয়া হয়েছে। প্রকৌশল স্তরে নিয়ম: decryption ব্যর্থ হলে সার্ভার এমন আচরণ করবে যাতে বাইরে থেকে পার্থক্য বোঝা না যায়। তবু ২০১৭ সালে “ROBOT” নামে প্রকাশিত গবেষণায় বহু বাস্তব সার্ভারে এই পুরোনো আক্রমণের রূপভেদ পাওয়া গিয়েছিল বলে প্রতিবেদন আছে। এ কারণেই TLS 1.3 RSA দিয়ে সরাসরি key পাঠানোর পদ্ধতিটি বাদ দিয়েছে।
বিস্তারিত TLS-এর আলোচনা Computer Networks কোর্সের পর্ব ৪৮ আর Cybersecurity কোর্সের পর্ব ১২-এ আছে।
মূল উপলব্ধি: একটি সঠিক গাণিতিক পদ্ধতির চারপাশের ছোট সিদ্ধান্ত (padding-এর গঠন, ত্রুটি-বার্তা, সাড়ার সময়) নতুন oracle তৈরি করতে পারে; তাই crypto পরীক্ষিত লাইব্রেরির হাতে ছাড়তে হয়।
প্র ০৪“সই করা মানে private key দিয়ে encrypt করা”, এই কথাটি কেন বিভ্রান্তিকর, আর hash-then-sign কেন দরকার?
Textbook RSA-তে signature আর decryption একই সূত্র: x ↦ xd mod n. সেখান থেকে জনপ্রিয় ব্যাখ্যা এসেছে, “encryption-এ public key দিয়ে লক, signature-এ private key দিয়ে লক”. কিন্তু এর লক্ষ্য একেবারে আলাদা। Encryption-এর লক্ষ্য গোপনীয়তা: বার্তা কেউ পড়বেন না। Signature-এর লক্ষ্য প্রামাণিকতা আর অখণ্ডতা: বার্তা সবাই পড়তে পারেন, কিন্তু কেউ নকল সই বানাতে পারবেন না। Elliptic curve-এর ECDSA বা EdDSA-র মতো অনেক signature পদ্ধতিতে কোনো “encryption” নেই-ই, তাই এই ব্যাখ্যা সাধারণভাবে ভুল ধারণা দেয়। ভূমিকা আলাদা বলেই padding-ও আলাদা: OAEP-এর এলোমেলোতা গোপনীয়তার জন্য, PSS-এর কাঠামো জাল সই ঠেকানোর জন্য।
Hash ছাড়া textbook signature-এ দুটি জাল সহজ। প্রথমটি “existential forgery”: যেকোনো s নিয়ে h = se mod n হিসাব করলে (h, s) একটি বৈধ জোড়া, যদিও h হয়তো অর্থহীন। দ্বিতীয়টি গুণের জাল: h1 আর h2-এর সই জানা থাকলে s1s2 mod n হলো h1h2-এর সই (অনুশীলন ১). David Chaum এই একই ধর্মকে ইতিবাচকভাবে ব্যবহার করে ১৯৮০-এর দশকের শুরুতে blind signature প্রস্তাব করেন, যেখানে সইকারী না দেখে সই দেন; একই গণিত প্রসঙ্গভেদে দুর্বলতা বা বৈশিষ্ট্য।
Hash function (যেমন SHA-256) দুটি কাজ করে। এটি যেকোনো দৈর্ঘ্যের বার্তাকে নির্দিষ্ট মাপে আনে, আর এর collision resistance-এর কারণে জাল সইয়ের h-এর পেছনে কোনো অর্থপূর্ণ বার্তা খুঁজে পাওয়া কঠিন। তবু শুধু hash-ও যথেষ্ট নয়; বাস্তবে hash-কে PSS দিয়ে n-এর মাপে কাঠামোবদ্ধভাবে ছড়ানো হয়। Signature কীভাবে certificate আর বিশ্বাসের শিকলে ব্যবহৃত হয়, তা Cybersecurity কোর্সের পর্ব ১১-এ।
মূল উপলব্ধি: একই সমীকরণ দুটি ভিন্ন নিরাপত্তা-লক্ষ্যে কাজ করতে পারে, কিন্তু প্রতিটি লক্ষ্যের নিজস্ব আক্রমণ আছে; তাই সূত্র এক হলেও নকশা, padding আর key আলাদা রাখতে হয়।
প্র ০৫Decryption-এর সময় মেপেও কি private key বের করা যায়? Timing attack আর তার প্রতিকারে RSA-র গুণনীয় ধর্ম কীভাবে কাজে লাগে?
পর্ব ২২-এর repeated squaring-এ প্রতিটি ধাপে বর্গ হয়, কিন্তু গুণ হয় শুধু ঘাতের bit 1 হলে। অর্থাৎ কাজের পরিমাণ গোপন d-এর bit-এর ওপর নির্ভর করে। Paul Kocher ১৯৯৬ সালে দেখান যে অনেক decryption-এর সময় সাবধানে মেপে আর পরিসংখ্যান বিশ্লেষণ করে এমন গোপন ঘাতের তথ্য বের করা সম্ভব। এটি একটি side channel: গণিত ঠিক থাকলেও যন্ত্রের আচরণ (সময়, বিদ্যুৎ-খরচ, cache) গোপন তথ্য ফাঁস করে। পরে দেখানো হয়েছে, নেটওয়ার্কের ওপারে থাকা সার্ভারের ক্ষেত্রেও এমন মাপজোখ কিছু পরিস্থিতিতে সম্ভব।
প্রতিকার দুই রকম। প্রথমটি constant-time বাস্তবায়ন: প্রতিটি ধাপে একই কাজ, যেমন “Montgomery ladder” বা সবসময় গুণ করে প্রয়োজনমতো ফল বাছা, আর গোপন মানের ওপর নির্ভরশীল কোনো শাখা বা memory-প্রবেশ না রাখা। দ্বিতীয়টি blinding, আর সেখানে উপপাদ্য ৭.১ ব্যবহৃত হয় প্রতিরক্ষায়: decrypt করার আগে প্রাপক একটি এলোমেলো r নিয়ে c′ = c · re mod n বানান, decrypt করে পান m · r, তারপর r−1 দিয়ে গুণ করে m. যে সংখ্যার ঘাত নেওয়া হলো, তা প্রতিবার এলোমেলো, তাই সময়ের পরিমাপ আর আক্রমণকারীর বেছে নেওয়া c-এর সঙ্গে সম্পর্কিত থাকে না। গুণনীয় ধর্ম যে আক্রমণে সাহায্য করে, এখানে তা সুরক্ষা দেয়।
ব্লক ৪-এ আমরা সময় মেপেছিলাম শুধু গতি তুলনার জন্য, নিজেদের খেলনা key-এ। পেশাদার লাইব্রেরি এই সব সুরক্ষা নিজে থেকেই প্রয়োগ করে, আর একারণেই “নিজের RSA লিখবেন না” নিয়মটি শুধু গণিতের নয়, যন্ত্রের আচরণেরও শিক্ষা।
মূল উপলব্ধি: নিরাপত্তার প্রমাণ একটি মডেলের ভেতরে চলে, যেখানে আক্রমণকারী শুধু ইনপুট আর আউটপুট দেখেন; বাস্তব যন্ত্র সেই মডেলের বাইরেও তথ্য দেয়, তাই বাস্তবায়নকে সেই অতিরিক্ত পথও বন্ধ করতে হয়।
অনুশীলন
আগে খাতায় করুন, তারপর উত্তর খুলে মেলান।
-
প্রমাণ: একটি RSA key (n, e, d)-তে textbook signature S(h) = hd mod n. প্রমাণ করুন, s1 = S(h1) আর s2 = S(h2) জানা থাকলে s1s2 mod n হলো h1h2 mod n-এর বৈধ signature, d না জেনেই। এখান থেকে hash-then-sign-এর প্রয়োজন ব্যাখ্যা করুন।
- বৈধতার শর্ত: s বৈধ সই h-এর ⇔ se ≡ h (mod n). তাই দেখাতে হবে (s1s2)e ≡ h1h2. — সংজ্ঞা ৫.১
- (s1s2)e = s1e s2e. — ঘাতের নিয়ম
- si বৈধ (উপপাদ্য ৪.২ অনুযায়ী sie = hide ≡ hi), তাই গুণফল ≡ h1h2 (mod n). এই হিসাবে শুধু public e আর দুটি পুরোনো সই লেগেছে। ∎
উদাহরণ (n = 3233, d = 2753): S(12) = 2761, S(25) = 2740, আর 2761 · 2740 mod 3233 = 3153, যার 17-তম ঘাত mod 3233 = 300 = 12 · 25 ✓. h যদি বার্তা নিজেই হতো, তবে “12” আর “25” অর্ডারের সই থেকে “300” অর্ডারের জাল সই বানানো যেত। Hash থাকলে H(M3) = H(M1)H(M2) mod n হয় এমন অর্থপূর্ণ M3 খুঁজে পাওয়া কঠিন, আর PSS-এর কাঠামো গুণফলকে অবৈধ করে।
-
হিসাব: p = 5, q = 11, e = 3. (ক) n, φ(n) আর d বের করুন। (খ) m = 9 encrypt করুন। (গ) ciphertext থেকে decrypt করে m ফেরত আনুন (CRT ব্যবহার করতে পারেন)। (ঘ) e = 5 কি এই key-এ বৈধ?
(ক) n = 55, φ = 4 · 10 = 40. 40 = 3 · 13 + 1, তাই 1 = 40 − 13 · 3, আর d ≡ −13 ≡ 27 (mod 40). যাচাই: 3 · 27 = 81 = 2 · 40 + 1 ✓.
(খ) 92 = 81 ≡ 26, 93 ≡ 26 · 9 = 234 ≡ 14 (mod 55). তাই c = 14.
(গ) dp = 27 mod 4 = 3, dq = 27 mod 10 = 7. 14 mod 5 = 4, আর 43 = 64 ≡ 4 (mod 5). 14 mod 11 = 3; 35 = 243 ≡ 1 (mod 11), তাই 37 ≡ 32 = 9. m ≡ 4 (mod 5), m ≡ 9 (mod 11) ⇒ m = 9 ✓ (9 mod 5 = 4).
(ঘ) না। gcd(5, 40) = 5 ≠ 1, তাই 5-এর inverse mod 40 নেই, আর d বানানো যায় না। সব সংখ্যা scratch-এ Python দিয়ে যাচাই করা।
-
আউটপুট অনুমান: কোড না চালিয়ে বলুন কী ছাপা হবে। তারপর যেকোনো Python-এ চালিয়ে মেলান।
n, e, d = 55, 3, 27 c = [pow(m, e, n) for m in (2, 3, 9)] print(c, pow(c[2], d, n)) print(pow(c[0] * c[2] % n, d, n))[8, 27, 14] 9 1823 = 8 আর 33 = 27, দুটিই 55-এর চেয়ে ছোট, তাই mod-এ কিছু বদলায়নি (ছোট e-র ফাঁদের ছোট রূপ)। 93 mod 55 = 14, আর decrypt করে 9 ফেরত। দ্বিতীয় লাইন উপপাদ্য ৭.১: c0c2 = 8 · 14 = 112 ≡ 2 হলো E(2 · 9) = E(18), তাই decrypt করে 18.
-
প্রমাণের ভুল ধরুন: একজন লিখলেন: “key তৈরিতে p = q নিলেও চলে। n = p2, φ(n) = (p − 1)2, আর ed ≡ 1 (mod φ(n)) হলে উপপাদ্য ৪.২-এর প্রমাণ হুবহু খাটে, কারণ সেখানে শুধু mod p-তে Fermat লেগেছিল।” কোথায় কোথায় ভুল? p = 11, e = 3 নিয়ে দেখান।
- ভুল ১: φ(p2) = p(p − 1), (p − 1)2 নয় (পর্ব ২৪). p = 11-এ (p − 1)2 = 100 নিলে d = 67, আর 121টি বার্তার 110টিতে decryption ভুল হয়।
- ভুল ২: উপপাদ্য ৪.২-এর ধাপ ৪-এ “p ∣ X আর q ∣ X ⇒ pq ∣ X” ব্যবহৃত হয়েছিল, যার জন্য p আর q সহমৌলিক হতে হয়। p = q হলে p ∣ X থেকে p2 ∣ X আসে না। সঠিক φ = 110 আর d = 37 নিলেও 11, 22, …, 110, এই 10টি বার্তা ফেরত আসে না (scratch-এ যাচাই করা)।
- ভুল ৩ (নিরাপত্তা): n = p2 হলে √n হিসাব করলেই p বেরিয়ে আসে; factoring-এর কোনো কঠিনতাই থাকে না।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমRSA key তৈরির ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- দুটি ভিন্ন বড় মৌলিক p আর q এলোমেলোভাবে বাছা
- n = pq আর φ(n) = (p − 1)(q − 1) হিসাব করা
- gcd(e, φ(n)) = 1 এমন public exponent e বাছা
- extended Euclid দিয়ে d = e−1 mod φ(n) বের করা
- (n, e) প্রকাশ করা আর d, p, q গোপন রাখা
RSA-তে p = 7, q = 11, e = 7 হলে private exponent d কত?
- 11
- 43
- 53
- 67
n = pq (p ≠ q মৌলিক) আর ed ≡ 1 (mod φ(n)). med ≡ m (mod n)-এর পূর্ণ প্রমাণে শুধু Euler-এর উপপাদ্য যথেষ্ট নয় কেন?
- কারণ φ(n)-এর সূত্র সবসময় খাটে না
- কারণ ed ≡ 1 (mod φ(n)) প্রমাণ করা যায় না
- কারণ p বা q-এর গুণিতক m-এ Euler-এর শর্ত gcd(m, n) = 1 ভাঙে
- কারণ med খুব বড় সংখ্যা
RSA modulus n = 77 আর φ(n) = 60 জানা। p আর q কী?
- 7 আর 11
- 1 আর 77
- 5 আর 13
- φ(n) থেকে বের করা যায় না, factoring লাগবে
Textbook RSA-তে কেউ আটকানো ciphertext c-কে 2e mod n দিয়ে গুণ করে প্রাপককে পাঠালেন (d না জেনে)। প্রাপক decrypt করে কী পাবেন? (m < n/2 ধরুন।)
- একটি ত্রুটি-বার্তা
- আসল m
- m + 2
- 2m
e = 3, 2048-bit n, আর padding ছাড়া একটি ৮ byte-এর বার্তা m encrypt করা হলো। আক্রমণকারী d ছাড়া m পাবেন কীভাবে?
- n-কে factor করে
- c-এর সাধারণ পূর্ণসংখ্যা ঘনমূল নিয়ে
- c-এর discrete logarithm নিয়ে
- পাওয়া সম্ভব নয়
RSA signature-এ (n, e) public আর d private. বাজারঘর একটি অর্ডার M-এ সই দেয় কীভাবে, আর গুদাম তা যাচাই করে কীভাবে?
- গুদামের public key দিয়ে M encrypt করে; গুদাম নিজের d দিয়ে খোলে
- s = H(M)e mod n দিয়ে সই, sd দিয়ে যাচাই
- বাজারঘরের d দিয়ে s = H(M)d mod n; গুদাম দেখে se mod n = H(M) কি না
- বাজারঘরের d দিয়ে সরাসরি Md, hash ছাড়া, কারণ hash অপ্রয়োজনীয়
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন, অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- Key: n = pq (p ≠ q মৌলিক), φ(n) = (p − 1)(q − 1), gcd(e, φ(n)) = 1, d = e−1 mod φ(n). Public (n, e), private d (আর p, q, φ).
- হিসাব: c = me mod n, m = cd mod n, repeated squaring-এ O(log d) গুণ। উদাহরণ: (3233, 17, 2753)-এ 65 ↦ 2790 ↦ 65.
- প্রমাণ: প্রতিটি m-এ med ≡ m (mod n): mod p আর mod q-তে আলাদা করে Fermat (বা দুই পাশই 0), তারপর CRT. শুধু Euler দিয়ে gcd(m, n) > 1 ক্ষেত্র ধরা পড়ে না।
- Signature আর নিরাপত্তা: s = H(M)d, যাচাই se ≡ H(M). φ(n) বা d ফাঁস = factor ফাঁস। ভাঙা factoring-এর সমান কঠিন কি না, তা খোলা প্রশ্ন।
- বাস্তবে: textbook RSA deterministic, malleable, ছোট e-তে ভঙ্গুর; OAEP/PSS, বড় key আর পরীক্ষিত লাইব্রেরি লাগে। CRT-তে decryption প্রায় তিন-চার গুণ দ্রুত।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ২৯ · Discrete logarithm আর Diffie–Hellman key exchangeপরবর্তী পর্বখোলা পথে একই গোপন চাবিতে পৌঁছানোর গণিত।
- পর্ব ২৪ · Fermat-এর ছোট উপপাদ্য আর Euler-এর totientপুনরালোচনাφ(n), Euler আর Fermat, যাদের ওপর RSA-র সঠিকতার প্রমাণ দাঁড়িয়ে।
- ডিসক্রিট ম্যাথমেটিক্স · কোর্স হোম৮৩টি পর্বপুরো কোর্সের মানচিত্র আর ১৪টি মডিউল।
- Cybersecurity · পর্ব ১০ · Public key cryptography — RSA, elliptic curve আর key exchangeবাস্তব ব্যবহারRSA বাস্তবে কীভাবে নিরাপদে, লাইব্রেরি আর padding-সহ ব্যবহার হয়।
- Cybersecurity · পর্ব ১৪ · Cryptography-র সাধারণ ভুলসাবধানতানিজে crypto না বানানো, key management আর post-quantum প্রস্তুতি।
- DSA · পর্ব ৬২ · Number theory — GCD, sieve আর modular arithmeticকোডে প্রয়োগFast power, modular inverse আর sieve-এর কোড।