Trung tâm phát triển văn hóa đọc Nhà văn

Hàm dẫn xuất khóa HKDF – cơ chế tạo khóa mật mã từ vật liệu bí mật

HKDF là cấu trúc Extract-then-Expand, vai trò muối và info, phân tách miền mật mã – thành phần xuyên suốt trong X3DH, Double Ratchet và PQXDH.

33 phút đọc.

0 lượt xem.

HKDF là hàm dẫn xuất khóa chuẩn mực được thiết kế để biến đổi vật liệu khóa tùy ý thành các khóa mật mã đạt tiêu chuẩn, xuất hiện xuyên suốt trong X3DH, Double Ratchet và PQXDH như thành phần không thể thiếu.

Giới thiệu

Bài viết này mô tả hàm dẫn xuất khóa HKDF (HMAC-based Key Derivation Function – Hàm dẫn xuất khóa dựa trên HMAC), được đặc tả chính thức trong RFC 5869 bởi Hugo Krawczyk (1957–) và Pasi Eronen. HKDF giải quyết bài toán căn bản trong thiết kế giao thức mật mã: từ một nguồn vật liệu bí mật tùy ý – như đầu ra của phép tính Diffie–Hellman, khóa chủ chia sẻ hay bí mật chung từ KEM – làm thế nào tạo ra một hoặc nhiều khóa mật mã đạt tiêu chuẩn, đủ độ dài, độc lập thống kê với nhau và an toàn cho các mục đích sử dụng cụ thể.

Câu hỏi này nghe có vẻ đơn giản nhưng thực tế phức tạp và tinh tế hơn nhiều. Đầu ra của phép tính X25519 là một tọa độ trên đường cong elliptic – một số nguyên 32 byte có phân phối không hoàn toàn đồng đều và không thể dùng trực tiếp làm khóa AES hay khóa HMAC. Đầu ra của nhiều phép DH trong X3DH (DH1, DH2, DH3, DH4) cần được kết hợp thành một khóa phiên duy nhất theo cách đảm bảo an toàn. Double Ratchet cần liên tục tạo ra các cặp (khóa chuỗi mới, khóa tin nhắn) từ khóa chuỗi hiện tại mà không tiết lộ bất kỳ thông tin nào về các khóa trước hay sau. Tất cả những nhu cầu này đều được HKDF đáp ứng thông qua một thiết kế hai bước thanh lịch: trích xuất (extract) để chuẩn hóa entropy từ nguồn tùy ý, rồi mở rộng (expand) để tạo ra lượng vật liệu khóa tùy ý với các tính chất bảo mật mạnh.

Trong đặc tả Signal Protocol, HKDF xuất hiện như là hàm KDF trong X3DH, như là hàm KDF_RK trong Double Ratchet, và như là thành phần cốt lõi của quá trình dẫn xuất khóa trong PQXDH. Sự hiện diện xuyên suốt này không phải ngẫu nhiên: HKDF là lựa chọn duy nhất có đủ phân tích bảo mật hình thức để đảm bảo rằng toàn bộ các tính chất bảo mật của giao thức cấp trên không bị phá vỡ tại tầng dẫn xuất khóa.

Nền tảng lý thuyết

Để hiểu tại sao HKDF được thiết kế theo cách nó hoạt động, cần nắm rõ ba nền tảng lý thuyết: HMAC – hàm xác thực mã hóa mà HKDF xây dựng trên đó; bài toán dẫn xuất khóa và các thách thức kỹ thuật của nó; và mô hình bảo mật định nghĩa chính xác những gì HKDF đảm bảo.

HMAC – hàm xác thực mã hóa làm nền tảng

HMAC (Hash-based Message Authentication Code – Mã xác thực thông điệp dựa trên hàm băm) là cấu trúc tổng hợp biến một hàm băm mật mã thông thường thành hàm xác thực có khóa. Được định nghĩa bởi Mihir Bellare (1962–), Ran Canetti (1963–) và Hugo Krawczyk vào năm 1996 và chuẩn hóa trong RFC 2104, HMAC có công thức:

HMAC(K, m) = H((K ⊕ opad) || H((K ⊕ ipad) || m))

trong đó H là hàm băm mật mã (SHA256 hay SHA512), K là khóa bí mật, m là thông điệp, opad là hằng số 0x5c5c5c…ipad là hằng số 0x36363636…. Cấu trúc lồng ghép hai lớp băm này không phải tùy tiện: nó đảm bảo rằng kể cả khi hàm băm H bị xác định là có một số điểm yếu nhất định (cụ thể là tính chất length extension attacks), HMAC vẫn giữ được tính bảo mật. Đây là lý do tại sao HMAC được tin cậy và sử dụng rộng rãi hơn các cách dùng hàm băm ngây thơ khác như H(K || m) hay H(m || K).

Tính chất quan trọng nhất của HMAC đối với HKDF là tính chất PRF (Pseudorandom Function – Hàm giả ngẫu nhiên): khi khóa K bí mật và chưa biết, đầu ra HMAC(K, m) không thể phân biệt được với giá trị ngẫu nhiên thực sự cho bất kỳ đầu vào m nào. Điều này được chứng minh dựa trên giả định rằng hàm nén bên trong H là một PRF khi khóa hóa đúng cách – giả định này được cho là đúng với SHA256 và SHA512 dựa trên thiết kế Davies–Meyer của chúng. Tính chất PRF là điều kiện tiên quyết để HKDF có thể đảm bảo rằng các khóa đầu ra của nó trông ngẫu nhiên và độc lập với nhau đối với bất kỳ kẻ tấn công không biết vật liệu khóa đầu vào.

