Bài toán này có hai phần tách rời: mã hoá và quản lý khoá, rồi làm sao tìm kiếm trên bản mã.
Phần 1 — envelope encryption. Không nhúng khoá mã hoá vào code hay biến môi trường. Mô hình chuẩn:
- Một KEK (key-encryption key) nằm trong KMS/HSM, không bao giờ rời khỏi đó.
- Ứng dụng xin KMS cấp một DEK (data-encryption key); KMS trả về DEK ở cả dạng rõ (dùng trong bộ nhớ) và dạng đã mã hoá.
- Mã hoá dữ liệu bằng DEK với thuật toán AEAD (AES-256-GCM), rồi lưu ciphertext + IV + DEK đã mã hoá cạnh bản ghi. Xoá DEK dạng rõ khỏi bộ nhớ.
Lợi ích: mỗi bản ghi có thể một DEK riêng, lời gọi KMS ít, và rotate KEK không cần mã hoá lại toàn bộ dữ liệu — chỉ mã hoá lại các DEK.
Phần 2 — tra cứu. Bản mã AEAD có IV ngẫu nhiên nên cùng một số CCCD ra hai ciphertext khác nhau; không thể WHERE trực tiếp. Giải pháp thực dụng là blind index: thêm một cột lưu HMAC của giá trị đã chuẩn hoá, với khoá HMAC riêng.
-- id_number_enc: AES-256-GCM ciphertext
-- id_number_idx: HMAC-SHA256(normalize(id_number), index_key)
SELECT * FROM customers WHERE id_number_idx = $1;Tra cứu chính xác thành công, nhưng phải hiểu đánh đổi: blind index làm lộ tính bằng nhau — ai đọc được cột này biết hai bản ghi cùng số, và với miền giá trị hẹp thì có thể bị dò nếu khoá HMAC lộ. Vì vậy khoá index phải nằm trong KMS như mọi khoá khác, và không đánh index cho những trường không thật sự cần tìm.
Không làm được: so sánh khoảng, LIKE, sắp xếp trên trường đã mã hoá. Nếu nghiệp vụ cần những thứ đó, hãy xem lại — thường chỉ cần lưu 4 số cuối ở dạng rõ để hiển thị và tìm gần đúng là đủ.