TJGuard - Phần mềm quản lý mật khẩu
TJGuard Technical

Whitepaper: Kiến trúc mật mã học TJGuard

Phiên bản 1.0 — Tháng 4, 2026

T

Tác giả

Vưu Trường Nhật Thanh

Ngày phát hành

1 tháng 4, 2026

Phiên bản

1.0

Tóm tắt

TJGuard là một ứng dụng quản lý mật khẩu theo mô hình zero-knowledge — máy chủ không bao giờ nhận, lưu trữ, hay xử lý dữ liệu người dùng ở dạng văn bản thô. Toàn bộ quá trình mã hóa và giải mã đều diễn ra hoàn toàn trên thiết bị của người dùng (client-side), sử dụng các thuật toán mật mã học hiện đại đã được kiểm chứng bởi cộng đồng bảo mật quốc tế. Tài liệu này mô tả chi tiết các thuật toán, tham số kỹ thuật, và luồng hoạt động của hệ thống mật mã trong TJGuard nhằm giúp người dùng và cộng đồng kỹ thuật đánh giá độc lập mức độ bảo mật của sản phẩm.

1. Triết lý thiết kế

1.1. Zero-Knowledge là gì?

Trong mô hình zero-knowledge, nhà cung cấp dịch vụ (TJGuard) về mặt kỹ thuật không có khả năng đọc dữ liệu của người dùng, ngay cả khi muốn. Điều này khác với các mô hình truyền thống nơi nhà cung cấp giữ khóa mã hóa và chỉ "hứa" không đọc dữ liệu.

Với TJGuard:

  • Master password không bao giờ được gửi lên máy chủ.
  • Khóa mã hóa chỉ tồn tại trong RAM của trình duyệt người dùng trong thời gian phiên làm việc.
  • Máy chủ chỉ lưu trữ các blob đã mã hóa không thể đọc được nếu không có master password.
  • Khi người dùng đăng xuất hoặc bất hoạt quá 10 phút, tất cả khóa trong RAM được xóa hoàn toàn.

1.2. Nguyên tắc cốt lõi

Nguyên tắcHiện thực hóa trong TJGuard
Bảo mật ngay cả khi máy chủ bị xâm phạmChỉ lưu ciphertext, không có plaintext hay khóa
Thuật toán chuẩn quốc tếArgon2id, XChaCha20-Poly1305, Ed25519
Không tin tưởng mù quángCó thể kiểm toán kỹ thuật độc lập
Bảo vệ tối thiểu bề mặt tấn côngKhóa chỉ sống trong RAM, tự xóa sau 10 phút

2. Các thành phần mật mã học

TJGuard sử dụng bốn nhóm thuật toán mật mã, mỗi nhóm phục vụ một mục đích cụ thể:

2.1. Hàm dẫn xuất khóa từ mật khẩu — Argon2id

Mục đích: Biến master password (một chuỗi ký tự người nhớ được) thành một khóa mã hóa 256-bit (32 byte) có độ entropy cao.

Vấn đề cần giải quyết: Mật khẩu do người dùng tạo thường có entropy thấp và dễ bị tấn công brute-force. Hàm KDF (Key Derivation Function) được thiết kế để làm cho mỗi lần thử đoán mật khẩu cực kỳ tốn kém về mặt tính toán.

Thuật toán: Argon2id — phiên bản lai giữa Argon2i (kháng side-channel) và Argon2d (kháng GPU attack), đạt giải nhất cuộc thi Password Hashing Competition (PHC) năm 2015, được chuẩn hóa bởi IETF tại RFC 9106.

Tham số TJGuard:

Algorithm:      Argon2id
Memory cost:    128 MB (131,072 KB)
Time cost:      3 iterations
Parallelism:    1 thread
Output length:  32 bytes (256 bits)
Salt:           16 bytes random (stored on server, not secret)