HMAC còn có tính chất an toàn ngay cả khi hàm băm bị va chạm (collision resistance): ngay cả khi kẻ tấn công có thể tìm được hai thông điệp m₁m₂ với H(m₁) = H(m₂), điều đó không giúp họ giả mạo HMAC nếu không biết khóa K. Tính chất này quan trọng trong bối cảnh HKDF vì nó đảm bảo rằng ngay cả khi phát sinh va chạm trong hàm băm cơ sở, quá trình dẫn xuất khóa vẫn không bị ảnh hưởng về mặt bảo mật. Đây là một trong các lý do HKDF được thiết kế dùng HMAC thay vì các hàm băm hay cấu trúc khác: HMAC cung cấp nền tảng bảo mật mạnh hơn và được phân tích kỹ lưỡng hơn bất kỳ lựa chọn thay thế nào.

Bài toán dẫn xuất khóa và những thách thức kỹ thuật

Bài toán dẫn xuất khóa phát sinh ở đây: cho một giá trị bí mật IKM (Input Keying Material – Vật liệu khóa đầu vào) có thể có phân phối không lý tưởng, làm thế nào tạo ra một hay nhiều khóa mật mã K₁, K₂, … đáp ứng đồng thời ba yêu cầu: mỗi khóa đạt entropy đầy đủ (tức là trông ngẫu nhiên thực sự với bất kỳ kẻ tấn công nào không biết IKM); các khóa độc lập về mặt thống kê với nhau (biết K₁ không cho thêm thông tin nào về K₂); và các khóa an toàn ngay cả khi IKM không đồng đều hoàn toàn nhưng có đủ entropy.

Câu trả lời ngây thơ – chỉ đơn giản là băm IKM rồi cắt lấy độ dài cần thiết – có nhiều điểm yếu. Thứ nhất, hàm băm thông thường như SHA256 được thiết kế để cung cấp tính kháng va chạm và kháng tiền ảnh, không nhất thiết cung cấp tính chất PRF mạnh khi đầu vào có phân phối không đồng đều. Thứ hai, cắt lấy nhiều phần khác nhau từ đầu ra hàm băm không đảm bảo độc lập thống kê giữa các phần đó. Thứ ba, nếu IKM có cấu trúc đặc biệt (như tọa độ điểm trên đường cong elliptic có các bit cao luôn bằng 0), phép băm đơn giản có thể để lộ cấu trúc đó qua đầu ra.

Vấn đề phức tạp thêm khi vật liệu khóa đến từ nhiều nguồn cần kết hợp. Trong X3DH, SK được tính từ bốn giá trị DH: SK = KDF(DH1 || DH2 || DH3 || DH4). Nếu dùng băm đơn giản, độ bảo mật của SK chỉ bằng độ bảo mật của phần yếu nhất trong bốn giá trị DH – vì nếu kẻ tấn công biết ba trong bốn giá trị, họ còn lại bài toán tìm giá trị thứ tư từ băm đã biết và ba giá trị kia. HKDF giải quyết điều này bằng cách xử lý toàn bộ chuỗi nối DH1 || DH2 || DH3 || DH4 như một khối vật liệu khóa duy nhất, đảm bảo rằng biết bất kỳ tập con nào trong bốn giá trị DH cũng không đủ để tính SK.

Thách thức thứ ba là tạo ra nhiều khóa có độ dài tùy ý từ một nguồn entropy có độ dài cố định. Double Ratchet cần tạo ra liên tục các cặp (khóa chuỗi 32 byte, khóa tin nhắn 32 byte) từ một khóa chuỗi 32 byte đầu vào. Nếu thực hiện bằng hai lần băm độc lập, hai đầu ra có thể có tương quan thống kê. HKDF giải quyết bằng cơ chế mở rộng (expand) có thể tạo ra lượng vật liệu khóa tùy ý trong khi đảm bảo mỗi phần đầu ra là độc lập về mặt tính toán với các phần khác.

Mô hình bảo mật và các giả định

Krawczyk phân tích bảo mật của HKDF trong bài báo gốc bằng cách xây dựng mô hình bảo mật hai tầng, tương ứng với hai bước của HKDF.

Bước trích xuất (Extract) được phân tích trong mô hình entropy yếu: đầu vào IKM có ít nhất k bit entropy nhưng phân phối có thể tùy ý (không nhất thiết đồng đều). Krawczyk chứng minh rằng nếu HMAC là PRF và đầu vào có đủ entropy, đầu ra của bước Extract – gọi là PRK (Pseudorandom Key – Khóa giả ngẫu nhiên) – không thể phân biệt với một chuỗi ngẫu nhiên đồng đều. Bằng chứng này dựa trên định lý Leftover Hash Lemma trong lý thuyết thông tin mật mã: khi hàm băm được xây dựng từ họ hàm băm phổ quát, đầu ra tiến gần đến phân phối đồng đều nếu đầu vào có đủ entropy. HMAC với muối ngẫu nhiên đáp ứng điều kiện họ hàm băm phổ quát theo nghĩa thống kê.

