2025, Oct 05 01:31

AES‑CBC में सही IV कैसे सहेजें: Python उदाहरण और समाधान

AES‑CBC में IV गलत होने से Python डिक्रिप्शन विफल होता है। जानें UnicodeDecodeError की वजह, IV को सिफरटेक्स्ट संग सहेजकर सही IV से डिक्रिप्ट करने की विधि.

जब आप AES को CBC मोड में एन्क्रिप्शन के लिए इस्तेमाल करते हैं, तो एक बारीक लेकिन बेहद अहम बात आसानी से छूट सकती है—इनीशियलाइज़ेशन वेक्टर (IV)। अगर डिक्रिप्शन के समय इस्तेमाल हुआ IV, एन्क्रिप्शन वाले IV से मेल नहीं खाता, तो वापस मिली बाइट्स गलत होंगी, और उन्हें UTF‑8 टेक्स्ट की तरह समझने की कोशिश UnicodeDecodeError के साथ क्रैश कर सकती है। नीचे एक छोटा उदाहरण है जो समस्या दिखाता है और उसका सीधा समाधान भी बताता है।

समस्या का सेटअप

नीचे दिया गया Python स्निपेट AES‑CBC एन्क्रिप्शन करता है, सिफरटेक्स्ट को एक फ़ाइल में लिखता है, फिर उसे पढ़कर डिक्रिप्ट करता है। पहली नज़र में सब ठीक लगता है, लेकिन डिक्रिप्शन बाद में वैध टेक्स्ट नहीं देता।

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Hash import SHA256 as H256
def digest_hex(buf):
    h = H256.new(buf)
    return h.hexdigest()
secret = '1234'
print('Key length:', len(secret))
blk_sz = 16
msg = "The quick brown fox jumped over the lazy dog"
print('Plain text length:', len(msg))
kbuf = pad(secret.encode(), blk_sz)
print('akey length', len(kbuf))
msg_bytes = msg.encode()
enc_ctx = AES.new(kbuf, AES.MODE_CBC)
padded = pad(msg_bytes, blk_sz)
print('sha payload:', digest_hex(padded))
ct = enc_ctx.encrypt(padded)
print('Encrypted sha:', digest_hex(ct))
with open('data.bin', 'wb') as fh:
    fh.write(ct)
# ---- बाद में, डिक्रिप्ट ----
dec_ctx = AES.new(kbuf, AES.MODE_CBC)
with open('data.bin', 'rb') as fh:
    raw = fh.read()
print('file contents sha:', digest_hex(raw))
pt = dec_ctx.decrypt(raw)
print('decrypted sha:', digest_hex(pt))
clear = unpad(pt, blk_sz)
print('Plain text:', clear.decode())

डिक्रिप्शन चरण गैर‑टेक्स्ट बाइट्स देता है, और डिकोडिंग इस तरह की त्रुटि के साथ असफल हो जाती:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa8 in position 1: invalid start byte

असल में क्या गलत हो रहा है

CBC मोड में, एन्क्रिप्शन और डिक्रिप्शन दोनों में वही IV इस्तेमाल होना चाहिए। अगर डिक्रिप्शन के दौरान अलग IV उपयोग होता है, तो पहला ब्लॉक गलत तरीके से रूपांतरित होगा, और यह गलती डिक्रिप्ट किए गए आउटपुट में फैलती जाती है। भले ही कोड एन्क्रिप्ट/डिक्रिप्ट कॉल्स सफलतापूर्वक चलाता है, वापस मिली बाइट्स मूल प्लेनटेक्स्ट नहीं होतीं, इसलिए UTF‑8 में डिकोड करना त्रुटि फेंक देता है।

इसे कैसे ठीक करें

समाधान यह है कि सिफरटेक्स्ट के साथ IV को भी सहेजें और डिक्रिप्शन में वही IV दें। एक आसान तरीका है कि डिस्क पर लिखते समय IV को सिफरटेक्स्ट से पहले जोड़ दें, और पढ़ते समय शुरुआती 16 बाइट्स को AES‑CBC के IV के रूप में अलग कर लें।

IV को सहेजते हुए एन्क्रिप्शन:

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Hash import SHA256 as H256
def digest_hex(buf):
    h = H256.new(buf)
    return h.hexdigest()
secret = '1234'
blk_sz = 16
msg = "The quick brown fox jumped over the lazy dog"
kbuf = pad(secret.encode(), blk_sz)
enc_ctx = AES.new(kbuf, AES.MODE_CBC)
padded = pad(msg.encode(), blk_sz)
ct = enc_ctx.encrypt(padded)
with open('data.bin', 'wb') as fh:
    fh.write(enc_ctx.iv + ct)

सहेजे गए IV का उपयोग करते हुए डिक्रिप्शन:

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from Crypto.Hash import SHA256 as H256
def digest_hex(buf):
    h = H256.new(buf)
    return h.hexdigest()
secret = '1234'
blk_sz = 16
# kbuf को बिल्कुल उसी तरह बनाना होगा जैसा एन्क्रिप्शन के समय किया गया था
from Crypto.Util.Padding import pad
kbuf = pad(secret.encode(), blk_sz)
with open('data.bin', 'rb') as fh:
    payload = fh.read()
iv, raw = payload[:16], payload[16:]
dec_ctx = AES.new(kbuf, AES.MODE_CBC, iv=iv)
pt = dec_ctx.decrypt(raw)
clear = unpad(pt, blk_sz)
print(clear.decode())

यह क्यों मायने रखता है

सही IV के बिना आप मूल प्लेनटेक्स्ट वापस नहीं पाएंगे, भले ही API कॉल्स बिना कोई अपवाद उठाए पूरी हो जाएँ। इसका नतीजा उलझाने वाले लक्षणों में दिखता है—जैसे हैश का न मिलना और डिकोडिंग की विफलता। डिक्रिप्शन में वही IV सहेजकर और दोबारा इस्तेमाल करने से प्रक्रिया सममित रहती है और भ्रष्ट आउटपुट से बचाव होता है।

मुख्य बातें

AES को CBC मोड में इस्तेमाल करते समय, एन्क्रिप्शन के लिए बना IV हमेशा सहेजें और डिक्रिप्शन में ठीक वही IV दें। एक व्यावहारिक तरीका है कि IV और सिफरटेक्स्ट को एक ही बाइनरी ब्लॉब में जोड़ दें, और पढ़ते समय उसी क्रम में उन्हें पुनर्निर्मित करें। इस अनुशासन से अंतिम डिकोड चरण में UnicodeDecodeError जैसी पकड़ में कठिन गलतियों से बचा जा सकता है और डिक्रिप्टेड बाइट्स मूल संदेश से मेल खाती हैं।

यह लेख StackOverflow पर प्रश्न (लेखक: deostroll) और 0ro2 के उत्तर पर आधारित है।