Tại sao chọn các tham số này?

  • 128 MB memory cost: Buộc kẻ tấn công phải dùng 128 MB RAM cho mỗi lần thử, làm cho các cuộc tấn công song song bằng GPU/ASIC trở nên không khả thi về kinh tế. Với một GPU RTX 4090 có 24 GB VRAM, kẻ tấn công chỉ chạy được ~187 thử nghiệm song song thay vì hàng triệu.
  • 3 iterations: Tăng thêm thời gian tính toán trên CPU, không ảnh hưởng đáng kể đến trải nghiệm người dùng (< 1 giây) nhưng tăng chi phí tấn công.
  • Salt ngẫu nhiên: Mỗi người dùng có salt riêng, ngăn chặn tấn công rainbow table và đảm bảo hai người dùng có cùng mật khẩu vẫn ra khóa khác nhau.

Implementation: Thư viện hash-wasm (WebAssembly) — chạy trực tiếp trong trình duyệt, không cần gửi mật khẩu lên server.

2.2. Mã hóa đối xứng xác thực — XChaCha20-Poly1305

Mục đích: Mã hóa dữ liệu vault với tính năng Authenticated Encryption with Associated Data (AEAD) — đảm bảo dữ liệu vừa bí mật vừa không bị giả mạo.

Thuật toán: XChaCha20-Poly1305, gồm hai phần:

  • XChaCha20: Thuật toán mã hóa stream cipher với nonce 192-bit (24 byte). Là phiên bản mở rộng của ChaCha20 (RFC 8439), thiết kế bởi Daniel J. Bernstein. Nonce lớn hơn giúp tạo ngẫu nhiên an toàn hơn mà không lo nguy cơ nonce tái sử dụng.
  • Poly1305: MAC (Message Authentication Code) 128-bit, đảm bảo tính toàn vẹn — bất kỳ sự thay đổi nào vào ciphertext đều bị phát hiện khi giải mã.

Tham số TJGuard:

Algorithm:      XChaCha20-Poly1305
Key size:       32 bytes (256 bits)
Nonce size:     24 bytes (192 bits) — random per encryption
Tag size:       16 bytes (128 bits) MAC
AAD:            Vault owner's email (Additional Authenticated Data)

Tại sao XChaCha20-Poly1305 thay vì AES-GCM?

Tiêu chíXChaCha20-Poly1305AES-GCM
Kích thước nonce24 byte (an toàn random hơn)12 byte (cần cẩn thận hơn)
Phụ thuộc phần cứngKhông cần AES-NICần hỗ trợ phần cứng
Timing attacksConstant-time by designPhụ thuộc implementation
WebAssembly performanceRất tốtPhụ thuộc platform
Tiêu chuẩnRFC 8439 + XSalsa20 extensionNIST SP 800-38D

Additional Authenticated Data (AAD): TJGuard dùng email người dùng làm AAD. Điều này đảm bảo rằng một ciphertext chỉ có thể giải mã thành công trong ngữ cảnh của đúng tài khoản — ngăn chặn tấn công "copy ciphertext sang tài khoản khác".

Implementation: Thư viện @stablelib/xchacha20poly1305 — thuần JavaScript/TypeScript, đã được kiểm toán bảo mật.

2.3. Dẫn xuất khóa theo ngữ cảnh — HKDF-SHA256

Mục đích: Từ một khóa gốc (Account Key), dẫn xuất ra các khóa con độc lập cho từng mục trong vault, đảm bảo việc lộ khóa của một mục không ảnh hưởng đến các mục khác.

Thuật toán: HKDF (HMAC-based Key Derivation Function) với SHA-256, được chuẩn hóa tại RFC 5869 NIST SP 800-56C.

Tham số TJGuard:

Algorithm:      HKDF-SHA256
IKM (Input):    Account Key (32 bytes)
Salt:           16 bytes random (stored with vault item)
Info:           "tjguard:item:v1" (UTF-8 domain separator)
Output length:  32 bytes (256 bits)

Tại sao dùng HKDF?

Không thể dùng trực tiếp Account Key để mã hóa nhiều mục vì:

  • Key reuse risk: Dùng cùng khóa + cùng nonce = thảm họa bảo mật.
  • Forward secrecy cục bộ: Nếu khóa một mục bị lộ, các mục khác vẫn an toàn.
  • Domain separation: Tham số info = "tjguard:item:v1" đảm bảo các khóa dẫn xuất cho các mục đích khác nhau không trùng nhau.

Implementation: Web Crypto API của trình duyệt — API mật mã học cấp thấp được tích hợp sẵn, không phụ thuộc thư viện bên thứ ba.