Bước mở rộng (Expand) được phân tích trong mô hình PRK lý tưởng: giả định rằng PRK từ bước Extract là khóa bí mật ngẫu nhiên thực sự, bước Expand dùng HMAC như một PRF để tạo ra lượng vật liệu khóa tùy ý. Krawczyk chứng minh rằng nếu HMAC là PRF (giả định chuẩn trong phân tích bảo mật), đầu ra của bước Expand không thể phân biệt được với một chuỗi ngẫu nhiên thực sự có cùng độ dài. Điều quan trọng là bằng chứng này đảm bảo tính chất phân tách: các phần khác nhau của đầu ra Expand (tương ứng với các khóa khác nhau cần tạo ra) độc lập tính toán với nhau – biết một phần không giúp tính các phần còn lại.

Kết hợp hai bước, mô hình bảo mật đầy đủ của HKDF khẳng định: nếu HMAC là PRF và đầu vào có đủ entropy, đầu ra HKDF không thể phân biệt được với các chuỗi ngẫu nhiên độc lập có cùng độ dài. Đây là nền tảng cho phép Signal Protocol dùng HKDF để kết hợp nhiều giá trị DH thành một khóa phiên, tạo chuỗi khóa tin nhắn trong Double Ratchet, và đảm bảo phân tách miền giữa các mục đích sử dụng khác nhau.

Cấu trúc HKDF

HKDF gồm hai bước tách biệt có thể dùng độc lập hoặc kết hợp tùy theo nhu cầu. Hiểu rõ từng bước và lý do tách biệt chúng là điều kiện để áp dụng đúng trong các ngữ cảnh cụ thể.

Bước trích xuất – Extract

Bước Extract nhận hai đầu vào và cho một đầu ra:

PRK = HKDF-Extract(salt, IKM)
	= HMAC-Hash(salt, IKM)

Đầu vào IKM (Input Keying Material) là vật liệu khóa gốc – có thể là đầu ra của X25519, kết quả nối nhiều giá trị DH, hay bất kỳ chuỗi byte nào có entropy. Salt là một giá trị công khai tùy chọn – nếu không cung cấp, mặc định là chuỗi toàn số 0 có độ dài bằng độ dài đầu ra của hàm băm. Đầu ra PRK (Pseudorandom Key) là khóa giả ngẫu nhiên có độ dài bằng đầu ra hàm băm (32 byte với SHA256, 64 byte với SHA512).

Vai trò của muối (salt) trong bước Extract là quan trọng và thường bị hiểu sai. Muối không phải bí mật – nó có thể là công khai mà không làm giảm bảo mật. Vai trò của muối là phân tách miền thống kê: cùng một IKM với các muối khác nhau sẽ cho ra các PRK độc lập, ngăn chặn tương quan giữa các ứng dụng sử dụng cùng vật liệu khóa gốc. Muối cũng cải thiện bảo mật khi IKM có phân phối không lý tưởng: như đã phân tích trong Leftover Hash Lemma, một muối ngẫu nhiên giúp quá trình trích xuất entropy hoạt động tốt hơn so với không có muối. Trong Signal Protocol, bước Extract thường dùng muối là chuỗi toàn số 0 – lựa chọn này là hợp lệ khi IKM đã có phân phối tốt (như đầu ra X25519) và không có nhiều ứng dụng cùng dùng chung IKM.

Bước Extract là một lần dùng: từ một IKM tùy ý, Extract tạo ra một PRK chuẩn hóa có phân phối xấp xỉ đồng đều và độ dài cố định. Sau bước này, mọi thông tin về cấu trúc hay phân phối của IKM gốc đã bị loại bỏ hoàn toàn – PRK chỉ đại diện cho lượng entropy của IKM theo dạng chuẩn hóa. Tính chất này đặc biệt quan trọng trong X3DH: bốn giá trị DH1 || DH2 || DH3 || DH4 có thể có các phân phối tương quan nhau (vì chúng đều dùng các khóa liên quan), nhưng sau bước Extract, PRK là đầu ra xấp xỉ ngẫu nhiên đồng đều phụ thuộc vào toàn bộ entropy của tất cả bốn giá trị DH.

Bước mở rộng – Expand

Bước Expand nhận PRK từ bước trước, một chuỗi thông tin ngữ cảnh (info) và độ dài đầu ra mong muốn:

OKM = HKDF-Expand(PRK, info, L)

Bước Expand tạo ra OKM (Output Keying Material) có độ dài L byte bằng cách lặp lại HMAC với bộ đếm tăng dần:

T(0) = empty string
T(1) = HMAC-Hash(PRK, T(0) || info || 0x01)
T(2) = HMAC-Hash(PRK, T(1) || info || 0x02)
T(3) = HMAC-Hash(PRK, T(2) || info || 0x03)

OKM = T(1) || T(2) || T(3) || … (lấy L byte đầu tiên)

Cấu trúc lặp này có một tính chất quan trọng: mỗi khối T(i) phụ thuộc vào T(i-1), tạo thành một chuỗi tính toán tuần tự. Kẻ tấn công không thể tính T(i) mà không tính xong T(1), T(2), …, T(i-1) (trừ khi biết PRK). Điều này đảm bảo rằng toàn bộ đầu ra OKM là một chuỗi nhất quán không thể chia cắt thành các phần độc lập – các phần khác nhau của OKM có tương quan tính toán nhưng độc lập thống kê, nghĩa là biết một phần không cho phép tính các phần khác nhanh hơn tấn công brute-force.

