Trọng tâm chính của .NET Cryptography trong .NET 10 là bổ sung hỗ trợ cho Mật mã Hậu Lượng Tử (Post-Quantum Cryptography – PQC). Công việc về mật mã thường rơi vào dạng “quan trọng, nhưng không thực sự đáng để bàn luận”, nhưng vì có khá nhiều buzz trong năm nay xoay quanh PQC, đây có vẻ là thời điểm thích hợp để nói về PQC trong .NET.
Đầu tiên, một lưu ý về thuật ngữ. “Hậu” trong “Hậu Lượng Tử” không có nghĩa là “máy tính lượng tử đã xuất hiện”, mà chủ yếu có nghĩa là “các thuật toán sẽ không bị xâm phạm bởi sự tồn tại của một máy tính lượng tử đủ mạnh”. Thậm chí điều đó còn hơi quá, bởi vì một “máy tính lượng tử có liên quan đến mật mã” (CRQC) sẽ không có tác động đáng kể đến AES, họ các thuật toán băm SHA-2, hay họ các thuật toán băm SHA-3 như nó sẽ tác động đến ECC (EC-DSA, EC-Diffie-Hellman, v.v.) hay RSA. Vì vậy, chủ yếu, “PQC” chỉ có nghĩa là “một số thuật toán mới chúng tôi đang thêm vào vì máy tính lượng tử là mối đe dọa đối với RSA và ECC.”
Các chiến lược như “Thu hoạch ngay, giải mã sau” có nghĩa là quá trình chuyển đổi từ mật mã bất đối xứng “truyền thống” sang PQC nên được thực hiện trước khi CRQC tồn tại. Tùy thuộc vào nhà tương lai học bạn hỏi (và dữ liệu của bạn quan trọng đến mức nào), thời điểm để chuyển đổi dao động từ “nhiều năm trước” đến “có thể không bao giờ”. Chúng tôi không có cỗ máy thời gian, vì vậy chúng tôi không thể giải quyết vấn đề cho “nhiều năm trước”, nhưng chúng tôi đã đạt được “ngay trong bản phát hành đầu tiên sau khi các đặc tả đầu tiên được tiêu chuẩn hóa”, vì vậy “bây giờ” là tốt nhất có thể!
Trong .NET 10, chúng tôi tập trung vào 4 thuật toán PQC:
| Thuật toán | Loại | Đặc tả | Lớp .NET |
|---|---|---|---|
| ML-KEM | Key Encapsulation | NIST FIPS 203 | MLKem |
| ML-DSA | Chữ ký | NIST FIPS 204 | MLDsa |
| SLH-DSA | Chữ ký | NIST FIPS 205 | SlhDsa |
| Composite ML-DSA | Chữ ký | IETF Draft “Composite ML-DSA for use in X.509 Public Key Infrastructure“ | CompositeMLDsa |
ML-DSA, SLH-DSA và Composite ML-DSA đều là các sản phẩm thay thế cho chữ ký bằng RSA và EC-DSA. ML-KEM thay thế về mặt logic cả “RSA Key Transport” và “EC-Diffie-Hellman Key Agreement”, mặc dù cách sử dụng thực tế không phải là sự thay thế trực tiếp cho bất kỳ cái nào trong số chúng. Không có sự thay thế trực tiếp cho “Mã hóa dữ liệu” RSA, nhưng đó là vì đó không phải là cách sử dụng RSA được khuyến nghị ngay từ đầu.
Mục lục
Cách Chúng Ta Vẫn Luôn Làm
Nói chung, khi bạn đang làm “một việc gì đó” mà “giống như một việc khác”, bạn nên làm theo cùng một cách. Trong .NET Cryptography, chúng tôi có một mẫu thiết kế đã được thiết lập cho các khóa của thuật toán bất đối xứng:
- Các loại thuật toán kế thừa từ
AsymmetricAlgorithm - Các loại triển khai kế thừa từ các loại thuật toán
- Các loại thuật toán có phương thức
Create()tĩnh hoạt động bất kể bạn đang ở hệ điều hành nào (trừ khi thuật toán không được hỗ trợ trên hệ điều hành của bạn). - Các khóa sau đó có thể được nhập, tạo một cách tường minh, hoặc tạo ngầm định.
namespace System.Security.Cryptography;
public partial class AsymmetricAlgorithm : IDisposable { }
public partial class RSA : AsymmetricAlgorithm
{
public static RSA Create();
}
public partial class DSA : AsymmetricAlgorithm
{
public static DSA Create();
}
public partial class RSACng : RSA { }
public partial class RSAOpenSsl : RSA { }
// v.v.
Nó Bắt Đầu Sai Ở Đâu Đó
Khi chúng tôi bắt đầu dự án PQC, câu trả lời hiển nhiên là chúng tôi nên tiếp tục mở rộng AsymmetricAlgorithm, nhưng có một gợi ý rằng đó là một câu trả lời tồi… và đó là thuộc tính KeySize trên AsymmetricAlgorithm:
public partial class AsymmetricAlgorithm
{
public virtual int KeySize { get; set; }
}
Thuộc tính này được giới thiệu khi .NET chỉ hỗ trợ RSA và DSA, và nó có ý nghĩa: khi tạo khóa RSA hoặc khóa DSA, tham số duy nhất là kích thước modulus RSA (n) hoặc kích thước prime modulus DSA (p). Các giá trị KeySize của RSA và các giá trị KeySize của DSA không nên được so sánh giữa các thuật toán, nhưng chúng là một thuộc tính của bất kỳ khóa nào.
Sau đó chúng tôi giới thiệu EC-DSA và EC-DiffieHellman. Các khóa ECC có một giá trị số nguyên đơn giản làm khóa riêng, một số trong khoảng [1, p), trong đó p là modulus nguyên tố cho “đường cong”. Vì vậy, mọi người đồng ý rằng “kích thước khóa” của khóa ECC là “số bit cần thiết để biểu diễn p“. .NET tại thời điểm đó chỉ hỗ trợ 3 đường cong: NIST P-256, NIST P-384 và NIST P-521. Số sau dấu “P-” là “cần bao nhiêu bit để biểu diễn p“, vì vậy chúng tôi có một câu trả lời hợp lý cho thuộc tính này.
Sau đó Windows thêm hỗ trợ cho nhiều đường cong elliptic hơn, vì vậy .NET cũng thêm hỗ trợ cho nhiều đường cong elliptic hơn. Brainpool’s brainpool384r1 và NIST’s P-384 đều báo cáo 384 từ getter, nhưng setter nên làm gì? Câu trả lời tốt nhất chúng tôi đưa ra là “setter vẫn chọn từ 3 tùy chọn trước đây, và chúng tôi cần một cách mới để kiểm tra hoặc chỉ định đường cong.”
Điều đó về cơ bản giống như nghe thấy tiếng kẽo kẹt của gỗ vào một ngày yên tĩnh khi đang đứng cạnh một con đập.
Vì vậy, bây giờ chúng tôi đang thêm nhiều thuật toán mới hơn. Với khóa ML-DSA-65, chúng ta nên báo cáo giá trị KeySize là gì? “65” là một câu trả lời hiển nhiên, nhưng nó khá vô nghĩa (cái tên đó chỉ có nghĩa là “bộ tham số” này sử dụng ma trận 6×5). Khóa công khai thô cho ML-DSA-65 là 1952 byte, vậy có thể là 1952? Chà, đây là mật mã, vì vậy nó nên được tính bằng bit: 15616?
Đây là khởi đầu của một hành trình nơi chúng tôi quyết định “chia tay” với AsymmetricAlgorithm.
… Còn Gì Nữa Không?
Cách đây rất lâu, tôi đã thấy một tấm áp phích có nội dung “Thay đổi thật khủng khiếp… trừ khi nó tuyệt vời!”. Dựa trên nơi nó được đặt, tôi nghĩ đối tượng mục tiêu là các nhà thiết kế UX và tấm áp phích muốn nói “người dùng ghét khi bạn di chuyển các nút xung quanh, vì vậy nếu bạn định di chuyển nó, tốt hơn bạn nên có một lý do tuyệt vời”. Bất kể đối tượng nào, thông điệp đã gây ấn tượng với tôi trong suốt những năm qua, và vì vậy tôi biết rằng chúng tôi cần một thứ gì đó khác ngoài “AsymmetricAlgorithm, nhưng không có thuộc tính KeySize.”
Những phần không tốt:
- Việc sử dụng nhiều
public virtualcó nghĩa là chúng tôi phải lặp lại trạng thái và xác thực đối số trong mọi kiểu dẫn xuất. Và đôi khi chúng tôi đã không lặp lại một cách chính xác. - Bạn phải tạo một phiên bản để hỏi về khả năng của nó (ví dụ:
public virtual LegalKeySizes[] { get; }) Create()không tạo khóa, trong trường hợp bạn import. Kết quả là, việc tạo khóa xảy ra khi khóa lần đầu tiên được cần, gây ra một số bất ngờ về hiệu suất.Dispose()không phải lúc nào cũng có nghĩa là “đối tượng không thể sử dụng được”, thường nó có nghĩa là “Tôi đã từ bỏ khóa này, nhưng tôi có thể tạo một khóa khác!”- Bạn không thể thực sự sử dụng nó nguyên trạng. Nếu bạn chấp nhận một cái, bạn cần ép kiểu nó thành một loại thuật toán.
KeySizedường như không có ý nghĩa đối với các thuật toán mới này.KeyExchangeAlgorithm,SignatureAlgorithm,ToXmlString(bool),FromXmlString(string)là những sự xâm nhập từSignedXmlvàEncryptedXml, chúng ở sai tầng.ExportParameters(bool)gây khó khăn cho việc viết một trình phân tích luồng nhất quán để biết khi nào bạn có dữ liệu khóa riêng hoặc dữ liệu khóa công khai.
Những phần tốt:
- Có một cách nhất quán để import/export khóa.
Rõ ràng, một khi chúng tôi bắt đầu lập danh sách “chia tay”, nó khá rõ ràng. Xin lỗi, AsymmetricAlgorithm, không phải bạn, mà là tôi (PS: hoàn toàn là tại bạn).
Các Mục Tiêu Của Thiết Kế Mới
- Các phiên bản đại diện cho một khóa/cặp khóa.
- Một khi đã dispose, luôn được dispose.
- Không có “lớp cơ sở chung” khi hai thứ không thực sự có điểm chung.
- Giảm thiểu mã cho các kiểu dẫn xuất, để giảm thiểu khả năng xảy ra sai sót.
- Sử dụng thuật ngữ hiện có khi nó có cùng ý nghĩa.
- Sử dụng thuật ngữ mới khi thuật ngữ hiện tại có nghĩa khác.
- Thiết kế cho Span
Thiết Kế Mới
Đây là cái nhìn về lớp cho ML-DSA, với hầu hết các overload được loại bỏ cho ngắn gọn:
namespace System.Security.Cryptography;
public abstract partial class MLDsa : System.IDisposable
{
public static bool IsSupported { get; }
protected MLDsa(MLDsaAlgorithm algorithm);
public MLDsaAlgorithm Algorithm { get; }
public void Dispose();
protected virtual void Dispose(bool disposing);
// Tạo khóa mới
public static MLDsa GenerateKey(MLDsaAlgorithm algorithm);
// Import định dạng khóa dành riêng cho thuật toán
public static MLDsa ImportMLDsaPublicKey(MLDsaAlgorithm algorithm, ReadOnlySpan<byte> source);
public static MLDsa ImportMLDsaPrivateKey(MLDsaAlgorithm algorithm, ReadOnlySpan<byte> source);
public static MLDsa ImportMLDsaPrivateSeed(MLDsaAlgorithm algorithm, ReadOnlySpan<byte> source);
// Import định dạng chứa khóa tiêu chuẩn
public static MLDsa ImportSubjectPublicKeyInfo(ReadOnlySpan<byte> source);
public static MLDsa ImportPkcs8PrivateKey(ReadOnlySpan<byte> source);
public static MLDsa ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, ReadOnlySpan<byte> source);
public static MLDsa ImportFromPem(ReadOnlySpan<char> source);
public static MLDsa ImportFromEncryptedPem(ReadOnlySpan<char> source, ReadOnlySpan<char> password);
// Export định dạng khóa dành riêng cho thuật toán
public void ExportMLDsaPublicKey(Span<byte> destination);
public void ExportMLDsaPrivateKey(Span<byte> destination);
public void ExportMLDsaPrivateSeed(Span<byte> destination);
// Export định dạng chứa khóa tiêu chuẩn
public byte[] ExportSubjectPublicKeyInfo();
public byte[] ExportPkcs8PrivateKey();
public byte[] ExportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, PbeParameters pbeParameters);
public string ExportSubjectPublicKeyInfoPem();
public string ExportEncryptedPkcs8PrivateKeyPem(ReadOnlySpan<char> password, PbeParameters pbeParameters);
// Các thao tác thuật toán có thể thực hiện
public void SignData(ReadOnlySpan<byte> data, Span<byte> destination, ReadOnlySpan<byte> context = default);
public void SignMu(ReadOnlySpan<byte> externalMu, Span<byte> destination);
public void SignPreHash(ReadOnlySpan<byte> hash, Span<byte> destination, string hashAlgorithmOid, ReadOnlySpan<byte> context = default);
public bool VerifyData(ReadOnlySpan<byte> data, ReadOnlySpan<byte> signature, ReadOnlySpan<byte> context = default);
public bool VerifyMu(ReadOnlySpan<byte> externalMu, ReadOnlySpan<byte> signature);
public bool VerifyPreHash(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> signature, string hashAlgorithmOid, ReadOnlySpan<byte> context = default);
// Export khóa, dành riêng cho triển khai.
protected abstract void ExportMLDsaPrivateSeedCore(Span<byte> destination);
protected abstract void ExportMLDsaPublicKeyCore(Span<byte> destination);
protected abstract void ExportMLDsaPrivateKeyCore(Span<byte> destination);
protected abstract bool TryExportPkcs8PrivateKeyCore(Span<byte> destination, out int bytesWritten);
// Các thao tác thuật toán, dành riêng cho triển khai.
protected abstract void SignDataCore(ReadOnlySpan<byte> data, ReadOnlySpan<byte> context, Span<byte> destination);
protected abstract void SignMuCore(ReadOnlySpan<byte> externalMu, Span<byte> destination);
protected abstract void SignPreHashCore(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> context, string hashAlgorithmOid, Span<byte> destination);
protected abstract bool VerifyDataCore(ReadOnlySpan<byte> data, ReadOnlySpan<byte> context, ReadOnlySpan<byte> signature);
protected abstract bool VerifyMuCore(ReadOnlySpan<byte> externalMu, ReadOnlySpan<byte> signature);
protected abstract bool VerifyPreHashCore(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> context, string hashAlgorithmOid, ReadOnlySpan<byte> signature);
}
Hãy xem nó đáp ứng các mục tiêu của chúng tôi như thế nào:
- ✅ Tất cả các phương thức instance đều về “khóa/cặp khóa”, không có cái nào về “thuật toán”. Việc tạo và nhập khóa là các phương thức
static. - ✅ Bạn không thể biết từ hình dạng lớp, nhưng lớp cơ sở theo dõi việc dispose và sẽ không gọi bất kỳ thành viên ảo nào khi khóa đã được dispose.
- ✅ Hóa ra ML-DSA và ML-KEM có rất ít điểm chung. Và trong khi ML-DSA và Composite ML-DSA nghe có vẻ giống nhau, chúng khác nhau ở những điểm quan trọng. Vì vậy, tất cả các thuật toán mới trực tiếp mở rộng
object. - ✅ Lớp sử dụng rộng rãi Mẫu Phương thức Khuôn mẫu (Template Method Pattern). Tất cả xác thực đối số và trạng thái được thực hiện trong các phương thức
publiccủa lớp cơ sở, các phương thứcprotected abstractchỉ cần thực hiện bước cuối cùng. - ✅
RSAvàECDsađều có phương thức tênSignDatanhận toàn bộ dữ liệu cần ký và tạo ra chữ ký.MLDsaphù hợp với điều đó. Phiên bản củaMLDsacó thêm tham sốcontexttừ đặc tả, nhưng điều đó không thay đổi cơ bản thuật ngữ. - ✅
RSAvàECDsađều có phương thức tênSignHash, nó tạo ra chữ ký tương thích vớiSignData. Biến thểHashML-DSAcủa ML-DSA tạo ra chữ ký cố ý không tương thích, vì vậy thay vìSignHash, nó được gọi làSignPreHash.SignMugần vớiSignHashhơn, nhưng vẫn khác. - ✅ Không có phương thức
abstracthoặcvirtualnào hoạt động trên mảng. Lớp cơ sởMLDsacó nhiều overload chấp nhận (hoặc trả về) mảng, nhưng đó chỉ là để thuận tiện cho người gọi.
Một điều có thể nổi bật là sự phổ biến của các phương thức void ghi vào span. Đối với ML-DSA, ML-KEM và SLH-DSA, tất cả các thao tác thuật toán đều có phản hồi kích thước cố định; điều đó có nghĩa là có một lý do chính đáng cho việc “nếu bạn truyền một bộ đệm không đúng kích thước, bạn đang sai”. Vậy làm thế nào để bạn biết cách đúng? Rõ ràng, chỉ cần mở FIPS 204, nhảy xuống phần 4 (Bộ tham số), và đọc Bảng 2 (Kích thước (tính bằng byte) của khóa và chữ ký của ML-DSA)… Chỉ đùa thôi.
Dữ liệu từ bảng này (cũng như dữ liệu khác) nằm trong thuộc tính Algorithm:
namespace System.Security.Cryptography;
public sealed partial class MLDsaAlgorithm : IEquatable<MLDsaAlgorithm>
{
public static MLDsaAlgorithm MLDsa44 { get; }
public static MLDsaAlgorithm MLDsa65 { get; }
public static MLDsaAlgorithm MLDsa87 { get; }
public string Name { get; }
public int MuSizeInBytes { get; }
public int PrivateKeySizeInBytes { get; }
public int PrivateSeedSizeInBytes { get; }
public int PublicKeySizeInBytes { get; }
public int SignatureSizeInBytes { get; }
}
Thỉnh thoảng, ai đó muốn/cần tương tác với nhà cung cấp cơ bản. Vì vậy, chúng tôi vẫn có các kiểu dẫn xuất Cng và OpenSsl, nhưng chúng nhỏ hơn nhiều, nhiều.
namespace System.Security.Cryptography;
public sealed partial class MLDsaCng : MLDsa
{
public MLDsaCng(CngKey key) : base (GetMLDsaAlgorithm(key)) { }
public CngKey GetKey();
protected override void Dispose(bool disposing);
protected override void ExportMLDsaPrivateKeyCore(Span<byte> destination);
// ...
}
public sealed partial class MLDsaOpenSsl : MLDsa
{
public MLDsaOpenSsl(SafeEvpPKeyHandle pkeyHandle) : base (GetMLDsaAlgorithm(pkeyHandle)) { }
public SafeEvpPKeyHandle DuplicateKeyHandle();
// ...
}
Và đó là thay đổi cuối cùng của chúng tôi so với các kiểu hiện có: không có “import khóa vào MLDsaCng”, hay “tạo khóa với MLDsaCng”. Tại sao? Lý do chính là bạn không nên quan tâm. MLDsaCng không hoạt động trên Linux, MLDsaOpenSsl không hoạt động trên Windows; vì vậy nếu bạn đang viết một ứng dụng hoặc thư viện chạy ở mọi nơi, bạn nên chỉ sử dụng lớp cơ sở.
Điều Này Có Giúp Tôi Là Người Triển Khai Không?
OK, khá bất thường khi ai đó ngoài chúng tôi mở rộng các kiểu khóa mật mã, nhưng nó vẫn xảy ra. Câu trả lời là, một cách nhấn mạnh, “có!”
Đối với RSAOpenSsl (và lớp ẩn được sử dụng bởi RSA.Create() trên Linux), việc ký trông như thế này:
public override bool TrySignHash(
ReadOnlySpan<byte> hash,
Span<byte> destination,
HashAlgorithmName hashAlgorithm,
RSASignaturePadding padding,
out int bytesWritten)
{
ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm));
ArgumentNullException.ThrowIfNull(padding);
ThrowIfDisposed();
// ... xác thực thêm, sau đó gọi provider
}
Đây là mã tương tự cho MLDsaOpenSsl:
protected override void SignDataCore(ReadOnlySpan<byte> data, ReadOnlySpan<byte> context, Span<byte> destination) =>
Interop.Crypto.MLDsaSignPure(_key, data, context, destination);
Điều duy nhất MLDsaOpenSsl.SignDataCore cần làm là gọi OpenSSL, mọi thứ khác đã được thực hiện trong lớp cơ sở.
Đối với RSA, mọi kiểu dẫn xuất đều được kiểm tra độc lập về xác thực đối số, trạng thái dispose, thứ tự xác thực đối số vs trạng thái dispose, bộ đệm quá nhỏ – chỉ để đảm bảo chúng nhất quán. Đối với MLDsa, không thể có sự không nhất quán, vì vậy chúng tôi chỉ cần kiểm tra lớp cơ sở.
Nhìn chung, ít mã hơn để viết, do đó ít lỗi hơn, và bằng cách loại bỏ các loại kiểm tra, nó làm cho giai đoạn kiểm thử tổng thể nhanh hơn (mà không mất đi độ phủ). Nghe có vẻ như một chiến thắng.
Vấn Đề Với [Experimental]?
Trong .NET Cryptography, chúng tôi tuân thủ nguyên tắc “quy tắc-của-hai” đã được sửa đổi: chúng tôi không (thường) thêm thuật toán trừ khi hai (hoặc nhiều hơn) hệ điều hành được hỗ trợ của chúng tôi cung cấp nó. Vì Windows vẫn chưa (tính đến thời điểm viết bài) thêm hỗ trợ cho SLH-DSA, và cả Windows và OpenSSL đều chưa thêm Composite ML-DSA như một thuật toán hạng nhất, chúng tôi đã quyết định phát hành các lớp SlhDsa và CompositeMLDsa với [Experimental] trên chính các lớp đó.
Đối với MLKem và MLDsa, chúng tôi đã loại bỏ [Experimental] khỏi các lớp, nhưng nó vẫn còn trên một vài phương thức:
[Experimental("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public byte[] ExportPkcs8PrivateKey();
[Experimental("SYSLIB5006", UrlFormat="https://aka.ms/dotnet-warnings/{0}")]
public byte[] ExportSubjectPublicKeyInfo();
// ...
Tất cả các phần của lớp đến từ FIPS 203 đều nằm trong đặc tả đã được công bố, đã được viết cho cả Windows và OpenSSL, và chúng tôi đã tích hợp với chúng. Do đó, không còn bất ngờ nào ở đó, và không cần [Experimental]. Tuy nhiên, các định dạng PKCS#8 PrivateKeyInfo và X.509 SubjectPublicKeyInfo của khóa đến từ một đặc tả khác (“draft-ietf-lamps-kyber-certificates”). Khi ngày cuối cùng cho các thay đổi đến, đặc tả vẫn chưa được công bố.
.NET Sử Dụng Các Thuật Toán Này Ở Đâu?
Các thuật toán mới này có thể được sử dụng ở một số nơi trong không gian tên System.Security.Cryptography:
CertificateRequest:MLDsa,SlhDsa,CompositeMLDsaSignedCms‘CmsSigner:MLDsa,SlhDsa- COSE’s
CoseSigner:MLDsa
Hầu hết các API .NET chấp nhận X509Certificate2 (hoặc thậm chí X509Certificate) đều quan tâm đến việc ký, vì vậy các khóa chủ thể ML-KEM bên trong chứng chỉ không thể được sử dụng với những thứ như TLS. Tuy nhiên, các chứng chỉ với khóa công khai ML-DSA thường sẽ hoạt động. Hai nơi nổi bật nhất là SslStreamCertificateContext (và SslStream trực tiếp) và SignedCms‘ CmsSigner.
Để SslStream hoạt động với chứng chỉ ML-DSA hoặc SLH-DSA, bạn cần sử dụng TLS 1.3 (hoặc phiên bản mới hơn trong tương lai), và hệ điều hành cần hỗ trợ nó, và phía bên kia của kết nối cũng vậy.
Tuyệt Vời, Làm Thế Nào Để Bắt Đầu?
- Tải phiên bản .NET 10
- Đảm bảo bạn đang ở trên máy tính mà hệ điều hành hỗ trợ các thuật toán. Chúng tôi sẽ cho bạn biết qua
System.Security.Cryptography.MLDsa.IsSupported(hoặc tương tự choMLKem,SlhDsa, v.v.).- Đối với Linux, bạn cần OpenSSL 3.5 hoặc mới hơn
- Hỗ trợ Windows đã đến trong tháng này, vì vậy nếu bạn đang chạy Windows 11 và đã khởi động lại cho Patch Tuesday, bạn sẽ sẵn sàng.
- Nếu bạn đang targeting .NET Standard 2.0, bạn sẽ cần tham chiếu phiên bản 10.0 của Microsoft.Bcl.Cryptography
using System.Security.Cryptography;
if (!MLKem.IsSupported)
{
Console.WriteLine("ML-KEM không được hỗ trợ :(");
return;
}
MLKemAlgorithm alg = MLKemAlgorithm.MLKem768;
using (MLKem privateKey = MLKem.GenerateKey(alg))
using (MLKem publicKey = MLKem.ImportEncapsulationKey(alg, privateKey.ExportEncapsulationKey()))
{
publicKey.Encapsulate(out byte[] ciphertext, out byte[] sharedSecret1);
byte[] sharedSecret2 = privateKey.Decapsulate(ciphertext);
if (sharedSecret1.AsSpan().SequenceEqual(sharedSecret2))
{
Console.WriteLine($"Cùng kết quả, toán học thật tuyệt! {Convert.ToHexString(sharedSecret1)}");
}
else
{
Console.WriteLine("Bạn vừa gặp trường hợp 1 trong 2^165 thất bại. Chắc có giải thưởng cho điều đó.");
}
}
Nếu bạn gặp bất kỳ bất ngờ nào, hãy cho chúng tôi biết!
Lời Cảm Ơn Đặc Biệt
Như người ta thường nói, cần cả một ngôi làng (để nuôi dạy một đứa trẻ). Chúng tôi sẽ không thể đi xa như vậy, với chất lượng như vậy, nếu không có sự giúp đỡ.
- GitHub Security Services: Tham gia vào hành trình thiết kế lớp, thực hiện tất cả công việc cho ML-KEM, và thiết lập một chân CI riêng để dự án có khởi đầu tốt.
- OpenSSL, Debian (13), CentOS (10): Thời điểm phát hành OpenSSL 3.5, và tốc độ Debian và CentOS áp dụng nó, có nghĩa là chúng tôi đã có độ phủ CI ổn định sớm hơn nhiều so với dự kiến.
- Windows Cryptography: Vì đã đưa PQC vào Windows Insider builds, và phản hồi nhanh chóng với phản hồi của chúng tôi.
- IETF LAMPS-WG: Vì đã nhanh chóng trả lời các câu hỏi và phản hồi của chúng tôi cho dự án chữ ký composite.



