Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
f8e9316
Add experimental HPKE cipher suite descriptors
vcsjones Sep 5, 2026
68258cf
Complete HpkeSuite metadata and public API
vcsjones Sep 5, 2026
939cd7d
Add managed HPKE foundation
vcsjones Sep 5, 2026
e87f872
Split managed HPKE KEM adapters
vcsjones Sep 5, 2026
f57271e
Add HPKE key factory APIs
vcsjones Sep 6, 2026
fa21cda
Implement HPKE decapsulation key export
vcsjones Sep 7, 2026
d035fc0
Implement HPKE encapsulation key export
vcsjones Sep 7, 2026
f589d5a
Checkpoint HPKE Seal and managed AEAD adapters
vcsjones Sep 7, 2026
e621f1c
Add HPKE KEM encapsulation and key schedule adapters
vcsjones Sep 8, 2026
ce437ba
Implement HPKE single-shot sealing
vcsjones Sep 8, 2026
7ea28a5
Use stack buffers for fixed-size HPKE intermediates
vcsjones Sep 8, 2026
576af50
Implement HPKE single-shot opening
vcsjones Sep 8, 2026
6e25e20
Add abstract HPKE sender and recipient contexts
vcsjones Sep 8, 2026
1b0907f
Implement stateful HPKE sender creation and sealing
vcsjones Sep 8, 2026
c2ff6cd
Implement stateful HPKE recipient creation and opening
vcsjones Sep 8, 2026
cfc2d3b
Implement HPKE PSK sender and recipient modes
vcsjones Sep 8, 2026
8f4fd22
Implement P-521 DHKEM support for HPKE
vcsjones Sep 8, 2026
a798ae5
Implement HPKE context secret export
vcsjones Sep 9, 2026
4a10e1d
Implement HPKE key import APIs
vcsjones Sep 9, 2026
6f8aa63
Reject concurrent HPKE sender sealing
vcsjones Sep 9, 2026
4152869
Validate HPKE sender buffer overlaps
vcsjones Sep 9, 2026
9d8e8b6
Complete HPKE single-shot API documentation
vcsjones Sep 9, 2026
0961d98
Fix HPKE target wiring in Microsoft.Bcl.Cryptography
vcsjones Sep 9, 2026
6a80474
Validate HPKE Open and Export buffer overlaps
vcsjones Sep 9, 2026
32f473c
Refine HPKE validation order and temporary buffers
vcsjones Sep 9, 2026
850ea5f
Remove redundant HPKE key-schedule output staging
vcsjones Sep 10, 2026
b26bfdd
Stop clearing non-secret HPKE buffers
vcsjones Sep 10, 2026
f0afdec
Derive HPKE KEM suite IDs from enum values
vcsjones Sep 10, 2026
9badba1
Assert the internal HPKE export-length invariant
vcsjones Sep 10, 2026
68535fa
Reuse the KDF adapter across HPKE key operations
vcsjones Sep 10, 2026
60e3a09
Stream HPKE SHAKE inputs through public APIs
vcsjones Sep 10, 2026
52c1bc7
Merge remote-tracking branch 'ms/main' into hpke-impl
vcsjones Sep 10, 2026
6624230
Add shared HPKE contract tests
vcsjones Sep 11, 2026
eac840c
Add a representative HPKE test-vector corpus
vcsjones Sep 11, 2026
7dad5f4
Bound HPKE test exporter contexts to 1024 bytes
vcsjones Sep 11, 2026
b2b0339
Add shared HPKE sender and recipient contract tests
vcsjones Sep 11, 2026
af31501
Add shared HPKE key tests and prune legacy tests
vcsjones Sep 12, 2026
a4318a9
Add shared HPKE implementation tests
vcsjones Sep 12, 2026
c37a857
Simplify HPKE recipient documentation
vcsjones Sep 12, 2026
93cf8e5
Simplify HPKE sender and suite documentation
vcsjones Sep 12, 2026
627779e
Separate HPKE static validation from instance contracts
vcsjones Sep 12, 2026
2d362f9
Refine HPKE export tests and browser build exclusions
vcsjones Sep 12, 2026
befd9b0
Add comment clarifying why OpenCore does not have a concurrency guard
vcsjones Sep 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/project/list-of-diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,3 +333,4 @@ Diagnostic id values for experimental APIs must not be recycled, as that could s
| __`SYSLIB5006`__ | .NET 10 | TBD | Types for Post-Quantum Cryptography (PQC) are experimental. |
| __`SYSLIB5007`__ | .NET 11 | TBD | Low-level TLS engine types (`TlsContext`, `TlsSession`) in `System.Net.Security` are experimental. |
| __`SYSLIB5008`__ | .NET 11 | TBD | `SocketsHttpHandler` connection eviction control and `HttpRequestMessage.ConnectionId` APIs are experimental. |
| __`SYSLIB5009`__ | .NET 11 | TBD | Types for HPKE (Hybrid Public Key Encryption) are experimental. |
3 changes: 3 additions & 0 deletions src/libraries/Common/src/System/Experimentals.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ internal static class Experimentals
// SocketsHttpHandler connection eviction control and HttpRequestMessage.ConnectionId APIs are experimental.
internal const string SocketsHttpHandlerExperimentalDiagId = "SYSLIB5008";