Tham số info là chuỗi thông tin ngữ cảnh tùy ý – thường là chuỗi ASCII mô tả mục đích sử dụng của đầu ra. Vai trò của infophân tách miền tính toán: cùng một PRK nhưng với info khác nhau sẽ cho ra các OKM hoàn toàn độc lập, ngay cả khi cùng độ dài. Điều này cho phép một PRK duy nhất được dùng để tạo nhiều khóa cho các mục đích khác nhau mà không có rủi ro tương quan. Trong Signal Protocol, info thường là chuỗi xác định giao thức và phiên bản, ví dụ MyProtocol_CURVE25519_SHA512_CRYSTALS-KYBER-1024 trong PQXDH, đảm bảo các khóa tạo ra cho ứng dụng MyProtocol không thể nhầm lẫn với khóa của bất kỳ ứng dụng hay cấu hình khác nào.

Giới hạn độ dài đầu ra của Expand là 255 lần độ dài đầu ra hàm băm – tức 255 × 32 = 8160 byte với SHA256 và 255 × 64 = 16320 byte với SHA512. Trong thực tế, Signal Protocol chưa bao giờ cần gần đến giới hạn này: các ứng dụng điển hình chỉ cần vài chục đến vài trăm byte đầu ra.

Tích hợp Extract-then-Expand

Hàm HKDF đầy đủ là tổ hợp tuần tự hai bước:

HKDF(IKM, salt, info, L) = HKDF-Expand(HKDF-Extract(salt, IKM), info, L)

Lý do tách hai bước độc lập thay vì gộp thành một hàm duy nhất là linh hoạt thiết kế. Trong một số trường hợp, cùng một PRK được dùng để tạo ra nhiều tập OKM với các info khác nhau – chạy bước Extract một lần rồi chạy Expand nhiều lần với cùng PRK hiệu quả hơn chạy HKDF đầy đủ mỗi lần. Trong các trường hợp khác – như KDF_CK trong Double Ratchet – IKM đã là khóa bí mật ngẫu nhiên 32 byte và không cần bước Extract; chỉ cần chạy Expand trực tiếp trên IKM như PRK.

Nguyên lý Extract-then-Expand cũng phản ánh triết lý thiết kế chính xác về trách nhiệm: Extract xử lý sự không đồng đều của đầu vào và tạo ra cơ sở ngẫu nhiên chuẩn hóa; Expand khai thác cơ sở đó để tạo ra lượng vật liệu khóa tùy ý với phân tách miền. Mỗi bước giải quyết một bài toán khác nhau và có thể được thay thế độc lập nếu cần – ví dụ, có thể thay bước Extract bằng một hàm trích xuất entropy khác mà vẫn dùng cùng bước Expand, miễn là đầu ra của bước Extract thỏa mãn cùng tính chất PRK.

HKDF trong Signal Protocol

Signal Protocol sử dụng HKDF ở ba điểm khác nhau với ba cấu hình khác nhau, phản ánh các bài toán dẫn xuất khóa khác nhau trong mỗi ngữ cảnh.

Ứng dụng trong X3DH và PQXDH

Trong X3DH, hàm KDF(KM) được định nghĩa là đầu ra 32 byte của HKDF với cấu hình đặc biệt:

KDF(KM) = HKDF(
	IKM  = F || KM,
	salt = 00…00 (độ dài bằng đầu ra hàm băm),
	info = tham số info của ứng dụng,
	L	= 32
)

Trong đó F là chuỗi 32 byte 0xFF (với Curve25519) hoặc 57 byte 0xFF (với Curve448), và KM là chuỗi nối DH1 || DH2 || DH3 || DH4. Chuỗi tiền tố F phục vụ mục đích phân tách miền với XEdDSA: nó đảm bảo rằng 32 byte đầu tiên của IKM không bao giờ là mã hóa hợp lệ của một số vô hướng hay điểm trên đường cong elliptic, ngăn chặn khả năng nhầm lẫn giữa đầu vào KDF và các giá trị mật mã khác trong giao thức.

Muối toàn số 0 là lựa chọn có chủ đích và được phân tích kỹ. Krawczyk giải thích trong bài báo gốc về HKDF rằng muối toàn số 0 là hoàn toàn hợp lệ khi IKM có phân phối đủ tốt. Đầu ra của phép tính X25519 có khoảng 250 bit entropy (trên 256 bit độ dài, một số bit bị ràng buộc bởi clamping), đủ để bước Extract hoạt động hiệu quả ngay cả với muối toàn số 0. Việc dùng muối ngẫu nhiên có thể cải thiện bảo mật trong lý thuyết nhưng yêu cầu hai bên phải đồng bộ về giá trị muối – điều này thêm độ phức tạp giao thức mà X3DH không muốn đánh đổi.

Tham số info – chuỗi ASCII định danh ứng dụng – đóng vai trò phân tách miền ở tầng ứng dụng. Trong PQXDH, info được mở rộng thành chuỗi ghép bốn tham số: MyProtocol_CURVE25519_SHA512_CRYSTALS-KYBER-1024. Sự mở rộng này không chỉ định danh ứng dụng mà còn định danh toàn bộ cấu hình mật mã, đảm bảo rằng khóa SK của PQXDH với Kyber-1024 không thể nhầm lẫn với SK của X3DH thuần túy dù cùng ứng dụng, cùng người dùng và cùng cặp khóa định danh.

Ứng dụng trong Double Ratchet

Double Ratchet sử dụng HKDF tại hai điểm với hai mục đích khác nhau, phản ánh hai tầng của cơ chế ratchet kép.