2.4. Mã hóa bất đối xứng — Ed25519 / NaCl Box

Mục đích: Cho phép người dùng chia sẻ vault item với người khác mà không cần tiết lộ khóa mã hóa, thông qua cơ chế public-key cryptography.

Thuật toán: NaCl box (Networking and Cryptography Library), dựa trên:

  • X25519 (RFC 7748): Elliptic Curve Diffie-Hellman (ECDH) để thỏa thuận khóa chung.
  • XSalsa20-Poly1305: AEAD để mã hóa dữ liệu sau khi có shared secret.

Tham số TJGuard:

Library:        TweetNaCl (JavaScript port of NaCl)
Key pair:       nacl.box.keyPair() — Ed25519-compatible (RFC 8032)
Secret key:     32 bytes
Public key:     32 bytes (stored publicly on server)
Nonce:          24 bytes random per seal
Ephemeral key:  Freshly generated per share

Luồng chia sẻ vault item:

Người chia sẻ (Owner):
1. Lấy public key của người nhận từ server
2. Tạo ephemeral keypair mới
3. ECDH(ephemeral_secret, recipient_public) → shared_secret
4. Mã hóa: nacl.box(itemKey, nonce, recipient_public, ephemeral_secret)
5. Gửi lên server: [ephPub(32B) || nonce(24B) || ciphertext]

Người nhận (Recipient):
1. Lấy wrapped_item_key từ server
2. Giải nén: ephPub + nonce + ciphertext
3. ECDH(recipient_secret, ephPub) → shared_secret
4. Giải mã: nacl.box.open(ciphertext, nonce, ephPub, recipient_secret) → itemKey
5. Dùng itemKey + XChaCha20-Poly1305 để giải mã nội dung vault item

Bảo vệ private key: Private key của người dùng không bao giờ lưu dạng thô. Nó được mã hóa bằng Account Key (XChaCha20-Poly1305) trước khi gửi lên server:

enc_private_wrapped = XChaCha20-Poly1305.seal(privateKey, accountKey)

2.5. Sinh số ngẫu nhiên an toàn

Tất cả các giá trị ngẫu nhiên trong TJGuard (salt, nonce, keypair) đều được sinh bởi Web Crypto API của trình duyệt thông qua crypto.getRandomValues(). Đây là CSPRNG (Cryptographically Secure Pseudo-Random Number Generator) được chuẩn hóa theo NIST SP 800-90A Rev. 1, sử dụng entropy từ hệ điều hành (tương đương /dev/urandom trên Linux). Không có ngẫu nhiên "giả" hay seed cố định.

2.6. Xác thực hai yếu tố — TOTP

Thuật toán: TOTP (Time-based One-Time Password) theo RFC 6238, tương thích với Google Authenticator, Authy, v.v.

TOTP = HOTP(secret, floor(timestamp / 30))
HOTP = HMAC-SHA1(secret, counter)
Output: 6 digits
Window: ±30 seconds (1 step) for clock drift tolerance

Secret TOTP được lưu mã hóa trên server và chỉ dùng để xác thực — không liên quan đến khóa mã hóa vault.

3. Kiến trúc phân cấp khóa

[Master Password] + [KDF Salt]
         │
         ▼  Argon2id (128MB, 3 iter)
    [KEK - Key Encryption Key, 32B]
         │
         ▼  XChaCha20-Poly1305(seal, AAD=email)
    [Account Key, 32B] ──────────────────┐
         │                               │
         ├──▶ HKDF-SHA256(+salt+"tjguard:item:v1")
         │         │                     │
         │         ▼                     ▼
         │    [Item Key, 32B]      XChaCha20-Poly1305(seal)
         │         │                     │
         │         ▼                     ▼
         │    XChaCha20-Poly1305   [Encrypted Private Key]
         │    (encrypt vault item) (stored on server)
         │
         └──▶ Derive keypair
                   │
                   ├── Public Key → stored on server (public)
                   └── Private Key → encrypted by Account Key

Ý nghĩa kiến trúc này:

  • Thay đổi master password không cần mã hóa lại toàn bộ vault — chỉ cần wrap lại Account Key với KEK mới.
  • Recovery Key = bản sao Account Key được tải xuống an toàn — cho phép khôi phục vault mà không cần master password.
  • Chia sẻ vault dùng Item Key wrap bằng public key người nhận — không tiết lộ Account Key.
  • Xóa quyền chia sẻ yêu cầu rotate Item Key mới — người đã bị thu hồi không thể giải mã bản mới.

