Skip to content
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
82 changes: 41 additions & 41 deletions src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs
Original file line number Diff line number Diff line change
Expand Up @@ -616,8 +616,8 @@ public bool TryExportPkcs8PrivateKey(Span<byte> destination, out int bytesWritte
3 + // Version Integer
2 + // AlgorithmIdentifier Sequence
3 + // AlgorithmIdentifier OID value, undervalued to be safe
2 + // Secret key Octet String prefix, undervalued to be safe
Algorithm.SecretKeySizeInBytes;
2 + // Private key Octet String prefix, undervalued to be safe
Algorithm.PrivateKeySizeInBytes;

if (destination.Length < MinimumPossiblePkcs8SlhDsaKey)
{
Expand Down Expand Up @@ -650,19 +650,19 @@ public bool TryExportPkcs8PrivateKey(Span<byte> destination, out int bytesWritte
/// </exception>
protected virtual bool TryExportPkcs8PrivateKeyCore(Span<byte> destination, out int bytesWritten)
{
// Secret key size for SLH-DSA is at most 128 bytes so we can stack allocate it.
int secretKeySizeInBytes = Algorithm.SecretKeySizeInBytes;
Debug.Assert(secretKeySizeInBytes is <= 128);
Span<byte> secretKey = (stackalloc byte[128])[..secretKeySizeInBytes];
// Private key size for SLH-DSA is at most 128 bytes so we can stack allocate it.
int privateKeySizeInBytes = Algorithm.PrivateKeySizeInBytes;
Debug.Assert(privateKeySizeInBytes is <= 128);
Span<byte> privateKey = (stackalloc byte[128])[..privateKeySizeInBytes];

try
{
ExportSlhDsaSecretKey(secretKey);
ExportSlhDsaPrivateKey(privateKey);

// The ASN.1 overhead of a PrivateKeyInfo encoding a private key is 22 bytes.
// Round it off to 32. This checked operation should never throw because the inputs are not
// user provided.
int capacity = checked(32 + secretKeySizeInBytes);
int capacity = checked(32 + privateKeySizeInBytes);
AsnWriter writer = new AsnWriter(AsnEncodingRules.DER, capacity);

using (writer.PushSequence())
Expand All @@ -674,15 +674,15 @@ protected virtual bool TryExportPkcs8PrivateKeyCore(Span<byte> destination, out
writer.WriteObjectIdentifier(Algorithm.Oid);
}

writer.WriteOctetString(secretKey);
writer.WriteOctetString(privateKey);
}

Debug.Assert(writer.GetEncodedLength() <= capacity);
return writer.TryEncode(destination, out bytesWritten);
}
finally
{
CryptographicOperations.ZeroMemory(secretKey);
CryptographicOperations.ZeroMemory(privateKey);
}
}

Expand Down Expand Up @@ -1108,55 +1108,55 @@ public byte[] ExportSlhDsaPublicKey()
}

/// <summary>
/// Exports the current key in the FIPS 205 secret key format.
/// Exports the current key in the FIPS 205 private key format.
/// </summary>
/// <param name="destination">
/// The buffer to receive the secret key. Its length must be exactly
/// <see cref="SlhDsaAlgorithm.SecretKeySizeInBytes"/>.
/// The buffer to receive the private key. Its length must be exactly
/// <see cref="SlhDsaAlgorithm.PrivateKeySizeInBytes"/>.
/// </param>
/// <exception cref="ArgumentException">
/// <paramref name="destination"/> is the incorrect length to receive the secret key.
/// <paramref name="destination"/> is the incorrect length to receive the private key.
/// </exception>
/// <exception cref="CryptographicException">
/// <para>The current instance cannot export a secret key.</para>
/// <para>The current instance cannot export a private key.</para>
/// <para>-or-</para>
/// <para>An error occurred while exporting the key.</para>
/// </exception>
/// <exception cref="ObjectDisposedException">The object has already been disposed.</exception>
public void ExportSlhDsaSecretKey(Span<byte> destination)
public void ExportSlhDsaPrivateKey(Span<byte> destination)
{
int secretKeySizeInBytes = Algorithm.SecretKeySizeInBytes;
int privateKeySizeInBytes = Algorithm.PrivateKeySizeInBytes;

if (destination.Length != secretKeySizeInBytes)
if (destination.Length != privateKeySizeInBytes)
{
throw new ArgumentException(
SR.Format(SR.Argument_DestinationImprecise, secretKeySizeInBytes),
SR.Format(SR.Argument_DestinationImprecise, privateKeySizeInBytes),
nameof(destination));
}

ThrowIfDisposed();

ExportSlhDsaSecretKeyCore(destination);
ExportSlhDsaPrivateKeyCore(destination);
}

/// <summary>
/// Exports the current key in the FIPS 205 secret key format.
/// Exports the current key in the FIPS 205 private key format.
/// </summary>
/// <returns>
/// The FIPS 205 secret key.
/// The FIPS 205 private key.
/// </returns>
/// <exception cref="CryptographicException">
/// <para>The current instance cannot export a secret key.</para>
/// <para>The current instance cannot export a private key.</para>
/// <para>-or-</para>
/// <para>An error occurred while exporting the key.</para>
/// </exception>
/// <exception cref="ObjectDisposedException">The object has already been disposed.</exception>
public byte[] ExportSlhDsaSecretKey()
public byte[] ExportSlhDsaPrivateKey()
{
ThrowIfDisposed();

byte[] destination = new byte[Algorithm.SecretKeySizeInBytes];
ExportSlhDsaSecretKeyCore(destination);
byte[] destination = new byte[Algorithm.PrivateKeySizeInBytes];
ExportSlhDsaPrivateKeyCore(destination);
return destination;
}

Expand Down Expand Up @@ -1293,12 +1293,12 @@ public static SlhDsa ImportPkcs8PrivateKey(ReadOnlySpan<byte> source)
SlhDsaAlgorithm info = GetAlgorithmIdentifier(in algId);
ReadOnlySpan<byte> privateKey = key.Span;

if (privateKey.Length != info.SecretKeySizeInBytes)
if (privateKey.Length != info.PrivateKeySizeInBytes)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
}

