# 🔐 Luồng Hoạt Động - Hệ Thống Lưu Mật Khẩu AES-256 **Version:** 2.0 (AES-256 Encryption) **File:** `src/utils/rememberMe.ts` **Loại Bảo Mật:** AES-256 (Advanced Encryption Standard) --- ## 📋 Mục Lục 1. [Tổng Quan](#tổng-quan) 2. [Kiến Thức Nền Tảng](#kiến-thức-nền-tảng) 3. [Luồng Lưu Thông Tin](#luồng-lưu-thông-tin) 4. [Luồng Tải Thông Tin](#luồng-tải-thông-tin) 5. [Chi Tiết Mã Hóa AES-256](#chi-tiết-mã-hóa-aes-256) 6. [Ví Dụ Cụ Thể](#ví-dụ-cụ-thể) 7. [Xử Lý Lỗi](#xử-lý-lỗi) 8. [So Sánh Bảo Mật](#so-sánh-bảo-mật) --- ## 🎯 Tổng Quan Hệ thống lưu mật khẩu "Remember Me" sử dụng **AES-256 encryption** để bảo vệ thông tin đăng nhập người dùng khi lưu vào `localStorage`. ### Các Bước Chính: ``` ┌─────────────────────────────────────────────────────────┐ │ 1. Nhập Email + Password từ form đăng nhập │ ├─────────────────────────────────────────────────────────┤ │ 2. Tạo Object: { email, password } │ ├─────────────────────────────────────────────────────────┤ │ 3. Chuyển thành JSON string │ ├─────────────────────────────────────────────────────────┤ │ 4. Mã hóa AES-256 (với SECRET_KEY) │ ├─────────────────────────────────────────────────────────┤ │ 5. Lưu ciphertext vào localStorage │ ├─────────────────────────────────────────────────────────┤ │ 6. Khi cần: Giải mã và lấy lại thông tin │ └─────────────────────────────────────────────────────────┘ ``` --- ## 🏫 Kiến Thức Nền Tảng ### AES-256 là gì? **AES** = Advanced Encryption Standard (chuẩn mã hóa quốc tế) **256** = Khóa bí mật dài 256 bit (32 bytes) ### Tại sao dùng AES-256? | Tiêu Chí | Chi Tiết | | --- | --- | | **Độ An Toàn** | ✅ Hầu như không thể bẻ khóa (2^256 khả năng) | | **Tốc Độ** | ✅ Nhanh (xử lý được tỷ tấn dữ liệu/giây) | | **Tiêu Chuẩn** | ✅ Được chính phủ Mỹ & thế giới sử dụng | | **IV (Initialization Vector)** | ✅ Tự động tạo ngẫu nhiên mỗi lần | | **Pattern Hiding** | ✅ Cùng plaintext → khác ciphertext | ### IV (Initialization Vector) là gì? - **Định nghĩa:** Một chuỗi bit ngẫu nhiên 128-bit (16 bytes) - **Chức năng:** Đảm bảo cùng plaintext lại được mã hóa khác - **Ví dụ:** ``` Plaintext: "password" Lần 1: IV = random_1 → Ciphertext = "aB3dE7..." Lần 2: IV = random_2 → Ciphertext = "xY9pQ2..." (khác!) Lần 3: IV = random_3 → Ciphertext = "kL5mR8..." (khác!) Cả 3 lần đếu giải mã lại thành "password" ``` --- ## 💾 Luồng Lưu Thông Tin ### Hàm: `saveCredentials(email, password)` ``` Đầu Vào: email = "user@gmail.com" password = "MyPassword123" ↓ ┌────────────────────────────────┐ │ Bước 1: Tạo Object Credentials │ └────────────────────────────────┘ credentials = { email: "user@gmail.com", password: "MyPassword123" } ↓ ┌─────────────────────────────────┐ │ Bước 2: Chuyển Object → JSON │ └─────────────────────────────────┘ json = '{"email":"user@gmail.com","password":"MyPassword123"}' ↓ ↓ ┌───────────────────────────────────────────┐ │ Bước 3: Mã Hóa (AES-256) │ │ │ │ Hàm: encrypt(json) │ │ CryptoJS.AES.encrypt(json, SECRET_KEY) │ └───────────────────────────────────────────┘ ↓ ↓ encrypted = "U2FsdGVkX1+ZzO2jNxNKbvH..." (output = Salt + IV + Ciphertext, tất cả dạng Base64) ↓ ┌─────────────────────────────────────────┐ │ Bước 4: Lưu vào localStorage │ │ localStorage.setItem(REMEMBER_ME_KEY, │ │ encrypted) │ └─────────────────────────────────────────┘ ↓ localStorage['smatec_remember_login'] = "U2FsdGVkX1+ZzO2jNxNKbvH..." Đầu Ra: ✅ Mật khẩu được mã hóa & lưu an toàn ``` ### Code Chi Tiết: ```typescript export function saveCredentials(email: string, password: string): void { try { // Bước 1: Tạo object const credentials: RememberedCredentials = { email, password }; // Bước 2: JSON stringify const json = JSON.stringify(credentials); // Kết quả: '{"email":"user@gmail.com","password":"MyPassword123"}' // Bước 3: Mã hóa AES-256 const encrypted = encrypt(json); // Kết quả: "U2FsdGVkX1+ZzO2jNxNKbvH..." // Bước 4: Lưu vào localStorage localStorage.setItem(REMEMBER_ME_KEY, encrypted); // Lưu thành công ✅ } catch (error) { console.error('Error saving credentials:', error); } } ``` --- ## 📂 Luồng Tải Thông Tin ### Hàm: `loadCredentials()` ``` Đầu Vào: (Không có tham số - tự động từ localStorage) ↓ ┌────────────────────────────────────────┐ │ Bước 1: Lấy Dữ Liệu Từ localStorage │ └────────────────────────────────────────┘ encrypted = localStorage.getItem(REMEMBER_ME_KEY) // Kết quả: "U2FsdGVkX1+ZzO2jNxNKbvH..." hoặc null ↓ ┌────────────────────────────────┐ │ Bước 2: Kiểm Tra Null │ └────────────────────────────────┘ if (!encrypted) { return null ❌ (Không có dữ liệu lưu) } ↓ ┌───────────────────────────────────────────┐ │ Bước 3: Giải Mã (AES-256) │ │ │ │ Hàm: decrypt(encrypted) │ │ CryptoJS.AES.decrypt(encrypted, │ │ SECRET_KEY) │ └───────────────────────────────────────────┘ ↓ ↓ decrypted_text = '{"email":"user@gmail.com","password":"MyPassword123"}' ↓ ┌──────────────────────────────────┐ │ Bước 4: Kiểm Tra Decode Hợp Lệ │ └──────────────────────────────────┘ if (!decrypted_text) { clearCredentials() // Xóa dữ liệu lỗi return null ❌ } ↓ ┌──────────────────────────────┐ │ Bước 5: Parse JSON │ └──────────────────────────────┘ credentials = JSON.parse(decrypted_text) // Kết quả: // { // email: "user@gmail.com", // password: "MyPassword123" // } ↓ return credentials ✅ Đầu Ra: RememberedCredentials object hoặc null ``` ### Code Chi Tiết: ```typescript export function loadCredentials(): RememberedCredentials | null { try { // Bước 1: Lấy từ localStorage const encrypted = localStorage.getItem(REMEMBER_ME_KEY); // Bước 2: Kiểm tra null if (!encrypted) { return null; } // Bước 3: Giải mã AES-256 const decrypted = decrypt(encrypted); // Kết quả: '{"email":"user@gmail.com","password":"MyPassword123"}' // Bước 4: Kiểm tra giải mã hợp lệ if (!decrypted) { clearCredentials(); return null; } // Bước 5: Parse JSON const credentials: RememberedCredentials = JSON.parse(decrypted); // Trả về object credentials ✅ return credentials; } catch (error) { console.error('Error loading credentials:', error); clearCredentials(); return null; } } ``` --- ## 🔐 Chi Tiết Mã Hóa AES-256 ### Hàm Encrypt ```typescript function encrypt(data: string): string { try { // CryptoJS.AES.encrypt() tự động: // 1. Tạo salt ngẫu nhiên (8 bytes) // 2. Từ salt + SECRET_KEY → tạo key & IV (PBKDF2) // 3. Mã hóa data bằng AES-256-CBC // 4. Trả về: Salt + IV + Ciphertext (tất cả Base64) const encrypted = CryptoJS.AES.encrypt(data, SECRET_KEY).toString(); return encrypted; } catch (error) { console.error('Encryption error:', error); return ''; } } ``` **Cấu Trúc Output:** ``` Ciphertext cuối cùng = "U2FsdGVkX1+ZzO2jNxNKbvH..." ↓ Được chia thành 3 phần: │ Part 1 │ Part 2 │ Part 3 │ │ Magic String │ Salt (8) │ IV + Ciphertext │ │ "Salted__" │ random │ │ └──────────────┴───────────┴─────────────────┘ ↓ Tất cả encode Base64 ``` ### Hàm Decrypt ```typescript function decrypt(encrypted: string): string { try { // CryptoJS.AES.decrypt() tự động: // 1. Decode Base64 ciphertext // 2. Trích xuất Salt từ đầu // 3. Từ salt + SECRET_KEY → tạo key & IV (PBKDF2) // 4. Giải mã dữ liệu bằng AES-256-CBC // 5. Trả về plaintext const decrypted = CryptoJS.AES.decrypt(encrypted, SECRET_KEY); // Chuyển từ WordArray sang UTF8 string const result = decrypted.toString(CryptoJS.enc.Utf8); return result; } catch (error) { console.error('Decryption error:', error); return ''; } } ``` ### Biểu Đồ Quy Trình AES-256 ``` ENCRYPTION SIDE (Lưu Mật Khẩu) ═══════════════════════════════════════════════════════ Plaintext: "password" │ ├─→ [PBKDF2 + Salt] ──→ Key (256-bit) + IV (128-bit) │ │ │ ↓ └──────────────────→ [AES-256-CBC Engine] │ ↓ Ciphertext │ ↓ [Base64 Encode] │ ↓ "U2FsdGVkX1+ZzO2jNxNKbvH..." DECRYPTION SIDE (Tải Mật Khẩu) ═══════════════════════════════════════════════════════ Ciphertext: "U2FsdGVkX1+ZzO2jNxNKbvH..." │ ├─→ [Base64 Decode] │ ├─→ Extract Salt (8 bytes) │ │ │ └──→ [PBKDF2] ──→ Key (256-bit) + IV (128-bit) │ ├─→ Extract Ciphertext │ │ │ └──→ [AES-256-CBC Engine] │ │ │ ↓ └──────────→ Plaintext: "password" ``` --- ## 💡 Ví Dụ Cụ Thể ### Ví Dụ 1: Lưu Email & Mật Khẩu **Input:** ```javascript saveCredentials('john@example.com', 'SecurePass2024!'); ``` **Bước Bước:** | Bước | Dữ Liệu | Mô Tả | | --- | --- | --- | | 1 | `{ email: "john@example.com", password: "SecurePass2024!" }` | Object credentials | | 2 | `'{"email":"john@example.com","password":"SecurePass2024!"}'` | JSON stringify | | 3 | `U2FsdGVkX1...abc123...` | AES-256 encrypt + Base64 | | 4 | localStorage | Lưu thành công ✅ | **Trong localStorage:** ```javascript localStorage = { smatec_remember_login: 'U2FsdGVkX1+ZzO2jNxNKbvHJmVaFptBWc0p...', }; ``` ### Ví Dụ 2: Tải Email & Mật Khẩu **Input:** ```javascript loadCredentials(); ``` **Bước Bước:** | Bước | Dữ Liệu | Mô Tả | | --- | --- | --- | | 1 | `"U2FsdGVkX1+ZzO2jNxNKbvHJmVaFptBWc0p..."` | Lấy từ localStorage | | 2 | ✅ Tồn tại | Kiểm tra có dữ liệu | | 3 | `'{"email":"john@example.com","password":"SecurePass2024!"}'` | AES-256 decrypt | | 4 | ✅ Valid JSON | Kiểm tra hợp lệ | | 5 | `{ email: "john@example.com", password: "SecurePass2024!" }` | JSON parse | | 6 | Trả về object | ✅ | **Output:** ```javascript { email: "john@example.com", password: "SecurePass2024!" } ``` --- ## ⚠️ Xử Lý Lỗi ### Trường Hợp 1: Không Có Dữ Liệu Lưu ``` loadCredentials() ↓ Kiểm tra localStorage ↓ encrypted === null ↓ return null ← Không có gì để tải ``` ### Trường Hợp 2: Dữ Liệu Bị Hỏng ``` loadCredentials() ↓ Lấy được dữ liệu ↓ Giải mã thất bại (decrypt() trả về '') ↓ clearCredentials() ← Xóa dữ liệu lỗi ↓ return null ← Không thể tải ``` ### Trường Hợp 3: JSON Parse Lỗi ``` loadCredentials() ↓ Giải mã thành công ↓ JSON.parse() thất bại (dữ liệu không phải JSON) ↓ catch block → clearCredentials() ↓ return null ← Lỗi JSON ``` ### Trường Hợp 4: LocalStorage Không Khả Dụng ``` Các hàm try-catch sẽ bắt lỗi ↓ Trả về false / null / log error ↓ Ứng dụng vẫn hoạt động bình thường (graceful degradation) ``` --- ## 📊 So Sánh Bảo Mật ### XOR Cipher (Cũ) vs AES-256 (Mới) ``` ╔════════════════════════════════════════════════════════════════╗ ║ XOR CIPHER (CŨ) │ AES-256 (MỚI) ║ ╠════════════════════════════════════════════════════════════════╣ ║ Mã Hóa Kiểu │ XOR từng ký tự │ Mã hóa khối ║ ║ Độ An Toàn │ ⚠️ Rất Thấp │ ✅ Cực Cao ║ ║ Key Length │ Xoay vòng bằng khóa │ 256-bit (32 bytes) ║ ║ IV │ ❌ Không có │ ✅ Ngẫu nhiên ║ ║ Brute Force │ ⚠️ Dễ (2^key_length) │ ✅ Không Thể ║ ║ Pattern │ ⚠️ Có pattern │ ✅ Ẩn pattern ║ ║ │ (cùng text → lại) │ (random IV) ║ ║ Block Mode │ N/A │ ✅ CBC Mode ║ ║ Salt │ ❌ Không │ ✅ Có PBKDF2 ║ ║ Performance │ ✅ Cực Nhanh │ ✅ Nhanh (HW opt) ║ ║ Standard │ ❌ Custom/Weak │ ✅ NIST/Military ║ ╚════════════════════════════════════════════════════════════════╝ ``` ### Ví Dụ Tấn Công: **XOR Cipher:** ``` Nếu biết: - Ciphertext = "abc123" - Plaintext đối với ciphertext khác = "password" Có thể dễ dàng suy ra SECRET_KEY bằng XOR: plaintext XOR ciphertext = key ``` **AES-256:** ``` Ngay cả biết: - Ciphertext = "U2FsdGVkX1+ZzO2jNxNKbvH..." - Plaintext = "password" - IV được sử dụng Vẫn không thể suy ra SECRET_KEY (cần brute force 2^256 khả năng) ≈ 10^77 năm với máy tính hiện đại ``` --- ## 🔧 Các Hàm Hỗ Trợ ### 1. `clearCredentials()` ```typescript export function clearCredentials(): void { localStorage.removeItem(REMEMBER_ME_KEY); // Xóa hoàn toàn dữ liệu khỏi localStorage // Dùng khi: Người dùng logout hoặc "Forget Me" } ``` ### 2. `hasSavedCredentials()` ```typescript export function hasSavedCredentials(): boolean { try { const encrypted = localStorage.getItem(REMEMBER_ME_KEY); return encrypted !== null; // Kiểm tra xem có dữ liệu lưu hay không // Dùng khi: Hiển thị checkbox "Remember Me" } catch (error) { return false; } } ``` --- ## 🎯 Luồng Sử Dụng Trong Ứng Dụng ### Sơ Đồ Hoàn Chỉnh: ``` LOGIN PAGE │ ├─→ User nhập email + password │ ├─→ Tick checkbox "Remember Me"? │ │ │ ├─→ YES: saveCredentials(email, pwd) │ │ └─→ Mã hóa + Lưu localStorage ✅ │ │ │ └─→ NO: Không lưu gì │ ├─→ Gửi login request lên server │ └─→ Server xác thực OK ✅ │ └─→ Redirect tới Dashboard SUBSEQUENT LOGIN (Lần Đăng Nhập Tiếp Theo) │ ├─→ Check: hasSavedCredentials()? │ │ │ ├─→ YES: loadCredentials() │ │ └─→ Giải mã + Parse ✅ │ │ └─→ Auto-fill form │ │ │ └─→ NO: Form trống (User nhập thủ công) │ └─→ User xác nhận + submit │ └─→ Login ``` --- ## 📝 Tóm Tắt | Chức Năng | Hàm | Mô Tả | | --- | --- | --- | | Lưu | `saveCredentials(email, pwd)` | Mã hóa AES-256 + lưu localStorage | | Tải | `loadCredentials()` | Lấy từ localStorage + giải mã | | Xóa | `clearCredentials()` | Xóa hoàn toàn từ localStorage | | Kiểm Tra | `hasSavedCredentials()` | Kiểm tra có dữ liệu hay không | ## 🛡️ Kết Luận ✅ **AES-256** được sử dụng để mã hóa thông tin sensitive ✅ **Random IV** đảm bảo mã hóa khác lần nữa ✅ **PBKDF2** làm việc với SECRET_KEY để tạo key mạnh ✅ **Try-Catch** xử lý tất cả lỗi gracefully ✅ **localStorage** là vị trí lưu phù hợp (with encrypted data) **Bảo mật hiện tại:** ⭐⭐⭐⭐⭐ (Military Grade)