Hàm KDF_RK(rk, dh_out) được dùng trong bộ tăng Diffie–Hellman để cập nhật chuỗi gốc (root chain). Đầu vào là khóa gốc hiện tại rk và đầu ra DH mới dh_out; đầu ra là cặp (khóa gốc mới 32 byte, khóa chuỗi mới 32 byte). Cấu hình khuyến nghị là HKDF với SHA256 hoặc SHA512, dùng rk làm muối, dh_out làm IKM và một chuỗi byte cụ thể cho ứng dụng làm info. Lưu ý quan trọng: ở đây muối là rk (khóa gốc hiện tại) thay vì toàn số 0 – khác với cấu hình trong X3DH. Lý do là dh_out đơn thuần có thể có phân phối không hoàn toàn đồng đều và chỉ có khoảng 252 bit entropy; dùng rk đã chuẩn hóa làm muối giúp bước Extract hoạt động tốt hơn và đảm bảo đầu ra phụ thuộc vào cả lịch sử các bước tăng trước (qua rk) lẫn bước hiện tại (qua dh_out).

Hàm KDF_CK(ck) được dùng trong bộ tăng khóa đối xứng để tạo cặp (khóa chuỗi mới, khóa tin nhắn) từ khóa chuỗi hiện tại. Không giống KDF_RK, hàm này không có IKM tùy ý mà chỉ có khóa chuỗi ck đã là giá trị ngẫu nhiên chuẩn hóa 32 byte. Do đó, cấu hình khuyến nghị là HMAC đơn giản – không cần bước Extract đầy đủ của HKDF vì ck đã có phân phối lý tưởng. Cụ thể: khóa tin nhắn mk = HMAC-SHA256(ck, 0x01) và khóa chuỗi mới ck’ = HMAC-SHA256(ck, 0x02), với các hằng số byte 0x010x02 đóng vai trò phân tách miền. Cấu hình này thực chất là HKDF-Expand không có bước Extract, và nó hiệu quả hơn cho bài toán cụ thể này.

Sự kết hợp hai cấu hình – HKDF đầy đủ cho chuỗi gốc và HMAC đơn giản cho chuỗi đối xứng – phản ánh sự khác biệt về bài toán: chuỗi gốc cần xử lý đầu vào từ bên ngoài (đầu ra DH) có thể không đồng đều, trong khi chuỗi đối xứng chỉ xử lý trạng thái nội bộ đã chuẩn hóa. Dùng công cụ phù hợp cho từng bài toán là nguyên tắc thiết kế tốt giúp tối ưu hóa cả về hiệu suất lẫn sự rõ ràng của đặc tả.

Liên hệ với bảo mật chuyển tiếp và phục hồi sau xâm phạm

Vai trò của HKDF không chỉ là biến đổi dữ liệu kỹ thuật – nó là thành phần thiết yếu tạo nên tính chất bảo mật chuyển tiếp (forward secrecy) và khả năng phục hồi sau xâm phạm (break-in recovery) trong Double Ratchet.

Bảo mật chuyển tiếp đòi hỏi rằng biết trạng thái hiện tại (khóa chuỗi ck) không cho phép tính lại các khóa tin nhắn đã dùng trong quá khứ. Điều này đảm bảo nhờ tính chất một chiều của HMAC: biết mk = HMAC-SHA256(ck, 0x01)ck’ = HMAC-SHA256(ck, 0x02) không thể tính ngược về ck trừ khi giải được bài toán PRF inversion – bài toán được giả định là khó theo định nghĩa PRF. Do đó, kể cả khi kẻ tấn công có được ck tại thời điểm t, họ không thể tính lại ck{t-1}_ hay các khóa tin nhắn trước thời điểm t.

Khả năng phục hồi sau xâm phạm – tính chất đặc biệt của Double Ratchet – đến từ cách HKDF kết hợp đầu ra DH mới vào chuỗi gốc. Sau mỗi bước tăng DH, KDF_RK tạo ra khóa gốc mới từ hai đầu vào: rk (trạng thái cũ) và dh_out (entropy mới từ phép tính DH). Kẻ tấn công biết rk tại thời điểm t nhưng không biết khóa riêng DH mới của thiết bị (vì nó được tạo sau khi xâm phạm) sẽ không thể tính dh_out và do đó không thể tính khóa gốc mới. Đây chính là cơ chế phục hồi: entropy mới từ bước DH khi trộn vào chuỗi gốc qua HKDF làm cho trạng thái tương lai không thể dự đoán từ trạng thái đã biết.

Phân tách miền mật mã

Phân tách miền (domain separation) là kỹ thuật đảm bảo rằng cùng một vật liệu khóa dùng trong nhiều ngữ cảnh khác nhau sẽ tạo ra các khóa hoàn toàn độc lập. HKDF triển khai phân tách miền thông qua tham số info và Signal Protocol xây dựng một hệ thống phân tách miền nhiều tầng trên nền tảng đó.

Tại sao phân tách miền là bắt buộc

Phân tách miền không phải là tối ưu hóa hay tính năng bổ sung – nó là yêu cầu bảo mật bắt buộc trong bất kỳ hệ thống nào dùng cùng một vật liệu khóa cho nhiều mục đích khác nhau. Hậu quả của việc thiếu phân tách miền có thể nghiêm trọng đến mức phá vỡ hoàn toàn bảo mật.

Xét tình huống cụ thể: giả sử hệ thống dùng cùng một khóa phiên SK vừa để mã hóa tin nhắn AEAD vừa để tạo khóa xác thực HMAC, và cả hai đều chạy HKDF với cùng info. Kẻ tấn công có khả năng chọn nội dung tin nhắn (plaintext-chosen attack) có thể gửi tin nhắn đặc biệt khai thác tương quan giữa đầu ra HKDF cho mã hóa và đầu ra HKDF cho xác thực – từ đó suy ra thông tin về SK. Nếu hai đầu ra đó là độc lập (nhờ info khác nhau), cuộc tấn công thất bại. Đây không phải viễn cảnh giả thuyết: nhiều thư viện mật mã từng có lỗ hổng thực tế do thiếu phân tách miền giữa mã hóa và xác thực.

