Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
Expand Up @@ -473,23 +473,67 @@ private static CompositeMLDsaAlgorithm CreateECDsa(
// publicKey [1] BIT STRING OPTIONAL
// }

// version

int versionSizeInBytes =
1 + // Tag for INTEGER
1 + // Length field
1; // Value (always 1)

// privateKey

int privateKeySizeInBytes =
1 + // Tag for OCTET STRING
GetDerLengthLength(keySizeInBytes) + // Length field
keySizeInBytes; // Value

// parameters and publicKey must be omitted for Composite ML-DSA
// parameters

int namedCurveSizeInBytes =
oid switch
{
Oids.MLDsa44WithECDsaP256PreHashSha256 or
Oids.MLDsa65WithECDsaP256PreHashSha512 =>
// 1.2.840.10045.3.1.7
// 06 08 2A 86 48 CE 3D 03 01 07
10,
Oids.MLDsa65WithECDsaP384PreHashSha512 or
Oids.MLDsa87WithECDsaP384PreHashSha512 =>
// 1.3.132.0.34
// 06 05 2B 81 04 00 22
7,
Oids.MLDsa87WithECDsaP521PreHashSha512 =>
// 1.3.132.0.35
// 06 05 2B 81 04 00 23
7,
Oids.MLDsa65WithECDsaBrainpoolP256r1PreHashSha512 =>
// 1.3.36.3.3.2.8.1.1.7
// 06 09 2B 24 03 03 02 08 01 01 07
11,
Oids.MLDsa87WithECDsaBrainpoolP384r1PreHashSha512 =>
// 1.3.36.3.3.2.8.1.1.11
// 06 09 2B 24 03 03 02 08 01 01 0B
11,
_ => AssertAndThrow(oid),
};

static int AssertAndThrow(string oid)
{
Debug.Fail($"Unsupported OID: {oid}.");
throw new CryptographicException();
}

int parametersSizeInBytes =
1 + // Context-specific tag for [0]
GetDerLengthLength(namedCurveSizeInBytes) + // Length field
namedCurveSizeInBytes; // Value

// publicKey must be omitted for Composite ML-DSA

int ecPrivateKeySizeInBytes =
1 + // Tag for SEQUENCE
GetDerLengthLength(versionSizeInBytes + privateKeySizeInBytes) + // Length field
versionSizeInBytes + // Version
privateKeySizeInBytes;
1 + // Tag for SEQUENCE
GetDerLengthLength(versionSizeInBytes + privateKeySizeInBytes + parametersSizeInBytes) + // Length field
versionSizeInBytes + privateKeySizeInBytes + parametersSizeInBytes; // Value

return new CompositeMLDsaAlgorithm(
name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,19 @@ public static unsafe ECDsaComponent ImportPrivateKey(ECDsaAlgorithm algorithm, R
ECPrivateKey ecPrivateKey = ECPrivateKey.Decode(manager.Memory, AsnEncodingRules.BER);

if (ecPrivateKey.Version != 1 ||
ecPrivateKey.Parameters is not null ||
ecPrivateKey.PublicKey is not null)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
}

if (ecPrivateKey.Parameters is not ECDomainParameters domainParameters ||
domainParameters.Named is not string curveOid ||
curveOid != algorithm.CurveOidValue)
{
// The curve specified must be named and match the required curve for the Composite ML-DSA algorithm.
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
}

byte[] d = new byte[ecPrivateKey.PrivateKey.Length];

using (PinAndClear.Track(d))
Expand Down Expand Up @@ -206,7 +213,7 @@ internal override bool TryExportPrivateKey(Span<byte> destination, out int bytes

try
{
WriteKey(ecParameters.D, writer);
WriteKey(ecParameters.D, _algorithm.CurveOidValue, writer);
return writer.TryEncode(destination, out bytesWritten);
}
finally
Expand Down Expand Up @@ -239,7 +246,7 @@ internal override bool TryExportPrivateKey(Span<byte> destination, out int bytes
throw new CryptographicException();
}

WriteKey(d, writer);
WriteKey(d, _algorithm.CurveOidValue, writer);
return true;
});
});
Expand All @@ -252,7 +259,7 @@ internal override bool TryExportPrivateKey(Span<byte> destination, out int bytes
}
#endif

