XAES-256-GCM: AEAD nonce mở rộng
(words.filippo.io)- XAES-256-GCM là một đặc tả AEAD mới dùng khóa 256 bit và nonce 192 bit, nhằm giúp việc quản lý nonce trong các API mã hóa cấp cao bớt rủi ro hơn
- Nonce lớn cho phép tự động tạo giá trị mới từ CSPRNG của hệ điều hành cho mỗi thông điệp, với mục tiêu rủi ro va chạm ở mức 2⁻³² trên 2⁸⁰ thông điệp
- Bên trong, nó tạo khóa dẫn xuất và nonce 96 bit từ khóa đầu vào và nonce lớn, rồi dùng nguyên AES-256-GCM tiêu chuẩn như một cấu hình nonce mở rộng
- Bản triển khai tham chiếu bằng Go nằm trong chưa đến 100 dòng chỉ với
crypto/ciphervàcrypto/aes; một phần trong 3 lần gọi AES-256 cho mỗi thông điệp có thể được tính trước - Do coi trọng tuân thủ FIPS 140 và khả năng tương thích thư viện, nó có thể được dùng cùng XChaCha20Poly1305 và AES-GCM-SIV như một ứng viên cho API AEAD không cần nonce
AEAD nonce lớn cho API cấp cao
- XAES-256-GCM là thuật toán mã hóa có xác thực với dữ liệu xác thực bổ sung (AEAD), dùng khóa 256 bit và nonce 192 bit
- Mục tiêu thiết kế được gói gọn trong ba điểm
- Hỗ trợ nonce lớn để việc sinh ngẫu nhiên vẫn an toàn ngay cả với số lượng thông điệp gần như không giới hạn
- Tuân thủ FIPS 140 đầy đủ và trực tiếp
- Dễ triển khai trên các thư viện mã hóa phổ biến
- Nhờ nonce lớn, có thể tạo API đọc nonce mới từ CSPRNG của hệ điều hành cho từng thông điệp mà người dùng không phải tự tính birthday bound
- Do ưu tiên tuân thủ và tương thích, nó có thể áp dụng ở những nơi cần AEAD, kể cả trong môi trường khó dùng các AEAD nonce lớn khác
Cấu hình nonce mở rộng tận dụng nguyên AES-256-GCM
- XAES-256-GCM là một cấu hình nonce mở rộng đặt trên AEAD hiện có, tương tự XChaCha20Poly1305
- Từ khóa đầu vào và nonce 192 bit, nó tính khóa dẫn xuất và nonce dẫn xuất dùng nội bộ cho AES-256-GCM
- Khóa đầu vào và nonce lần lượt là
K,N - Khóa và nonce AES-256-GCM dẫn xuất là
Kₓ,Nₓ
- Khóa đầu vào và nonce lần lượt là
Kₓđược tạo bằng các lần gọiAES-256ₖvà phần đầu của nonce, còn 96 bit cuối của nonce đầu vào được dùng làmNₓ- Mỗi thông điệp cần 3 lần gọi
AES-256ₖ- Trong đó, một lần có thể tính trước cho một khóa cho trước
- Hai lần gọi còn lại có thể tái sử dụng cùng key schedule
Triển khai ngắn gọn và có thể mô tả bằng các thành phần tiêu chuẩn
- Bản triển khai tham chiếu bằng Go có dưới 100 dòng, bao gồm tối ưu tính trước và phần lớn boilerplate
- Bản triển khai Go chỉ dùng
crypto/ciphervàcrypto/aestrong thư viện chuẩn - XAES-256-GCM cũng có thể được mô tả bằng KDF chuẩn NIST SP 800-108r1 và AEAD NIST AES-256-GCM chuẩn
- KDF là counter-based KDF
- PRF là CMAC-AES256
- Khóa đầu vào là
Kin - Nhãn là ký tự ASCII
X, tức0x58 - Ngữ cảnh là 96 bit đầu của nonce đầu vào
- Kích thước bộ đếm là 16 bit
- Trường
Ltùy chọn được lược bỏ - Đầu ra là khóa dẫn xuất 256 bit
- Khóa dẫn xuất và 96 bit cuối của nonce đầu vào được đưa vào AES-256-GCM
- Nhờ lựa chọn tham số, nếu gỡ bỏ các trừu tượng KDF và CMAC, nó chỉ chậm và phức tạp hơn một chút so với cách đơn giản gọi AES-256 trên bộ đếm
- Các tham số tương tự cũng được hỗ trợ trong API OpenSSL cấp cao
Triển khai bên thứ ba và test vector
- Tính đến bản chỉnh sửa ngày 2024-06-29, các triển khai bên thứ ba đã được bổ sung
- Bản triển khai Web Cryptography API dùng
CryptoKeyAES-CBC 256 bit - Đặc tả bao gồm test vector cho hai đường mã chính
MSB₁(L) = 0MSB₁(L) = 1
- Cũng có test vector tích lũy nén từ 10.000 hoặc 1.000.000 vòng lặp ngẫu nhiên
Từ bỏ /11 và các lựa chọn thay thế
- Trong ý tưởng trước đây từng có tên
XAES-256-GCM/11, nhưng đặc tả cuối cùng đã bỏ/11 /11là một tối ưu hiệu năng, và vì một trong các lý do dùng AES-GCM là tuân thủ FIPS 140, việc thay đổi số vòng sẽ làm mất tính tuân thủ- Nếu mục tiêu không phải là tuân thủ FIPS 140, có nhiều lựa chọn thay thế
- AES-GCM-SIV
- Các cấu hình AEAD hiện đại dựa trên lõi AES
- Phần Alternatives của đặc tả so sánh từng lựa chọn thay thế với XAES-256-GCM
Vị trí trong Go và API AEAD không cần nonce
- XAES-256-GCM hướng tới một AEAD an toàn, nhàm chán, có thể tuân thủ và có khả năng tương tác
- Trường hợp sử dụng chính là loại API cấp cao muốn bổ sung vào Go
- XAES-256-GCM được thiết kế để bổ sung cho XChaCha20Poly1305 và AES-GCM-SIV, đồng thời là ứng viên triển khai cho API AEAD không cần nonce giả định
- Vì không ưu tiên thêm một cấu hình chỉ dành riêng cho Go vào thư viện chuẩn Go, nên cần ý kiến từ các maintainer của những thư viện mã hóa khác
1 bình luận
Các ý kiến trên Hacker News
Thiết kế rất khéo: vì dựa trên CMAC nên có thể dẫn xuất khóa bằng AES-CBC ngay cả khi không có primitive cấp thấp
Nhìn từ góc độ AES-CBC, có thể xem như bắt đầu với
L = AES-CBC-256ₖ(iv = 0¹²⁸, plaintext = 0¹²⁸)[:16]để tạoK1, mã hóaM1,M2để lấyKₓ, rồi dùngNₓ = N[12:]Có thể coi AES-CBC-256 chỉ trả về khối 128 bit đầu tiên của bản mã và bỏ khối padding; ngay cả khi không tắt được padding thì cũng chỉ tốn thêm 3 lần gọi AES với cùng khóa so với triển khai cấp thấp, nên không tệ
Một triển khai JS dựa trên WebCrypto API tận dụng đặc tính này có tại https://github.com/dchest/xaes; nó nhận nguyên
CryptoKeycho AES-CBC và cũng hỗ trợ các đặc tính củaCryptoKeynhư lưu vào IndexedDB vớiextractable=falseTrong đoạn mã giả đó, một nửa các con số dường như đếm số byte, nửa còn lại đếm số bit; nếu chưa biết thuật toán thì gần như không thể biết cái nào là cái nào
Ví dụ
N[:12]trông như 12 byte, nhưng0¹²⁸là 16 byte;Xlà ký tự thực tế'X', tức chuỗi bit01011000, cònLlà biến chứ không phải chuỗi bit01001100Rõ ràng các nhà toán học không thích ký pháp không mơ hồ bằng dân khoa học máy tính
0¹²⁰10000111là chuỗi bit biểu diễn các hệ số của đa thức đầu tiên theo thứ tự từ điển trong số các đa thức bất khả quy bậcbcó số hạng khác 0 ít nhất, vớiblà kích thước khối của mã khối bên dưới mà CMAC dùngKhông có dụng ý ẩn giấu gì cả
Công trình này giúp dễ dàng tránh vấn đề đó bằng cách thay đổi cả khóa lẫn nonce cho mỗi lần gọi AES-GCM
Ngoài ra, nếu có AES-GCM thì nó về cơ bản chỉ dùng AES “thông thường” vốn thường sẵn có, và tránh các cấu trúc mới phức tạp mà có thể vẫn còn điểm yếu
Chi phí phụ trội cho mỗi thông điệp là 2 bộ đệm nhỏ cần mã hóa/giải mã bằng AES “thông thường” và một nonce dài hơn 192 bit
[1]: https://frereit.de/aes_gcm/
Có vẻ loại bỏ cái bẫy của AES-GCM nguyên bản, vốn khi dùng nonce ngẫu nhiên phải thay khóa khoảng mỗi 2^32 thông điệp
Trong AES-GCM, va chạm nonce là chí mạng và ít nhất sẽ cho phép kẻ tấn công ký các thông điệp tùy ý
Không nhất thiết phải dùng nonce ngẫu nhiên, nhưng thường được khuyến nghị; khá khéo ở chỗ nó dùng hai primitive là hàm dẫn xuất khóa dựa trên bộ đếm và GCM nguyên bản để đạt tuân thủ FIPS
Với AES-GCM chuẩn, 96 bit không đủ để tránh va chạm ngẫu nhiên, nên cần dùng cách sinh nonce xác định
Ngoài ra, bất kể nonce được tạo ra thế nào, bộ đếm sẽ bị quay vòng khiến khối tiếp theo dùng cùng cặp nonce+bộ đếm với khối đầu tiên; vì vậy sau 2^32 khối thì phải đổi nonce hoặc khóa
Thật sự tuyệt vời. Ước gì vài năm trước, lần cuối tôi xây dựng hệ thống tệp mã hóa, đã có cái này
Trong triển khai hệ thống tệp quy mô lớn, va chạm nonce là mối lo lớn
2^32 nghe có vẻ lớn, nhưng với một mảng cấp PB ghi ở 100k IOPS mỗi giây và trông chờ vào tính ngẫu nhiên của bộ sinh giả ngẫu nhiên, khả năng va chạm gần như là điều chắc chắn
[1] https://en.m.wikipedia.org/wiki/CAESAR_Competition
Chẳng phải nó chỉ có nghĩa là hai khối chia sẻ cùng khóa mã hóa sao?
Nếu không biết bản rõ của bất kỳ khối nào, tôi không hiểu điều đó làm suy yếu bảo mật hệ thống thế nào
Mong cái này được dùng cho một biến thể age tuân thủ FIPS dành cho mã hóa tệp lưu trữ
Trong kiểm toán ngành ngân hàng, age bị loại cho mục đích này vì dùng ChaCha, còn phần khóa công khai X25519 của age thì được xem là ổn. Tôi nhớ X25519 đã được NIST phê duyệt tương đối gần đây
Tôi không có kinh nghiệm Go, nhưng nhìn đặc tả age thì có vẻ có thể cắm vào ngay; nếu có thời gian tôi cũng có thể thử
Tên thì có thể gọi là “cage”, với nghĩa “compliant actually good encryption”
1: https://github.com/FiloSottile/age
Với tư cách người không làm mật mã học, tôi thắc mắc tại sao lại dùng nonce 192 bit mà không phải 256 bit
Trong các ứng dụng thực tế, tôi không nghĩ các bit bổ sung đó bị xem là chi phí
Cũng có thể làm đầu vào CMAC dài hơn, nhưng như vậy phải chạy hàm khối AES-256 nhiều lần hơn và còn gặp vấn đề kiểm soát khóa phiền phức trong hàm dẫn xuất khóa CMAC
Điều này cũng tương tự lý do XChaCha20Poly1305 dùng nonce 192 bit; việc nhất quán với các AEAD nonce mở rộng chủ đạo khác cũng là một lợi điểm nhỏ
Bài nói “rủi ro va chạm 2⁻³² ở 2⁸⁰ thông điệp”, nhưng liệu việc kích thước khối AES chỉ 128 bit có gây vấn đề trước đó không?
XAES dẫn xuất một khóa lớn cho mỗi thông điệp, nên đạt được cái thường gọi là bảo đảm tốt hơn giới hạn sinh nhật
Nếu không có thêm ngữ cảnh về vì sao bạn nghĩ đó là vấn đề, thì khó trả lời chi tiết hơn thế này
“An toàn, nhàm chán, có thể tuân thủ, có thể tương tác”
Đây là kiểu công nghệ tôi thích nhất
Tốt. Việc thực sự có một cấu trúc dựa trên NIST là điều đáng mừng
Tuy vậy, hơi tiếc là phải bỏ đi nhiều tính năng như label và context, vốn là ưu điểm của hàm dẫn xuất khóa NIST
Tôi hiểu đó là đánh đổi để giảm số lần gọi AES xuống tối thiểu, nhưng đặc biệt với thông điệp dài hơn vài trăm byte, tôi có lẽ sẽ ưu tiên phân tách mật mã mạnh hơn hơn là tiết kiệm vài lần gọi AES
Cuối cùng, nonce GCM ngẫu nhiên dài hơn 96 bit chắc chắn đang bị hiểu nhầm rất nhiều và cung cấp bảo đảm tốt hơn nonce 96 bit[1]
Tất nhiên nếu có thể dẫn xuất khóa mới cho mỗi thông điệp thì cách đó rõ ràng tốt hơn
[1] [https://neilmadden.blog/2024/05/23/galois-counter-mode-and-r...](https://neilmadden.blog/2024/05/23/galois-counter-mode-and-random-nonces/])