4. Mô hình bảo mật và phân tích mối đe dọa

4.1. Kịch bản: Máy chủ TJGuard bị xâm phạm

Dữ liệu trên serverKẻ tấn công thu đượcĐọc vault?
kdf_saltSalt của Argon2idKhông — vẫn cần master password
ak_wrappedAccount Key đã mã hóaKhông — cần KEK
enc_private_wrappedPrivate key đã mã hóaKhông — cần Account Key
ciphertextVault item đã mã hóaKhông — cần Item Key
enc_public_keyPublic key người dùngPublic key không bí mật
"Ngay cả khi database bị dump toàn bộ, kẻ tấn công không thể đọc bất kỳ vault item nào mà không biết master password của từng người dùng."

4.2. Kịch bản: Tấn công brute-force master password

Với Argon2id (128 MB, 3 iterations) theo RFC 9106:

  • Thời gian tính toán mỗi lần thử: ~300-800ms trên phần cứng thông thường
  • Với GPU RTX 4090 (24 GB VRAM): ~187 luồng song song, ~600 lần thử/phút (ước tính)
  • Với master password 12 ký tự ngẫu nhiên (chữ hoa + thường + số + ký tự đặc biệt): không gian tìm kiếm ≈ 2^78
  • Thời gian brute-force toàn bộ không gian: vượt xa thời gian hữu ích

Lưu ý: các ước tính trên giả định master password được sinh ngẫu nhiên. Password do người tạo thường có entropy thấp hơn nhiều — bạn nên dùng bộ sinh password của TJGuard.

4.3. Kịch bản: Nonce tái sử dụng

Với XChaCha20-Poly1305 (RFC 8439), nonce 24 byte (192 bit):

  • Xác suất collision với 2^64 lần mã hóa: ~10^-18 (negligible)
  • Mỗi vault item dùng nonce ngẫu nhiên mới từ crypto.getRandomValues()
  • Rủi ro thực tế: cực kỳ thấp ngay cả với hàng triệu vault item

4.4. Kịch bản: Man-in-the-Middle (MITM)

  • Toàn bộ giao tiếp qua HTTPS (TLS 1.2/1.3)
  • Dù MITM có giải được TLS: dữ liệu truyền đi vẫn là ciphertext (vault đã mã hóa)
  • Master password không bao giờ rời khỏi trình duyệt — không thể chặn qua mạng

4.5. Kịch bản: Insider threat (nhân viên TJGuard)

Vì hệ thống zero-knowledge, nhân viên TJGuard không có khả năng kỹ thuật để đọc vault của người dùng, ngay cả với toàn quyền truy cập database và source code.

5. So sánh với các tiêu chuẩn ngành

Tiêu chíTJGuardBitwarden1PasswordLastPass (cũ)
KDFArgon2idArgon2id2SKD (PBKDF2)PBKDF2
AEADXChaCha20-Poly1305AES-CBC + HMACAES-GCMAES-CBC
Chia sẻ vaultEd25519 + nacl.boxRSA-2048P-521 ECDHAES (no PK)
Zero-knowledgeKhông (breach 2022)
Open-source cryptoKhông hoàn toànKhông

TJGuard sử dụng cùng bộ thuật toán với các password manager đầu ngành, với lợi thế XChaCha20-Poly1305 (nonce lớn hơn, an toàn hơn cho môi trường web) và Argon2id với memory cost cao.

6. Thư viện mật mã học sử dụng

Thư việnMục đíchNguồn gốc
hash-wasmArgon2id (WebAssembly)MIT License, widely audited
@stablelib/xchacha20poly1305XChaCha20-Poly1305MIT License
tweetnaclEd25519, nacl.boxPublic domain, kiểm toán bởi Cure53
Web Crypto APIHKDF-SHA256, CSPRNGChuẩn W3C, tích hợp trình duyệt
otplibTOTP/HOTPMIT License

Tất cả thư viện mật mã học đều là peer-reviewed open source. TJGuard không triển khai bất kỳ thuật toán mật mã học tự chế nào (no "roll your own crypto").