static void WriteKey(byte[] d, AsnWriter writer)
static void WriteKey(byte[] d, string curveOid, AsnWriter writer)
{
// ECPrivateKey
using (writer.PushSequence())
Expand All @@ -262,6 +269,12 @@ static void WriteKey(byte[] d, AsnWriter writer)

// privateKey
writer.WriteOctetString(d);

// parameters
using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0, isConstructed: true)))
{
writer.WriteObjectIdentifier(curveOid);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ internal static CompositeMLDsa GenerateKeyImpl(CompositeMLDsaAlgorithm algorithm

AlgorithmMetadata metadata = s_algorithmMetadata[algorithm];

// draft-ietf-lamps-pq-composite-sigs-08, 4.1
// draft-ietf-lamps-pq-composite-sigs-12, 4.1
// 1. Generate component keys
//
// mldsaSeed = Random(32)
Expand Down Expand Up @@ -115,7 +115,7 @@ internal static CompositeMLDsa ImportCompositeMLDsaPublicKeyImpl(CompositeMLDsaA

AlgorithmMetadata metadata = s_algorithmMetadata[algorithm];

// draft-ietf-lamps-pq-composite-sigs-08, 5.1
// draft-ietf-lamps-pq-composite-sigs-12, 5.1
// 1. Parse each constituent encoded public key.
// The length of the mldsaKey is known based on the
// size of the ML-DSA component key length specified
Expand Down Expand Up @@ -167,7 +167,7 @@ internal static CompositeMLDsa ImportCompositeMLDsaPrivateKeyImpl(CompositeMLDsa

AlgorithmMetadata metadata = s_algorithmMetadata[algorithm];

// draft-ietf-lamps-pq-composite-sigs-08, 5.2
// draft-ietf-lamps-pq-composite-sigs-12, 5.2
// 1. Parse each constituent encoded key.
//
// mldsaSeed = bytes[:32]
Expand Down Expand Up @@ -203,7 +203,7 @@ static CryptographicException FailAndGetException()

protected override int SignDataCore(ReadOnlySpan<byte> data, ReadOnlySpan<byte> context, Span<byte> destination)
{
// draft-ietf-lamps-pq-composite-sigs-08, 4.2
// draft-ietf-lamps-pq-composite-sigs-12, 4.2
// 1. If len(ctx) > 255:
// return error

Expand Down Expand Up @@ -287,7 +287,7 @@ protected override int SignDataCore(ReadOnlySpan<byte> data, ReadOnlySpan<byte>

protected override bool VerifyDataCore(ReadOnlySpan<byte> data, ReadOnlySpan<byte> context, ReadOnlySpan<byte> signature)
{
// draft-ietf-lamps-pq-composite-sigs-08, 4.3
// draft-ietf-lamps-pq-composite-sigs-12, 4.3
// 1. If len(ctx) > 255
// return error

Expand Down Expand Up @@ -375,7 +375,7 @@ protected override bool TryExportPkcs8PrivateKeyCore(Span<byte> destination, out

protected override int ExportCompositeMLDsaPublicKeyCore(Span<byte> destination)
{
// draft-ietf-lamps-pq-composite-sigs-08, 5.1
// draft-ietf-lamps-pq-composite-sigs-12, 5.1
// 1. Combine and output the encoded public key
//
// output mldsaPK || tradPK
Expand All @@ -397,7 +397,7 @@ protected override int ExportCompositeMLDsaPublicKeyCore(Span<byte> destination)

protected override int ExportCompositeMLDsaPrivateKeyCore(Span<byte> destination)
{
// draft-ietf-lamps-pq-composite-sigs-08, 5.2
// draft-ietf-lamps-pq-composite-sigs-12, 5.2
// 1. Combine and output the encoded private key.
//
// output mldsaSeed || tradSK
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,57 +158,62 @@ static byte[] CreateKeyWithVersion(int? version)

return ComposeKeys(
MLDsaTestsData.IetfMLDsa65.PrivateSeed,
WriteECPrivateKey(version, ecdsaKey.D, oid: null, point: null));
WriteECPrivateKey(version, ecdsaKey.D, oid: ecdsaKey.Curve.Oid.Value, point: null));
}
}

[Fact]
public static void ImportBadPrivateKey_ECDsa_NoPrivateKey()
{
ECParameters ecdsaKey = EccTestData.GetNistP256ReferenceKey();

byte[] compositeKey = ComposeKeys(
MLDsaTestsData.IetfMLDsa65.PrivateSeed,
WriteECPrivateKey(version: 1, d: null, oid: null, point: null));
WriteECPrivateKey(version: 1, d: null, oid: ecdsaKey.Curve.Oid.Value, point: null));

AssertImportBadPrivateKey(CompositeMLDsaAlgorithm.MLDsa65WithECDsaP256, compositeKey);
}

[Fact]
public static void ImportBadPrivateKey_ECDsa_HasCurve()
public static void ImportBadPrivateKey_ECDsa_WrongCurve()
{
ECParameters ecdsaKey = EccTestData.GetNistP256ReferenceKey();
CompositeMLDsaAlgorithm algorithm = CompositeMLDsaAlgorithm.MLDsa65WithECDsaP256;

// Domain parameters are not allowed
// Wrong curve OID
AssertImportBadPrivateKey(
CompositeMLDsaAlgorithm.MLDsa65WithECDsaP256,
ComposeKeys(
MLDsaTestsData.IetfMLDsa65.PrivateSeed,
WriteECPrivateKey(version: 1, ecdsaKey.D, ecdsaKey.Curve.Oid.Value, point: null)));
}
algorithm,
CreateKeyWithCurveOid(ECCurve.NamedCurves.nistP521.Oid.Value));

[Fact]
public static void ImportPrivateKey_ECDsa_HasPublicKey()
{
ECParameters ecdsaKey = EccTestData.GetNistP256ReferenceKey();
AssertImportBadPrivateKey(
algorithm,
CreateKeyWithCurveOid("1.3.36.3.3.2.8.1.1.7")); // brainpoolP256r1

// Public key is not allowed
// No parameters
AssertImportBadPrivateKey(
CompositeMLDsaAlgorithm.MLDsa65WithECDsaP256,
ComposeKeys(
algorithm,
CreateKeyWithCurveOid(null));

static byte[] CreateKeyWithCurveOid(string? oid)
{
ECParameters ecdsaKey = EccTestData.GetNistP256ReferenceKey();

return ComposeKeys(
MLDsaTestsData.IetfMLDsa65.PrivateSeed,
WriteECPrivateKey(version: 1, ecdsaKey.D, oid: null, ecdsaKey.Q)));
WriteECPrivateKey(version: 1, ecdsaKey.D, oid, ecdsaKey.Q));
}
}

[Fact]
public static void ImportPrivateKey_ECDsa_HasCurveAndPublicKey()
public static void ImportPrivateKey_ECDsa_HasPublicKey()
{
ECParameters ecdsaKey = EccTestData.GetNistP256ReferenceKey();

// Domain parameters and public key are not allowed
// Public key is not allowed
AssertImportBadPrivateKey(
CompositeMLDsaAlgorithm.MLDsa65WithECDsaP256,
ComposeKeys(
MLDsaTestsData.IetfMLDsa65.PrivateSeed,
WriteECPrivateKey(version: 1, ecdsaKey.D, ecdsaKey.Curve.Oid.Value, ecdsaKey.Q)));
WriteECPrivateKey(version: 1, ecdsaKey.D, oid: ecdsaKey.Curve.Oid.Value, ecdsaKey.Q)));
}

static byte[] ComposeKeys(byte[] mldsaKey, AsnWriter tradKey)
Expand Down
Loading
Loading