Trong bối cảnh Signal Protocol, phân tách miền cần thiết ở nhiều cấp độ. Ở cấp giao thức, SK do X3DH tạo ra không thể nhầm lẫn với SK do PQXDH tạo ra. Ở cấp ứng dụng, khóa cho giao thức SignalProtocol không thể nhầm lẫn với khóa cho bất kỳ ứng dụng nào khác dùng cùng đặc tả. Ở cấp Double Ratchet, khóa chuỗi mới và khóa tin nhắn tạo từ cùng một khóa chuỗi phải độc lập. Ở cấp chuỗi gốc, đầu ra KDF_RK cho chuỗi nhận và chuỗi gửi trong cùng bước tăng DH phải độc lập. Mỗi cấp đòi hỏi phân tách miền riêng và Signal Protocol xử lý tất cả thông qua kết hợp info, hằng số byte và cấu trúc HKDF phù hợp.

Cơ chế thực hiện trong Signal Protocol

Signal Protocol sử dụng ba cơ chế phân tách miền theo thứ tự từ thô đến tinh.

Phân tách miền tầng giao thức được thực hiện qua chuỗi F tiền tố trong IKM và tham số info của HKDF. Chuỗi F gồm các byte 0xFF đảm bảo đầu vào HKDF không bao giờ có thể bị nhầm là một điểm hay số vô hướng đường cong elliptic hợp lệ, ngăn chặn các cuộc tấn công chéo giao thức tinh vi. Tham số info trong X3DH là chuỗi định danh ứng dụng do người triển khai chọn; trong PQXDH, chuỗi này mở rộng thành bốn thành phần ngăn cách bởi dấu gạch dưới, mã hóa đầy đủ toàn bộ cấu hình mật mã. Hai ứng dụng khác nhau hay cùng ứng dụng với cấu hình khác nhau sẽ có info khác nhau, đảm bảo các SK của chúng độc lập hoàn toàn.

Phân tách miền tầng Double Ratchet được thực hiện qua hằng số byte trong KDF_CK. Sử dụng 0x01 cho khóa tin nhắn và 0x02 cho khóa chuỗi mới đảm bảo hai đầu ra HMAC này độc lập về mặt tính toán dù cùng chạy từ khóa chuỗi ck. Cách tiếp cận hằng số byte nhỏ này hiệu quả hơn việc dùng chuỗi info dài vì các hằng số chỉ chiếm một byte trong đầu vào HMAC, ít overhead hơn. Đặc tả khuyến nghị rằng các hằng số byte cho các mục đích khác nhau trong cùng giao thức phải không trùng nhau – điều kiện tối thiểu để phân tách miền có hiệu lực.

Phân tách miền tầng XEdDSA được thực hiện qua họ hàm hashi trong đặc tả XEdDSA: hash0, hash1, hash2, hash3, hash4, hash5 dùng các tiền tố byte khác nhau (0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA) để đảm bảo mỗi lần gọi hàm băm trong thuật toán ký và xác minh là độc lập. Đây là ví dụ về phân tách miền trong nội bộ thuật toán ký, không phải tầng KDF – nhưng nguyên tắc là giống nhau: cùng một dữ liệu đầu vào nhưng trong các ngữ cảnh khác nhau phải cho ra đầu ra độc lập.

Hệ quả khi thiếu phân tách miền

Hiểu tác hại cụ thể của thiếu phân tách miền giúp làm rõ tại sao đây là yêu cầu bắt buộc chứ không phải tối ưu hóa tùy chọn.

Tấn công chéo phiên xảy ra khi hai phiên giao thức khác nhau (ví dụ Mỹ Anh với Đan Nguyên và Mỹ Anh với Kỳ Lân) tạo ra các khóa không độc lập. Nếu info trong KDF không chứa định danh của các bên tham gia, hai phiên có thể tạo ra cùng SK nếu ngẫu nhiên dùng cùng khóa tiền. Điều này không chỉ là vấn đề lý thuyết: trong X3DH, DH2 = DH(EKA, IKB) và DH2’ = DH(EKA, IKB’) sẽ khác nhau nếu IKB ≠ IKB’, nhưng nếu bị thiếu sót trong AD hay info, kẻ tấn công có thể cố gắng thiết lập phiên giả mạo bằng cách sử dụng cùng EKA với IKB khác để tạo SK trùng. Chuỗi AD trong X3DH (chứa EncodeEC(IKA) và EncodeEC(IKB)) chính là biện pháp phòng thủ cho trường hợp này.

Tấn công chéo thuật toán xảy ra khi cùng một khóa được dùng trong hai thuật toán khác nhau không được thiết kế để kết hợp an toàn. Ví dụ điển hình là cùng dùng một khóa làm cả khóa mã hóa lẫn khóa MAC mà không có phân tách miền. Biết một cặp (bản rõ, bản mã) cho một ngữ cảnh có thể tiết lộ thông tin giúp tấn công ngữ cảnh khác. Trong Signal Protocol, khóa tin nhắn mk từ KDF_CK chỉ được dùng cho AEAD và bị xóa ngay sau đó – nó không được tái sử dụng cho bất kỳ mục đích nào khác. Nguyên tắc mỗi khóa chỉ dùng cho một mục đích (key separation) là ứng dụng trực tiếp của phân tách miền tại tầng khóa mật mã.

