[API Proposal]: KEM support for EnvelopedCms
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
### Background and motivation
Enveloped CMS has support for KEMs. RFC 9629 generalized an KEMReceipientInfo, and RFC 9936 specifies how to use ML-KEM with KEMRecipientInfo.
This is a proposal to add a KEMRecipientInfo and ML-KEM to `EnvelopedCms`.
### API Proposal
```csharp
namespace System.Security.Cryptography.Pkcs;
public sealed class KemRecipientInfo : RecipientInfo
{
internal KemRecipientInfo();
public override int Version { get; }
public override SubjectIdentifier RecipientIdentifier { get; }
public override AlgorithmIdentifier KeyEncryptionAlgorithm { get; }
public override byte[] EncryptedKey { get; }
public AlgorithmIdentifier KeyEncapsulationAlgorithm { get; }
public ReadOnlyMemory KeyEncapsulationCiphertext { get; }
public AlgorithmIdentifier KeyDerivationAlgorithm { get; }
public int KeyEncryptionKeyLengthInBytes { get; }
// Important, "null" means the OPTIONAL OCTET STRING is missing entirely.
// Present, but empty, means the OCTET STRING was present with a length of zero.
public ReadOnlyMemory? UserKeyingMaterial { get; }
}
public partial enum RecipientInfoType
{
// Existing values omitted.
KeyEncapsulation = 3,
}
public sealed partial class EnvelopedCms
{
public void Decrypt(KemRecipientInfo recipientInfo, MLKem privateKey);
}
public sealed partial class CmsRecipient
{
// Factories for specifying a userKeyingMaterial. It's important to recognize that an _empty_
// userKeyingMaterial is not the same as an _absent_ UKM. If someone wants to create a recipient
// with an no UKM, whatsoever, they use a constructor. If they want to specify a UKM, including
// an empty one, they use the factory. That is also why this parameter is not optional.
// We use a factory method instead of constructor overloading because `null` inputs will result in overload ambiguity.
// This will reject non-KEM certificates. That is another reason for not using a constructor.
public static CmsRecipient CreateForKeyEncapsulation(
X509Certificate2 certificate,
ReadOnlySpan userKeyingMaterial);
public static CmsRecipient CreateForKeyEncapsulation(
SubjectIdentifierType recipientIdentifierType,
X509Certificate2 certificate,
ReadOnlySpan userKeyingMaterial);
}
```
### API Usage
```csharp
using System.Security.Cryptography;
using System.Security.Cryptography.Pkcs;
using System.Text;
byte[] encodedCms = File.ReadAllBytes("message.p7m");
using MLKem privateKey = MLKem.ImportFromPem(File.ReadAllText("mlkem-private-key.pem"));
EnvelopedCms cms = new();
cms.Decode(encodedCms);
KemRecipientInfo recipient = (KemRecipientInfo)cms.RecipientInfos[0];
cms.Decrypt(recipient, privateKey);
```
### Alternative Designs
_No response_
### Risks
_No response_
Contributor guide
Assessment
This issue has not been assessed yet.