ret = ImportSlhDsaSecretKey(info, key.Span);
ret = ImportSlhDsaPrivateKey(info, key.Span);
},
out int read,
out SlhDsa slhDsa);
Expand Down Expand Up @@ -1704,13 +1704,13 @@ public static SlhDsa ImportSlhDsaPublicKey(SlhDsaAlgorithm algorithm, byte[] sou
}

/// <summary>
/// Imports an SLH-DSA private key in the FIPS 205 secret key format.
/// Imports an SLH-DSA private key in the FIPS 205 private key format.
/// </summary>
/// <param name="algorithm">
/// The specific SLH-DSA algorithm for this key.
/// </param>
/// <param name="source">
/// The bytes of a FIPS 205 secret key.
/// The bytes of a FIPS 205 private key.
/// </param>
/// <returns>
/// The imported key.
Expand All @@ -1728,29 +1728,29 @@ public static SlhDsa ImportSlhDsaPublicKey(SlhDsaAlgorithm algorithm, byte[] sou
/// The platform does not support SLH-DSA. Callers can use the <see cref="IsSupported" /> property
/// to determine if the platform supports SLH-DSA.
/// </exception>
public static SlhDsa ImportSlhDsaSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySpan<byte> source)
public static SlhDsa ImportSlhDsaPrivateKey(SlhDsaAlgorithm algorithm, ReadOnlySpan<byte> source)
{
ArgumentNullException.ThrowIfNull(algorithm);

if (source.Length != algorithm.SecretKeySizeInBytes)
if (source.Length != algorithm.PrivateKeySizeInBytes)
{
throw new ArgumentException(SR.Argument_SecretKeyWrongSizeForAlgorithm, nameof(source));
throw new ArgumentException(SR.Argument_PrivateKeyWrongSizeForAlgorithm, nameof(source));
}

ThrowIfNotSupported();

return SlhDsaImplementation.ImportSecretKey(algorithm, source);
return SlhDsaImplementation.ImportPrivateKey(algorithm, source);
}