7. Cơ chế bảo vệ phiên làm việc

7.1. Bộ nhớ trong phiên

Khóa mã hóa (Account Key, Private Key) chỉ tồn tại trong:

  • Zustand store (JavaScript heap của tab trình duyệt)
  • Không lưu vào localStorage, sessionStorage, hay cookie

7.2. Tự động đăng xuất

Sau 10 phút không có hoạt động (không di chuột, gõ phím, cuộn trang), hệ thống tự động:

  • Xóa Account Key và Private Key khỏi Zustand store
  • Gọi NextAuth signOut()
  • Chuyển người dùng về màn hình đăng nhập

7.3. JWT Session

  • Thời hạn JWT: 20 phút
  • Sliding window refresh: 5 phút
  • Cookie: HTTP-only, Secure, SameSite=Strict

8. Cơ chế khôi phục

8.1. Recovery Key

Recovery Key = Account Key thô (32 bytes) được tải xuống dưới dạng file .txt mã hóa sau khi xác thực OTP. Người dùng phải giữ an toàn file này — TJGuard không thể khôi phục thay cho người dùng nếu mất cả master password lẫn recovery key.

8.2. Đổi Master Password

1. Người dùng nhập recovery key + master password mới
2. Client tạo Argon2id(new_password + new_salt) → new_KEK
3. XChaCha20-Poly1305.seal(accountKey, new_KEK) → new_ak_wrapped
4. Gửi (new_kdf_salt, new_ak_wrapped) lên server
5. Vault items không cần mã hóa lại (accountKey không đổi)

8.3. Recovery Key Rotation

Khi người dùng chủ động rotate recovery key (Account Key mới):

  • Tạo Account Key mới
  • Dẫn xuất lại tất cả Item Key (HKDF với accountKey mới)
  • Mã hóa lại toàn bộ vault items
  • Cập nhật tất cả shared item keys cho người được chia sẻ

9. Kiểm toán và minh bạch

9.1. Các thuật toán đã được kiểm toán độc lập

  • Argon2id: Đạt giải nhất PHC 2015, phân tích bởi hàng chục nhóm nghiên cứu độc lập.
  • ChaCha20-Poly1305: RFC 8439, được tích hợp vào TLS 1.3.
  • NaCl/TweetNaCl: Kiểm toán bởi Cure53 (công ty bảo mật hàng đầu châu Âu).
  • HKDF: NIST SP 800-56C, được dùng trong TLS, Signal Protocol, và hàng ngàn ứng dụng.

9.2. Không "roll your own crypto"

TJGuard không tự triển khai bất kỳ primitive mật mã học nào. Toàn bộ đều dùng các thư viện đã được kiểm toán bởi cộng đồng bảo mật quốc tế.

10. Tiêu chuẩn và tuân thủ

Thuật toánTiêu chuẩn
Argon2idIETF RFC 9106
HKDF-SHA256NIST SP 800-56C, RFC 5869
XChaCha20-Poly1305RFC 8439 + XSalsa20 extension
Ed25519 / X25519RFC 8032, RFC 7748
TOTPRFC 6238
CSPRNGNIST SP 800-90A Rev. 1

Kết luận

TJGuard xây dựng kiến trúc bảo mật trên nguyên tắc: không tin tưởng bất kỳ ai, kể cả chính chúng tôi. Bằng cách dùng các thuật toán mật mã học hiện đại, đã được kiểm toán, và thực thi zero-knowledge triệt để ở tầng kỹ thuật — không phải chỉ là lời hứa — TJGuard đảm bảo rằng bảo mật của người dùng không phụ thuộc vào việc có tin tưởng nhà cung cấp hay không.

Người dùng và cộng đồng kỹ thuật được khuyến khích kiểm toán độc lập kiến trúc này. Mọi câu hỏi kỹ thuật xin liên hệ đội ngũ TJGuard qua kênh chính thức.

Tài liệu này sẽ được cập nhật theo mỗi phiên bản sản phẩm có thay đổi về kiến trúc mật mã.

Liên hệ

Nếu bạn có câu hỏi cho chúng tôi, hãy liên hệ:

Có câu hỏi kỹ thuật về kiến trúc mật mã TJGuard?

Liên hệ đội bảo mật