Skip to content

Commit ae2875a

Browse files
authored
ML-KEM: Add support for importing encrypted PKCS#8 keys
1 parent 45fa758 commit ae2875a

File tree

5 files changed

+655
-1
lines changed

5 files changed

+655
-1
lines changed

src/libraries/Common/src/System/Security/Cryptography/MLKem.cs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,101 @@ public static MLKem ImportPkcs8PrivateKey(byte[] source)
883883
return ImportPkcs8PrivateKey(new ReadOnlySpan<byte>(source));
884884
}
885885

886+
/// <summary>
887+
/// Imports an ML-KEM private key from a PKCS#8 EncryptedPrivateKeyInfo structure.
888+
/// </summary>
889+
/// <param name="passwordBytes">
890+
/// The bytes to use as a password when decrypting the key material.
891+
/// </param>
892+
/// <param name="source">
893+
/// The bytes of a PKCS#8 EncryptedPrivateKeyInfo structure in the ASN.1-BER encoding.
894+
/// </param>
895+
/// <returns>
896+
/// The imported key.
897+
/// </returns>
898+
/// <exception cref="CryptographicException">
899+
/// <para>
900+
/// The contents of <paramref name="source"/> do not represent an ASN.1-BER-encoded PKCS#8 EncryptedPrivateKeyInfo structure.
901+
/// </para>
902+
/// <para>-or-</para>
903+
/// <para>
904+
/// The specified password is incorrect.
905+
/// </para>
906+
/// <para>-or-</para>
907+
/// <para>
908+
/// The EncryptedPrivateKeyInfo indicates the Key Derivation Function (KDF) to apply is the legacy PKCS#12 KDF,
909+
/// which requires <see cref="char"/>-based passwords.
910+
/// </para>
911+
/// <para>-or-</para>
912+
/// <para>
913+
/// The value does not represent an ML-KEM key.
914+
/// </para>
915+
/// <para>-or-</para>
916+
/// <para>
917+
/// The algorithm-specific import failed.
918+
/// </para>
919+
/// </exception>
920+
/// <exception cref="PlatformNotSupportedException">
921+
/// The platform does not support ML-KEM. Callers can use the <see cref="IsSupported" /> property
922+
/// to determine if the platform supports ML-KEM.
923+
/// </exception>
924+
public static MLKem ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<byte> passwordBytes, ReadOnlySpan<byte> source)
925+
{
926+
ThrowIfTrailingData(source);
927+
ThrowIfNotSupported();
928+
929+
return KeyFormatHelper.DecryptPkcs8(
930+
passwordBytes,
931+
source,
932+
ImportPkcs8PrivateKey,
933+
out _);
934+
}
935+
936+
/// <summary>
937+
/// Imports an ML-KEM private key from a PKCS#8 EncryptedPrivateKeyInfo structure.
938+
/// </summary>
939+
/// <param name="password">
940+
/// The password to use when decrypting the key material.
941+
/// </param>
942+
/// <param name="source">
943+
/// The bytes of a PKCS#8 EncryptedPrivateKeyInfo structure in the ASN.1-BER encoding.
944+
/// </param>
945+
/// <returns>
946+
/// The imported key.
947+
/// </returns>
948+
/// <exception cref="CryptographicException">
949+
/// <para>
950+
/// The contents of <paramref name="source"/> do not represent an ASN.1-BER-encoded PKCS#8 EncryptedPrivateKeyInfo structure.
951+
/// </para>
952+
/// <para>-or-</para>
953+
/// <para>
954+
/// The specified password is incorrect.
955+
/// </para>
956+
/// <para>-or-</para>
957+
/// <para>
958+
/// The value does not represent an ML-KEM key.
959+
/// </para>
960+
/// <para>-or-</para>
961+
/// <para>
962+
/// The algorithm-specific import failed.
963+
/// </para>
964+
/// </exception>
965+
/// <exception cref="PlatformNotSupportedException">
966+
/// The platform does not support ML-KEM. Callers can use the <see cref="IsSupported" /> property
967+
/// to determine if the platform supports ML-KEM.
968+
/// </exception>
969+
public static MLKem ImportEncryptedPkcs8PrivateKey(ReadOnlySpan<char> password, ReadOnlySpan<byte> source)
970+
{
971+
ThrowIfTrailingData(source);
972+
ThrowIfNotSupported();
973+
974+
return KeyFormatHelper.DecryptPkcs8(
975+
password,
976+
source,
977+
ImportPkcs8PrivateKey,
978+
out _);
979+
}
980+
886981
/// <summary>
887982
/// Releases all resources used by the <see cref="MLKem"/> class.
888983
/// </summary>

src/libraries/Common/tests/System/Security/Cryptography/MLKemNotSupportedTests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,25 @@ public static void ImportDecapsulationKey_NotSupported(MLKemAlgorithm algorithm)
6464
algorithm,
6565
new Span<byte>(new byte[algorithm.DecapsulationKeySizeInBytes])));
6666
}
67+
68+
[Fact]
69+
public static void ImportPkcs8PrivateKey_NotSupported()
70+
{
71+
Assert.Throws<PlatformNotSupportedException>(() => MLKem.ImportPkcs8PrivateKey(
72+
MLKemTestData.IetfMlKem512PrivateKeySeed));
73+
74+
Assert.Throws<PlatformNotSupportedException>(() => MLKem.ImportPkcs8PrivateKey(
75+
new ReadOnlySpan<byte>(MLKemTestData.IetfMlKem512PrivateKeySeed)));
76+
}
77+
78+
[Fact]
79+
public static void ImportEncryptedPkcs8PrivateKey_NotSupported()
80+
{
81+
Assert.Throws<PlatformNotSupportedException>(() => MLKem.ImportEncryptedPkcs8PrivateKey(
82+
MLKemTestData.EncryptedPrivateKeyPassword, MLKemTestData.IetfMlKem512EncryptedPrivateKeySeed));
83+
84+
Assert.Throws<PlatformNotSupportedException>(() => MLKem.ImportEncryptedPkcs8PrivateKey(
85+
MLKemTestData.EncryptedPrivateKeyPasswordBytes, MLKemTestData.IetfMlKem512EncryptedPrivateKeySeed));
86+
}
6787
}
6888
}

0 commit comments

Comments
 (0)