JavaScript फ़ाइल एन्क्रिप्शन: स्टेप-बाय-स्टेप ट्यूटोरियल
JavaScript का उपयोग करके ब्राउज़र में फ़ाइलें एन्क्रिप्ट करें। AES एन्क्रिप्शन, की डेरिवेशन और सुरक्षित फ़ाइल हैंडलिंग को कवर करने वाला व्यावहारिक ट्यूटोरियल।
JavaScript Web Crypto API का उपयोग करके ब्राउज़र में किसी फाइल को पूरी तरह एन्क्रिप्ट कर सकता है, बिना किसी सर्वर के। मानक पाइपलाइन: फाइल को ArrayBuffer के रूप में पढ़ें, PBKDF2-SHA256 (600,000 पुनरावृत्तियों) के माध्यम से पासवर्ड से 256-बिट AES-GCM कुंजी व्युत्पन्न करें, एक यादृच्छिक 12-बाइट IV के साथ एन्क्रिप्ट करें, और salt, IV, और ciphertext को डाउनलोड योग्य Blob में पैकेज करें। प्रत्येक प्रमुख ब्राउज़र इसे window.crypto.subtle के माध्यम से नेटिव रूप से समर्थन करता है, और 2-3 GB तक की फाइलों के लिए पूरी चीज़ किसी तृतीय-पक्ष लाइब्रेरी को छुए बिना आधुनिक लैपटॉप पर दस सेकंड से कम में चलती है।
महत्वपूर्ण एल्गोरिदम विकल्प
AES-GCM चुनें, AES-CBC नहीं। GCM एक पास में प्रमाणित एन्क्रिप्शन देता है, 128-बिट टैग के साथ छेड़छाड़ का पता लगाता है, जबकि CBC को एक अलग HMAC चरण की आवश्यकता होती है जो अधिकांश ट्यूटोरियल गलत करते हैं। 256-बिट कुंजी का उपयोग करें — AES-NI वाले हार्डवेयर पर 128-बिट की तुलना में प्रदर्शन का अंतर नगण्य है। पासवर्ड-आधारित कुंजी व्युत्पत्ति के लिए PBKDF2-SHA256 चुनें जब तक आप WebAssembly के माध्यम से Argon2id शिप नहीं कर सकते, जो मज़बूत है लेकिन 50 KB डाउनलोड वज़न जोड़ता है।
इनसे बचें: ECB mode (मौलिक रूप से टूटा हुआ), हाथ से बना padding (CBC padding oracle हमलों का एक दशक), MD5 या SHA-1 (collision-broken), और crypto-js पैकेज से कुछ भी जब तक यह नहीं समझते कि यह डिफ़ॉल्ट रूप से PKCS7 के साथ CBC करता है।
फाइल को मेमोरी में पढ़ना
File API आपको बाइट्स प्राप्त करने के तीन तरीके देता है:
const buf = await file.arrayBuffer(); // whole file
const stream = file.stream(); // streaming
const text = await file.text(); // UTF-8 decoded
500 MB से ऊपर की फाइलों के लिए, arrayBuffer() अक्सर मोबाइल Safari पर विफल होता है। इसके बजाय स्ट्रीम करें:
async function* chunks(file, size = 4 * 1024 * 1024) {
for (let off = 0; off < file.size; off += size) {
yield new Uint8Array(await file.slice(off, off + size).arrayBuffer());
}
}
प्रत्येक स्लाइस डिस्क से lazily पढ़ता है, इसलिए पीक मेमोरी सीमित रहती है।
उपयोगकर्ता पासवर्ड से कुंजी व्युत्पन्न करना
कभी भी raw पासवर्ड को encrypt में पास न करें। पहले एक कुंजी व्युत्पन्न करें:
async function deriveKey(password, salt) {
const enc = new TextEncoder();
const material = await crypto.subtle.importKey(
'raw', enc.encode(password), { name: 'PBKDF2' }, false, ['deriveKey']
);
return crypto.subtle.deriveKey(
{ name: 'PBKDF2', salt, iterations: 600000, hash: 'SHA-256' },
material,
{ name: 'AES-GCM', length: 256 },
false,
['encrypt', 'decrypt']
);
}
crypto.getRandomValues(new Uint8Array(16)) के साथ प्रति फाइल एक ताज़ा 16-बाइट salt जनरेट करें। Salt को ciphertext के साथ संग्रहीत करें — फाइलों में salt का पुनः उपयोग PBKDF2 के उद्देश्य को विफल करता है। OWASP का दिसंबर 2026 पासवर्ड स्टोरेज चीट शीट वर्तमान में PBKDF2-SHA256 के लिए 600,000 पुनरावृत्ति की सिफारिश करता है, जो मिड-रेंज फोन पर लगभग 500 ms कुंजी व्युत्पत्ति में अनुवाद होता है।
फाइल एन्क्रिप्ट करना
कुंजी हाथ में होने पर, एन्क्रिप्शन प्रति buffer एक subtle.encrypt कॉल है:
async function encryptBuffer(key, plaintext) {
const iv = crypto.getRandomValues(new Uint8Array(12));
const ciphertext = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv, tagLength: 128 },
key,
plaintext
);
return { iv, ciphertext };
}
GCM यदि आप एक (iv, key) जोड़ी पुनः उपयोग करते हैं तो विनाशकारी रूप से विफल होता है — keystream collision दोनों plaintexts लीक करता है। 96-बिट यादृच्छिक IV एक कुंजी के साथ ~2^48 सुरक्षित एन्क्रिप्शन देता है, जो फाइल एन्क्रिप्शन के लिए ठीक है। यदि आप एक ही कुंजी के साथ कई चंक एन्क्रिप्ट कर रहे हैं, तो IV को एक काउंटर और एक यादृच्छिक 32-बिट prefix से व्युत्पन्न करें।
आउटपुट पैकेज करना
डिक्रिप्टर को salt, IV, और ciphertext चाहिए। उन्हें एक छोटे header के साथ एकल blob में पैक करें:
function pack(salt, iv, ciphertext) {
const magic = new TextEncoder().encode('ENC1');
return new Blob([magic, salt, iv, new Uint8Array(ciphertext)]);
}
Header को वर्जन करें (ENC1, ENC2…) ताकि आप पुरानी फाइलें तोड़े बिना बाद में एल्गोरिदम माइग्रेट कर सकें। इसके माध्यम से डाउनलोड प्रदान करें:
const url = URL.createObjectURL(packed);
const a = document.createElement('a');
a.href = url; a.download = `${file.name}.enc`; a.click();
URL.revokeObjectURL(url);
फाइलें डिक्रिप्ट करना
डिक्रिप्शन प्रक्रिया को उल्टा करता है और OperationError फेंकता है यदि पासवर्ड गलत है या फाइल के साथ छेड़छाड़ हुई है:
async function decryptFile(blob, password) {
const buf = await blob.arrayBuffer();
const view = new Uint8Array(buf);
const magic = new TextDecoder().decode(view.slice(0, 4));
if (magic !== 'ENC1') throw new Error('Unknown format');
const salt = view.slice(4, 20);
const iv = view.slice(20, 32);
const ct = view.slice(32);
const key = await deriveKey(password, salt);
const pt = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, ct);
return new Blob([pt]);
}
एक एकल त्रुटि संदेश प्रस्तुत करें — "डिक्रिप्ट नहीं हो सका, गलत पासवर्ड या भ्रष्ट फाइल" — tag विफलता और संरचनात्मक विफलता के बीच अंतर के बजाय। यह हमलावरों को जानकारी के padding-oracle-adjacent leak को हटाता है।
RAM से बाहर हुए बिना बड़ी फाइलें एन्क्रिप्ट करना
500 MB से ऊपर किसी के लिए भी, पूरी फाइल पर arrayBuffer() न कॉल करें। काउंटर से व्युत्पन्न अद्वितीय IV के साथ चंक को स्वतंत्र रूप से एन्क्रिप्ट करें:
function ivForChunk(baseIV, index) {
const iv = new Uint8Array(baseIV);
const view = new DataView(iv.buffer);
view.setUint32(8, index, false);
return iv;
}
फाइल को TransformStream के माध्यम से पाइप करें, प्रत्येक 4 MB चंक एन्क्रिप्ट करें, और File System Access API के माध्यम से डिस्क पर इंगित WritableStream में परिणाम लिखें। 20 GB फाइल के लिए भी पीक मेमोरी 10 MB के पास रहती है। चंक्ड फॉर्मेट को अपने header में चंक आकार और गणना रिकॉर्ड करनी होगी ताकि डिक्रिप्टर सही तरीके से फिर से जोड़ सके।
प्रोडक्शन में भेजे जाने वाली सामान्य गलतियाँ
तीन पैटर्न JavaScript crypto की वास्तविक कोड समीक्षाओं में दिखाई देते हैं:
पहला, सुविधा के लिए localStorage में raw कुंजी संग्रहीत करना। localStorage सिंक्रोनस, ओरिजिन-स्कोप्ड, और किसी भी XSS द्वारा पठनीय है। इसके बजाय IndexedDB में एक non-extractable CryptoKey उपयोग करें।
दूसरा, IV या salt के लिए Math.random() का उपयोग करना। Math.random() पूर्वानुमानित है; हमेशा crypto.getRandomValues का उपयोग करें।
तीसरा, यह मान लेना कि subtle.encrypt constant-time है। यह नेटिव ब्राउज़र कार्यान्वयन में है, लेकिन इसके चारों ओर कोई भी JavaScript wrapper लगभग निश्चित रूप से नहीं है। अपना कोड hot path से बाहर रखें।
HexaTransfer यह exact पाइपलाइन लागू करता है — 600k पुनरावृत्तियों पर PBKDF2, AES-256-GCM, स्ट्रीम्ड चंक — ताकि सर्वर केवल अपारदर्शी ciphertext संग्रहीत करे। hexatransfer.com पर मुफ्त में आज़माएं — कोई खाता नहीं, 10 GB अधिकतम।
कार्यान्वयन परखना
एक टेस्ट हार्नेस लिखें जो एक यादृच्छिक 10 MB blob को राउंड-ट्रिप करता है, एक बाइट बदलता है, और assert करता है कि डिक्रिप्शन throws होता है। खराब header और छंटे हुए ciphertext के विरुद्ध fuzzing जोड़ें — सामान्य बग slice() पर लापता bounds जांच है जो reject करने के बजाय crash करती है। iPhone SE, mid-range Android, और Chromebook पर benchmark करें; 2 सेकंड से अधिक कुंजी व्युत्पत्ति मोबाइल उपयोगकर्ताओं के लिए बहुत धीमी है। प्रोडक्शन से पहले दूसरी नज़र से ऑडिट करें — crypto code सरल दिखती है और सूक्ष्म तरीकों से टूटती है जो परीक्षण चूक जाते हैं।
एंड-टू-एंड एन्क्रिप्शन के साथ बड़ी फ़ाइलें सुरक्षित रूप से भेजें
एंड-टू-एंड एन्क्रिप्शन के साथ 10 GB तक की फ़ाइलें मुफ़्त में ट्रांसफ़र करें। अकाउंट की आवश्यकता नहीं। अपलोड से पहले आपकी फ़ाइलें ब्राउज़र में एन्क्रिप्ट की जाती हैं — कोई और उन्हें पढ़ नहीं सकता।
फ़ाइल भेजें