/// <inheritdoc cref="ImportSlhDsaSecretKey(SlhDsaAlgorithm, ReadOnlySpan{byte})" />
/// <inheritdoc cref="ImportSlhDsaPrivateKey(SlhDsaAlgorithm, ReadOnlySpan{byte})" />
/// <exception cref="ArgumentNullException">
/// <paramref name="algorithm"/> or <paramref name="source" /> is <see langword="null" />.
/// </exception>
public static SlhDsa ImportSlhDsaSecretKey(SlhDsaAlgorithm algorithm, byte[] source)
public static SlhDsa ImportSlhDsaPrivateKey(SlhDsaAlgorithm algorithm, byte[] source)
{
ArgumentNullException.ThrowIfNull(source);

return ImportSlhDsaSecretKey(algorithm, new ReadOnlySpan<byte>(source));
return ImportSlhDsaPrivateKey(algorithm, new ReadOnlySpan<byte>(source));
}

/// <summary>
Expand Down Expand Up @@ -1856,12 +1856,12 @@ protected virtual void Dispose(bool disposing)
protected abstract void ExportSlhDsaPublicKeyCore(Span<byte> destination);

/// <summary>
/// When overridden in a derived class, exports the FIPS 205 secret key to the specified buffer.
/// When overridden in a derived class, exports the FIPS 205 private key to the specified buffer.
/// </summary>
/// <param name="destination">
/// The buffer to receive the secret key.
/// The buffer to receive the private key.
/// </param>
protected abstract void ExportSlhDsaSecretKeyCore(Span<byte> destination);
protected abstract void ExportSlhDsaPrivateKeyCore(Span<byte> destination);

