1 điểm bởi GN⁺ 2024-06-30 | 1 bình luận | Chia sẻ qua WhatsApp
  • 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/ciphercrypto/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ₓ
  • Kₓ được tạo bằng các lần gọi AES-256ₖ và phần đầu của nonce, còn 96 bit cuối của nonce đầu vào được dùng làm Nₓ
  • 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/ciphercrypto/aes trong 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ức 0x58
    • Ngữ cảnh là 96 bit đầu của nonce đầu vào
    • Kích thước bộ đếm là 16 bit
    • Trường L tù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 CryptoKey AES-CBC 256 bit
  • Đặc tả bao gồm test vector cho hai đường mã chính
    • MSB₁(L) = 0
    • MSB₁(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
  • /11 là 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

 
GN⁺ 2024-06-30
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ạo K1, mã hóa M1, M2 để lấy Kₓ, rồi dùng Nₓ = 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 CryptoKey cho AES-CBC và cũng hỗ trợ các đặc tính của CryptoKey như lưu vào IndexedDB với extractable=false

    • Trong lĩnh vực này trông có vẻ là ký pháp chuẩn, nhưng nói thật là tôi không thích ký pháp mật mã học
      Trong đ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ưng 0¹²⁸ là 16 byte; X là ký tự thực tế 'X', tức chuỗi bit 01011000, còn L là biến chứ không phải chuỗi bit 01001100
      Rõ 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
    • Những hằng số trông rùng rợn như 0¹²⁰10000111 là 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ậc b có số hạng khác 0 ít nhất, với bkích thước khối của mã khối bên dưới mà CMAC dùng
      Không có dụng ý ẩn giấu gì cả
    • Tôi không phải chuyên gia mật mã, nhưng tóm lại tôi hiểu là AES-GCM AEAD chuẩn sẽ bị phá vỡ nghiêm trọng nếu dùng cùng một nonce hai lần cho các thông điệp khác nhau[1], và kích thước nonce trong nhiều trường hợp cũng quá nhỏ để dùng nonce ngẫu nhiên một cách an toàn
      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

    • Chính xác thì cách này ngay từ đầu làm cho nonce ngẫu nhiên trở nên an toàn
      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

    • Cuộc thi CAESAR[1] đã kết thúc năm 2019, và kết quả là có nhiều AEAD với không gian nonce đủ lớn
      [1] https://en.m.wikipedia.org/wiki/CAESAR_Competition
    • Nhưng tôi thắc mắc vì sao va chạm nonce lại là vấn đề
      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

    • “compliant actually good encryption” có lẽ cũng có thể là một cách nói nghịch hợp
    • Kiểm tra lại thì có vẻ Ed25519 đã được phê duyệt (FIPS 186-5), nhưng X25519 thì hình như chưa
    • Nhân tiện, thư viện chuẩn Go hiện chưa có triển khai XAES, chỉ có triển khai tham chiếu của C2SP
    • bge, bureaucratic good encryption
  • 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í

    • Không có chỗ để đưa 256 bit vào. 192 bit gồm 96 bit đến từ không gian nonce bên dưới, và 96 bit nằm trong khối CMAC 128 bit cùng với tiền tố cần thiết
      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?

    • Nếu đang nói về giới hạn sinh nhật trên các khối (https://sweet32.info), thì đó là giới hạn về số khối được mã hóa dưới một khóa duy nhất
      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
    • Không
      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/])