// Types for HPKE (Hybrid Public Key Encryption) are experimental.
internal const string HpkeExperimentalDiagId = "SYSLIB5009";

// When adding a new diagnostic ID, add it to the table in docs\project\list-of-diagnostics.md as well.
// Keep new const identifiers above this comment.
}
Expand Down
1,517 changes: 1,517 additions & 0 deletions src/libraries/Common/src/System/Security/Cryptography/Hpke.cs

Large diffs are not rendered by default.

30 changes: 30 additions & 0 deletions src/libraries/Common/src/System/Security/Cryptography/HpkeAead.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;

namespace System.Security.Cryptography
{
/// <summary>
/// Specifies an authenticated encryption with associated data (AEAD) algorithm for an HPKE cipher suite.
/// </summary>
/// <seealso cref="HpkeSuite" />
[Experimental(Experimentals.HpkeExperimentalDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
public enum HpkeAead
{
/// <summary>
/// Indicates that authenticated encryption uses AES-GCM with a 128-bit key.
/// </summary>
AES_128_GCM = 1,

/// <summary>
/// Indicates that authenticated encryption uses AES-GCM with a 256-bit key.
/// </summary>
AES_256_GCM = 2,

/// <summary>
/// Indicates that authenticated encryption uses ChaCha20-Poly1305.
/// </summary>
ChaCha20Poly1305 = 3,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Security.Cryptography
{
internal sealed partial class HpkeAeadMetadata
{
internal HpkeAead Aead { get; }
internal int Nk { get; }
internal int Nn { get; }
internal int Nt { get; }
internal string Name { get; }

private HpkeAeadMetadata(HpkeAead aead, int nk, int nn, int nt, string name)
{
Aead = aead;
Nk = nk;
Nn = nn;
Nt = nt;
Name = name;
}

internal static HpkeAeadMetadata? Create(HpkeAead aead)
{
// https://datatracker.ietf.org/doc/html/draft-ietf-hpke-hpke-04#section-7.3
switch (aead)
{
case HpkeAead.AES_128_GCM:
return new HpkeAeadMetadata(aead, nk: 16, nn: 12, nt: 16, name: "AES-128-GCM");
case HpkeAead.AES_256_GCM:
return new HpkeAeadMetadata(aead, nk: 32, nn: 12, nt: 16, name: "AES-256-GCM");
case HpkeAead.ChaCha20Poly1305:
return new HpkeAeadMetadata(aead, nk: 32, nn: 12, nt: 16, name: "ChaCha20Poly1305");
default:
return null;
}
}
}
}
40 changes: 40 additions & 0 deletions src/libraries/Common/src/System/Security/Cryptography/HpkeKdf.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;

namespace System.Security.Cryptography
{
/// <summary>
/// Specifies a key derivation function (KDF) for an HPKE cipher suite.
/// </summary>
/// <seealso cref="HpkeSuite" />
[Experimental(Experimentals.HpkeExperimentalDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
public enum HpkeKdf
{
/// <summary>
/// Indicates that key derivation uses HKDF with SHA-256.
/// </summary>
HKDF_SHA256 = 1,

/// <summary>
/// Indicates that key derivation uses HKDF with SHA-384.
/// </summary>
HKDF_SHA384 = 2,

/// <summary>
/// Indicates that key derivation uses HKDF with SHA-512.
/// </summary>
HKDF_SHA512 = 3,

/// <summary>
/// Indicates that key derivation uses SHAKE128.
/// </summary>
SHAKE128 = 16,

/// <summary>
/// Indicates that key derivation uses SHAKE256.
/// </summary>
SHAKE256 = 17
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Security.Cryptography
{
internal sealed partial class HpkeKdfMetadata
{
internal HpkeKdf Kdf { get; }
internal int Nh { get; }
internal bool IsTwoStage { get; }
internal string Name { get; }
internal int? MaximumInfoLength { get; }
internal int? MaximumPskLength { get; }
internal int? MaximumPskIdLength { get; }

// HKDF is limited to 255 hash blocks; HPKE encodes SHAKE output lengths in two bytes.
// https://datatracker.ietf.org/doc/html/draft-ietf-hpke-hpke-04#section-4.4
internal int MaximumExportLength => IsTwoStage ? 255 * Nh : ushort.MaxValue;

private HpkeKdfMetadata(HpkeKdf kdf, int nh, bool isTwoStage, string name)
{
Kdf = kdf;
Nh = nh;
IsTwoStage = isTwoStage;
Name = name;

if (!IsTwoStage)
{
// One-stage KDFs length-prefix each of these inputs with a 16-bit length.
// HKDF input limits exceed the length representable by a span.
// https://datatracker.ietf.org/doc/html/draft-ietf-hpke-hpke-04#section-5.1
MaximumInfoLength = ushort.MaxValue;
MaximumPskLength = ushort.MaxValue;
MaximumPskIdLength = ushort.MaxValue;
}
}

internal static HpkeKdfMetadata? Create(HpkeKdf kdf)
{
switch (kdf)
{
// HKDF SHAs have limits on their info size, 2^61 - 91 and 2^125 - 155. Since this is well above
// A Span's possible length we'll treat it as unlimited.
// https://datatracker.ietf.org/doc/html/draft-ietf-hpke-hpke-04#section-7.2
case HpkeKdf.HKDF_SHA256:
return new HpkeKdfMetadata(kdf, nh: 32, isTwoStage: true, name: "HKDF-SHA256");
case HpkeKdf.HKDF_SHA384:
return new HpkeKdfMetadata(kdf, nh: 48, isTwoStage: true, name: "HKDF-SHA384");
case HpkeKdf.HKDF_SHA512:
return new HpkeKdfMetadata(kdf, nh: 64, isTwoStage: true, name: "HKDF-SHA512");
case HpkeKdf.SHAKE128:
return new HpkeKdfMetadata(kdf, nh: 32, isTwoStage: false, name: "SHAKE128");
case HpkeKdf.SHAKE256:
return new HpkeKdfMetadata(kdf, nh: 64, isTwoStage: false, name: "SHAKE256");

default:
return null;
}
}
}
}
60 changes: 60 additions & 0 deletions src/libraries/Common/src/System/Security/Cryptography/HpkeKem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;

namespace System.Security.Cryptography
{
/// <summary>
/// Specifies a key encapsulation mechanism (KEM) for an HPKE cipher suite.
/// </summary>
/// <seealso cref="HpkeSuite" />
[Experimental(Experimentals.HpkeExperimentalDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
public enum HpkeKem
{
/// <summary>
/// Indicates that key encapsulation uses DHKEM with the NIST P-256 curve and HKDF-SHA-256.
/// </summary>
DHKEM_P256_HKDF_SHA256 = 16,

/// <summary>
/// Indicates that key encapsulation uses DHKEM with the NIST P-384 curve and HKDF-SHA-384.
/// </summary>
DHKEM_P384_HKDF_SHA384 = 17,

/// <summary>
/// Indicates that key encapsulation uses DHKEM with the NIST P-521 curve and HKDF-SHA-512.
/// </summary>
DHKEM_P521_HKDF_SHA512 = 18,

/// <summary>
/// Indicates that key encapsulation uses DHKEM with X25519 and HKDF-SHA-256.
/// </summary>
DHKEM_X25519_HKDF_SHA256 = 32,

/// <summary>
/// Indicates that key encapsulation uses ML-KEM-512.
/// </summary>
MLKEM_512 = 64,

/// <summary>
/// Indicates that key encapsulation uses ML-KEM-768.
/// </summary>
MLKEM_768 = 65,

/// <summary>
/// Indicates that key encapsulation uses ML-KEM-1024.
/// </summary>
MLKEM_1024 = 66,

/// <summary>
/// Indicates that key encapsulation combines ML-KEM-768 with ECDH using the NIST P-256 curve.
/// </summary>
MLKEM768_P256 = 80,

/// <summary>
/// Indicates that key encapsulation combines ML-KEM-1024 with ECDH using the NIST P-384 curve.
/// </summary>
MLKEM1024_P384 = 81,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Security.Cryptography
{
internal sealed partial class HpkeKemMetadata
{
internal HpkeKem Kem { get; }
internal int Nsk { get; }
internal int Npk { get; }
internal int Nenc { get; }
internal int Nsecret { get; }
internal string Name { get; }

private HpkeKemMetadata(HpkeKem kem, int nsecret, int nenc, int npk, int nsk, string name)
{
Kem = kem;
Nsk = nsk;
Npk = npk;
Nenc = nenc;
Nsecret = nsecret;
Name = name;
Setup();
}

partial void Setup();

internal static HpkeKemMetadata? Create(HpkeKem kem)
{
switch (kem)
{
// https://datatracker.ietf.org/doc/html/draft-ietf-hpke-hpke-04#section-7.1
case HpkeKem.DHKEM_P256_HKDF_SHA256:
return new HpkeKemMetadata(kem, nsecret: 32, nenc: 65, npk: 65, nsk: 32, name: "DHKEM(P-256, HKDF-SHA256)");
case HpkeKem.DHKEM_P384_HKDF_SHA384:
return new HpkeKemMetadata(kem, nsecret: 48, nenc: 97, npk: 97, nsk: 48, name: "DHKEM(P-384, HKDF-SHA384)");
case HpkeKem.DHKEM_P521_HKDF_SHA512:
return new HpkeKemMetadata(kem, nsecret: 64, nenc: 133, npk: 133, nsk: 66, name: "DHKEM(P-521, HKDF-SHA512)");
case HpkeKem.DHKEM_X25519_HKDF_SHA256:
return new HpkeKemMetadata(kem, nsecret: 32, nenc: 32, npk: 32, nsk: 32, name: "DHKEM(X25519, HKDF-SHA256)");

// https://datatracker.ietf.org/doc/html/draft-ietf-hpke-pq-05#section-8.1
// Nsk is the 64-byte seed, not the expanded ML-KEM decapsulation key.
case HpkeKem.MLKEM_512:
return new HpkeKemMetadata(kem, nsecret: 32, nenc: 768, npk: 800, nsk: 64, name: "ML-KEM-512");
case HpkeKem.MLKEM_768:
return new HpkeKemMetadata(kem, nsecret: 32, nenc: 1088, npk: 1184, nsk: 64, name: "ML-KEM-768");
case HpkeKem.MLKEM_1024:
return new HpkeKemMetadata(kem, nsecret: 32, nenc: 1568, npk: 1568, nsk: 64, name: "ML-KEM-1024");

// https://datatracker.ietf.org/doc/html/draft-ietf-hpke-pq-05#section-8.2
// Nsk is the 32-byte seed used to derive both component key pairs.
case HpkeKem.MLKEM768_P256:
return new HpkeKemMetadata(kem, nsecret: 32, nenc: 1153, npk: 1249, nsk: 32, name: "MLKEM768-P256");
case HpkeKem.MLKEM1024_P384:
return new HpkeKemMetadata(kem, nsecret: 32, nenc: 1665, npk: 1665, nsk: 32, name: "MLKEM1024-P384");

default:
return null;
}
}
}
}
Loading
Loading