private AsnWriter ExportSubjectPublicKeyInfoCore()
{
Expand Down Expand Up @@ -1952,7 +1952,7 @@ private TResult ExportPkcs8PrivateKeyCallback<TResult>(ExportPkcs8PrivateKeyFunc
{
// A PKCS#8 SLH-DSA-SHA2-256s private key has an ASN.1 overhead of 22 bytes, assuming no attributes.
// Make it an even 32 and that should give a good starting point for a buffer size.
int size = Algorithm.SecretKeySizeInBytes + 32;
int size = Algorithm.PrivateKeySizeInBytes + 32;
// The buffer is only being passed out as a span, so the derived type can't meaningfully
// hold on to it without being malicious.
byte[] buffer = CryptoPool.Rent(size);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ public sealed class SlhDsaAlgorithm : IEquatable<SlhDsaAlgorithm>
public string Name { get; }

/// <summary>
/// Gets the size of the secret key in bytes for this algorithm.
/// Gets the size of the private key in bytes for this algorithm.
/// </summary>
/// <value>
/// The size of the secret key in bytes for this algorithm.
/// The size of the private key in bytes for this algorithm.
/// </value>
public int SecretKeySizeInBytes { get; }
public int PrivateKeySizeInBytes { get; }

/// <summary>
/// Gets the size of the public key in bytes for this algorithm.
Expand Down Expand Up @@ -72,9 +72,9 @@ private SlhDsaAlgorithm(string name, int n, int signatureSizeInBytes, string oid
{
Name = name;

// The secret key and public key sizes are shown to be 4n and 2n respectively in
// The private key and public key sizes are shown to be 4n and 2n respectively in
// section 9.1 "Key Generation", particularly figure 15 and 16.
SecretKeySizeInBytes = 4 * n;
PrivateKeySizeInBytes = 4 * n;
PublicKeySizeInBytes = 2 * n;
SignatureSizeInBytes = signatureSizeInBytes;
Oid = oid;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ protected override void ExportSlhDsaPublicKeyCore(Span<byte> destination) =>
throw new PlatformNotSupportedException();

/// <inheritdoc />
protected override void ExportSlhDsaSecretKeyCore(Span<byte> destination) =>
protected override void ExportSlhDsaPrivateKeyCore(Span<byte> destination) =>
throw new PlatformNotSupportedException();

/// <inheritdoc />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ protected override bool VerifyPreHashCore(ReadOnlySpan<byte> hash, ReadOnlySpan<
protected override void ExportSlhDsaPublicKeyCore(Span<byte> destination) =>
throw new PlatformNotSupportedException();

protected override void ExportSlhDsaSecretKeyCore(Span<byte> destination) =>
protected override void ExportSlhDsaPrivateKeyCore(Span<byte> destination) =>
throw new PlatformNotSupportedException();

protected override bool TryExportPkcs8PrivateKeyCore(Span<byte> destination, out int bytesWritten) =>
Expand All @@ -44,7 +44,7 @@ internal static partial SlhDsaImplementation ImportPublicKey(SlhDsaAlgorithm alg
internal static partial SlhDsaImplementation ImportPkcs8PrivateKeyValue(SlhDsaAlgorithm algorithm, ReadOnlySpan<byte> source) =>
throw new PlatformNotSupportedException();

internal static partial SlhDsaImplementation ImportSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySpan<byte> source) =>
internal static partial SlhDsaImplementation ImportPrivateKey(SlhDsaAlgorithm algorithm, ReadOnlySpan<byte> source) =>
throw new PlatformNotSupportedException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ protected override bool VerifyPreHashCore(ReadOnlySpan<byte> hash, ReadOnlySpan<
protected override void ExportSlhDsaPublicKeyCore(Span<byte> destination) =>
throw new PlatformNotSupportedException();

protected override void ExportSlhDsaSecretKeyCore(Span<byte> destination) =>
protected override void ExportSlhDsaPrivateKeyCore(Span<byte> destination) =>
throw new PlatformNotSupportedException();

protected override bool TryExportPkcs8PrivateKeyCore(Span<byte> destination, out int bytesWritten) =>
Expand All @@ -44,7 +44,7 @@ internal static partial SlhDsaImplementation ImportPublicKey(SlhDsaAlgorithm alg
internal static partial SlhDsaImplementation ImportPkcs8PrivateKeyValue(SlhDsaAlgorithm algorithm, ReadOnlySpan<byte> source) =>
throw new PlatformNotSupportedException();

internal static partial SlhDsaImplementation ImportSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySpan<byte> source) =>
internal static partial SlhDsaImplementation ImportPrivateKey(SlhDsaAlgorithm algorithm, ReadOnlySpan<byte> source) =>
throw new PlatformNotSupportedException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ internal sealed partial class SlhDsaImplementation : SlhDsa
internal static partial SlhDsaImplementation GenerateKeyCore(SlhDsaAlgorithm algorithm);
internal static partial SlhDsaImplementation ImportPublicKey(SlhDsaAlgorithm algorithm, ReadOnlySpan<byte> source);
internal static partial SlhDsaImplementation ImportPkcs8PrivateKeyValue(SlhDsaAlgorithm algorithm, ReadOnlySpan<byte> source);
internal static partial SlhDsaImplementation ImportSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySpan<byte> source);
internal static partial SlhDsaImplementation ImportPrivateKey(SlhDsaAlgorithm algorithm, ReadOnlySpan<byte> source);

/// <summary>
/// Duplicates an SLH-DSA private key by export/import.
Expand All @@ -23,14 +23,14 @@ internal sealed partial class SlhDsaImplementation : SlhDsa
internal static SlhDsaImplementation DuplicatePrivateKey(SlhDsa key)
{
Debug.Assert(key is not SlhDsaImplementation);
Debug.Assert(key.Algorithm.SecretKeySizeInBytes <= 128);
Debug.Assert(key.Algorithm.PrivateKeySizeInBytes <= 128);

Span<byte> secretKey = (stackalloc byte[128])[..key.Algorithm.SecretKeySizeInBytes];
key.ExportSlhDsaSecretKey(secretKey);
Span<byte> secretKey = (stackalloc byte[128])[..key.Algorithm.PrivateKeySizeInBytes];
key.ExportSlhDsaPrivateKey(secretKey);

try
{
return ImportSecretKey(key.Algorithm, secretKey);
return ImportPrivateKey(key.Algorithm, secretKey);
}
finally
{
Expand Down
Loading
Loading