Skip to content

Seed in the skeleton of ML-DSA based on current prototyping #112891

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -314,3 +314,4 @@ Diagnostic id values for experimental APIs must not be recycled, as that could s
| __`SYSLIB5003`__ | .NET 9 | TBD | `System.Runtime.Intrinsics.Arm.Sve` is experimental |
| __`SYSLIB5004`__ | .NET 9 | TBD | `X86Base.DivRem` is experimental since performance is not as optimized as `T.DivRem` |
| __`SYSLIB5005`__ | .NET 9 | TBD | `System.Formats.Nrbf` is experimental |
| __`SYSLIB5006`__ | .NET 10 | TBD | Types for Post-Quantum Cryptography (PQC) 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 @@ -31,6 +31,9 @@ internal static class Experimentals
// System.Formats.Nrbf is experimental
internal const string NrbfDecoderDiagId = "SYSLIB5005";

// Types for Post-Quantum Cryptography (PQC) are experimental.
internal const string PostQuantumCryptographyDiagId = "SYSLIB5006";

// 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// 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
{
#if DESIGNTIMEINTERFACES
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this ifdef? This file appears to only be consumed into the S.S.Cryptography.csproj, which sets this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’ll also be consumed in Microsoft.Bcl.Cryptography as the project gets further along

internal interface IImportExportShape<TSelf> where TSelf : class, IImportExportShape<TSelf>
{
static abstract TSelf ImportSubjectPublicKeyInfo(ReadOnlySpan<byte> source);
static abstract TSelf ImportPkcs8PrivateKey(ReadOnlySpan<byte> source);
static abstract TSelf ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, ReadOnlySpan<byte> source);
static abstract TSelf ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, ReadOnlySpan<byte> source);

static abstract TSelf ImportFromPem(ReadOnlySpan<char> source);
static abstract TSelf ImportFromEncryptedPem(ReadOnlySpan<char> source, ReadOnlySpan<char> password);
static abstract TSelf ImportFromEncryptedPem(ReadOnlySpan<char> source, ReadOnlySpan<byte> passwordBytes);

byte[] ExportSubjectPublicKeyInfo();
bool TryExportSubjectPublicKeyInfo(Span<byte> destination, out int bytesWritten);
string ExportSubjectPublicKeyInfoPem();

byte[] ExportPkcs8PrivateKey();
bool TryExportPkcs8PrivateKey(Span<byte> destination, out int bytesWritten);
string ExportPkcs8PrivateKeyPem();

byte[] ExportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, PbeParameters pbeParameters);
bool TryExportEncryptedPkcs8PrivateKey(
ReadOnlySpan<char> password, PbeParameters pbeParameters, Span<byte> destination, out int bytesWritten);
string ExportEncryptedPkcs8PrivateKeyPem(ReadOnlySpan<char> password, PbeParameters pbeParameters);

byte[] ExportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, PbeParameters pbeParameters);
bool TryExportEncryptedPkcs8PrivateKey(
ReadOnlySpan<byte> passwordBytes, PbeParameters pbeParameters, Span<byte> destination, out int bytesWritten);
string ExportEncryptedPkcs8PrivateKeyPem(ReadOnlySpan<byte> passwordBytes, PbeParameters pbeParameters);
}
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ namespace System.Security.Cryptography
{
internal static partial class KeyFormatHelper
{
internal delegate TRet ReadOnlySpanFunc<TIn, TRet>(ReadOnlySpan<TIn> span);

internal static unsafe void ReadEncryptedPkcs8<TRet>(
string[] validOids,
ReadOnlySpan<byte> source,
Expand Down Expand Up @@ -272,6 +274,68 @@ internal static ArraySegment<byte> DecryptPkcs8(
out bytesRead);
}

internal static unsafe T DecryptPkcs8<T>(
ReadOnlySpan<char> password,
ReadOnlySpan<byte> source,
ReadOnlySpanFunc<byte, T> keyReader,
out int bytesRead)
{
fixed (byte* pointer = source)
{
using (PointerMemoryManager<byte> manager = new(pointer, source.Length))
{
ArraySegment<byte> decrypted = DecryptPkcs8(password, manager.Memory, out bytesRead);

try
{
AsnValueReader reader = new(decrypted, AsnEncodingRules.BER);
reader.ReadEncodedValue();
reader.ThrowIfNotEmpty();
return keyReader(decrypted);
}
catch (AsnContentException e)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
}
finally
{
CryptoPool.Return(decrypted);
}
}
}
}

internal static unsafe T DecryptPkcs8<T>(
ReadOnlySpan<byte> passwordBytes,
ReadOnlySpan<byte> source,
ReadOnlySpanFunc<byte, T> keyReader,
out int bytesRead)
{
fixed (byte* pointer = source)
{
using (PointerMemoryManager<byte> manager = new(pointer, source.Length))
{
ArraySegment<byte> decrypted = KeyFormatHelper.DecryptPkcs8(passwordBytes, manager.Memory, out bytesRead);
AsnValueReader reader = new(decrypted, AsnEncodingRules.BER);
reader.ReadEncodedValue();

try
{
reader.ThrowIfNotEmpty();
return keyReader(decrypted);
}
catch (AsnContentException e)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
}
finally
{
CryptoPool.Return(decrypted);
}
}
}
}

private static ArraySegment<byte> DecryptPkcs8(
ReadOnlySpan<char> inputPassword,
ReadOnlySpan<byte> inputPasswordBytes,
Expand Down
Loading
Loading