Triển khai và các lưu ý thực tế

Dù HKDF có đặc tả rõ ràng và đơn giản, triển khai sai vẫn có thể phá vỡ bảo mật hoặc gây ra lỗi giao thức. Phần này tổng hợp các sai lầm phổ biến và hướng dẫn triển khai đúng đắn.

Lựa chọn hàm băm

HKDF có thể dùng với bất kỳ hàm băm mật mã nào, nhưng không phải lựa chọn nào cũng tương đương về bảo mật và hiệu suất. Signal Protocol khuyến nghị SHA256 hoặc SHA512, và lựa chọn này không phải ngẫu nhiên.

SHA256 và SHA512 đều thuộc họ SHA-2 (Secure Hash Algorithm 2) do NIST tiêu chuẩn hóa năm 2001, được thiết kế trên cấu trúc Merkle–Damgård với hàm nén Davies–Meyer. Không có cuộc tấn công nào hiệu quả hơn tấn công sinh nhật đã biết đối với cả hai hàm này khi dùng trong HMAC, ngay cả sau hơn hai thập kỷ phân tích mật mã tích cực từ cộng đồng nghiên cứu toàn cầu. SHA256 cho đầu ra 32 byte và bảo mật khoảng 128 bit; SHA512 cho đầu ra 64 byte và bảo mật khoảng 256 bit.

Với Curve25519 (bảo mật 128 bit cổ điển), SHA256 là lựa chọn hiệu quả và đủ – mức bảo mật của HKDF sẽ bị giới hạn bởi mức bảo mật của đường cong (128 bit), không phải hàm băm, nên dùng SHA512 không tăng bảo mật thực tế mà chỉ tốn thêm thời gian tính toán. Với Curve448 (bảo mật 224 bit cổ điển), SHA512 phù hợp hơn vì nó cung cấp 256 bit bảo mật – cao hơn mức bảo mật của đường cong và đảm bảo HKDF không trở thành điểm yếu nhất trong hệ thống. Trong PQXDH với Kyber-1024 (bảo mật 180 bit hậu lượng tử theo NIST), SHA512 cũng là lựa chọn hợp lý vì Grover chỉ giảm bảo mật của SHA512 xuống còn 128 bit lượng tử – vẫn trên ngưỡng NIST Level 1.

SHA-3 (Keccak) và SHAKE cũng là các hàm băm an toàn được NIST tiêu chuẩn hóa năm 2015, nhưng Signal Protocol không dùng chúng trong HKDF vì lý do đơn giản là thiếu phân tích kết hợp với HMAC ở cùng mức độ như SHA-2. HMAC-SHA3 có tính chất khác với HMAC-SHA256 vì SHA-3 dựa trên cấu trúc sponge thay vì Merkle–Damgård, và bằng chứng bảo mật của HKDF cụ thể dùng SHA-3 ít được nghiên cứu hơn. Nguyên tắc bảo thủ là dùng tổ hợp đã được phân tích kỹ thay vì tổ hợp mới dù về lý thuyết cũng an toàn.

Sai lầm phổ biến khi triển khai

Sai lầm thứ nhất và phổ biến nhất là dùng hàm băm thay cho HKDF trong các bối cảnh đòi hỏi HKDF. Ví dụ điển hình là tính SK = SHA256(DH1 || DH2 || DH3 || DH4) thay vì SK = KDF(DH1 || DH2 || DH3 || DH4). Dù hàm băm có thể hoạt động đúng trong phần lớn trường hợp, nó không cung cấp phân tách miền, không xử lý đúng phân phối không đồng đều của đầu vào, và không có bằng chứng bảo mật hình thức tương đương HKDF. Nguy hiểm hơn, sai lầm này khó phát hiện qua kiểm thử thông thường vì hệ thống vẫn hoạt động đúng về mặt chức năng nhưng bị yếu về mặt bảo mật.

Sai lầm thứ hai là bỏ qua tham số info hoặc dùng cùng info cho các mục đích khác nhau. Bất kỳ triển khai nào gọi HKDF(IKM, salt, "", L) hay dùng info = “key” cho nhiều loại khóa khác nhau đều thiếu phân tách miền. Hệ quả có thể nghiêm trọng: hai khóa khác nhau trong cùng giao thức (ví dụ khóa mã hóa và khóa xác thực) được dẫn xuất từ cùng info sẽ có tương quan tính toán, mở ra các cuộc tấn công có thể khai thác cấu trúc đó.

Sai lầm thứ ba là nhầm lẫn thứ tự tham số hay cách nối chuỗi trong IKM. Tính AN TOÀN của X3DH phụ thuộc vào thứ tự nối DH1 || DH2 || DH3 || DH4 cụ thể – đảo thứ tự hay bỏ sót một thành phần tạo ra một giao thức khác với các tính chất bảo mật khác. Đặc tả của Signal Protocol định nghĩa chính xác thứ tự này và mỗi giá trị DH đóng vai trò gì, nhưng việc triển khai phải đảm bảo tuân thủ nghiêm ngặt. Kiểm thử vector chuẩn (test vectors) từ đặc tả chính thức là cách duy nhất đáng tin cậy để xác minh triển khai đúng thứ tự và định dạng.

Sai lầm thứ tư là tái sử dụng muối (salt) giữa các phiên hay người dùng khác nhau trong trường hợp muối có thể được chọn ngẫu nhiên. Dù Signal Protocol thường dùng muối toàn số 0 (lựa chọn hợp lệ vì IKM có phân phối tốt), một số ứng dụng khác tạo muối ngẫu nhiên để tăng cường phân tách miền. Tái sử dụng muối trong trường hợp này làm mất tính chất phân tách miền mà muối cung cấp, đặc biệt nguy hiểm nếu cùng IKM được dùng trong nhiều ngữ cảnh.

Kiểm thử và xác minh

Triển khai HKDF cần được kiểm thử ở hai cấp độ: kiểm thử đúng đắn (correctness) và kiểm thử bảo mật (security properties).

Kiểm thử đúng đắn được thực hiện bằng các vector chuẩn (test vectors) từ RFC 5869 và từ đặc tả cụ thể của giao thức đang triển khai. RFC 5869 cung cấp nhiều bộ vector kiểm thử bao phủ các trường hợp: có và không có muối, độ dài IKM khác nhau, độ dài đầu ra khác nhau, với SHA256 và SHA512. Mỗi bộ vector cho đầu vào cụ thể (IKM, salt, info, L) và đầu ra kỳ vọng (PRK, OKM). Triển khai đúng phải khớp chính xác từng byte với các vector này. Đặc tả Signal Protocol cũng cung cấp vector kiểm thử cho các hàm KDF, KDF_RK, KDF_CK cụ thể, giúp xác minh không chỉ bước HKDF đơn lẻ mà cả cấu hình tham số đầy đủ.

Kiểm thử bảo mật phức tạp hơn và thường đòi hỏi công cụ chuyên biệt. Phân tích tĩnh với công cụ như ct-verif hay boolector có thể xác minh rằng triển khai HMAC và HKDF không có nhánh phụ thuộc vào dữ liệu bí mật – điều kiện cho thời gian thực thi cố định. Kiểm thử mờ (fuzzing) với các đầu vào biên giúp phát hiện trường hợp ngoại lệ không được xử lý đúng. Kiểm toán mã nguồn độc lập bởi chuyên gia mật mã là biện pháp cao nhất nhưng cũng đắt nhất – Signal Foundation thực hiện điều này định kỳ cho toàn bộ cơ sở mã nguồn.

Một điều cần tránh tuyệt đối là tự triển khai HMAC hay HKDF từ đầu khi đã có thư viện được kiểm toán sẵn. Các thư viện như libsodium, BoringSSL (được Google duy trì và dùng trong Chrome/Android), hay HACL* (được chứng minh hình thức bằng F*) cung cấp HKDF được triển khai và kiểm toán kỹ lưỡng. Dùng thư viện này không chỉ đảm bảo đúng đắn mà còn đảm bảo các tối ưu hóa quan trọng như thời gian cố định được thực hiện đúng cách mà triển khai tự phát triển khó đảm bảo.

Kết luận

HKDF là ví dụ tiêu biểu của thiết kế mật mã học đúng đắn: giải quyết đúng bài toán, với nền tảng lý thuyết vững chắc, bằng cấu trúc đơn giản và minh bạch. Triết lý Extract-then-Expand – tách biệt bài toán chuẩn hóa entropy và bài toán tạo vật liệu khóa tùy ý – cho phép phân tích bảo mật từng bước độc lập và kết hợp chặt chẽ với nhau. Tham số info cho phép phân tách miền linh hoạt mà không cần thiết kế lại hàm cho từng ngữ cảnh.

Trong Signal Protocol, HKDF không chỉ là công cụ tiện lợi mà là thành phần bảo mật thiết yếu: nó là cầu nối giữa tính toán mật mã (đầu ra DH, đầu ra KEM) và vật liệu khóa thực sự sẵn sàng dùng cho mã hóa và xác thực. Không có HKDF hay một cơ chế dẫn xuất khóa tương đương, toàn bộ cấu trúc bảo mật của X3DH và Double Ratchet sẽ sụp đổ dù các thuật toán mật mã cốt lõi vẫn đúng về mặt toán học. Hiểu HKDF là hiểu tại sao Signal Protocol hoạt động đúng không chỉ về mặt chức năng mà còn về mặt bảo mật trong mọi trường hợp sử dụng thực tế.

Hàm dẫn xuất khóa HKDF – cơ chế tạo khóa mật mã từ vật liệu bí mật – developer, bao mat, mat ma hoc, hkdf, hmac, ham dan xuat khoa, key derivation function, signal protocol, phan tach mien, forward secrecy.
Hàm dẫn xuất khóa HKDF – cơ chế tạo khóa mật mã từ vật liệu bí mật.
  • bao-mat (10)

  • mat-ma-hoc (10)

  • signal-protocol (9)

  • hkdf (1)

  • hmac (1)

  • ham-dan-xuat-khoa (1)

  • key-derivation-function (1)

  • ma-hoa-thong-tin (8)

  • bao-mat-thong-tin (8)

  • phan-tach-mien (1)

  • domain-separation (1)

  • forward-secrecy (8)

  • double-ratchet (4)

  • x3dh (5)

  • sha256 (1)

  • sha512 (1)

  • pseudorandom-function (1)

  • extract-then-expand (1)

  • mat-ma-hoc-ung-dung (1)

Chuyên mục domain-separation

Chuyên mục ma-hoa-thong-tin

Theo dõi hành trình

Hãy để lại thông tin, khi có gì mới thì Nhà văn sẽ gửi thư đến bạn để cập nhật. Cam kết không gửi email rác.

Họ và tên

Email liên lạc

Đôi dòng chia sẻ