So verschlüsseln Sie CMS-Nachrichten
Sie verschlüsseln Daten für einen Empfänger, dessen Zertifikat einen ML-KEM-Schlüssel trägt, etwa für ein Archiv, dessen Inhalt auch gegen künftige Quantenrechner vertraulich bleiben soll.
Lösungsübersicht
| Element | Zweck |
|---|---|
PostQuantumConfig.Exemptions | erlaubt mit PurePostQuantum reine ML-KEM-Empfänger und den ML-DSA-Aussteller |
MLKemKey.Generate | erzeugt ein ML-KEM-Schlüsselpaar (ML-KEM-768 oder ML-KEM-1024; ML-KEM-512 nur mit ReducedParameterSets) |
X509CertificateBuilder mit einem ML-KEM-Schlüssel | stellt das Empfängerzertifikat aus |
AttachPrivateMLKemKey | ordnet dem Empfängerzertifikat seinen privaten Schlüssel zu |
KemEnvelopedCms.Encrypt, Encode | verschlüsselt den Inhalt für einen oder mehrere Empfänger |
KemEnvelopedCms.Decode, Decrypt | entschlüsselt beim Empfänger |
KemEnvelopedCms ist wie EnvelopedCms von .NET aufgebaut.
Umsetzung
BSI TR-02102-1 empfiehlt ML-KEM nur in Kombination mit einem klassischen Verfahren und dafür die Kombinierer
CatKDF oder KeyCombine. Ein KEMRecipientInfo nach RFC 9629 verwendet ML-KEM allein, Composite ML-KEM
kombiniert mit SHA3-256. Beide Empfängerarten brauchen deshalb eine Freischaltung, die Sie einmal beim Start
der Anwendung setzen; im Beispiel PurePostQuantum für den ML-KEM-Empfänger und die reine
ML-DSA-Zertifizierungsstelle:
PostQuantumConfig.Exemptions |= PostQuantumExemptions.PurePostQuantum;
Empfängerzertifikat; ein ML-KEM-Schlüssel kann nicht signieren, deshalb stellt ein ML-DSA-Aussteller das Zertifikat aus. Im Beispiel ist das eine eigene Zertifizierungsstelle:
var now = DateTimeOffset.UtcNow; using var caKey = MLDsaKey.Generate(MLDsaParameterSet.MLDsa65); var caRequest = new MLDsaX509SignatureGenerator(caKey).CreateCertificateRequest("CN=Muster GmbH PQ CA"); caRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true)); caRequest.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.KeyCertSign, true)); using var ca = caRequest.CreateSelfSigned(now, now.AddYears(10), CryptoMode.PostQuantum); using var archiveKey = MLKemKey.Generate(MLKemParameterSet.MLKem768); var archiveBuilder = new X509CertificateBuilder( new X500DistinguishedName("CN=Muster GmbH Archiv"), archiveKey.ExportSubjectPublicKeyInfo(), default); archiveBuilder.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.KeyEncipherment, true)); using var archive = archiveBuilder.Create( ca, now, now.AddYears(1), RandomNumberGenerator.GetBytes(16), CryptoMode.PostQuantum); archive.AttachPrivateMLKemKey(archiveKey);
Verschlüsseln und entschlüsseln:
var outgoing = new KemEnvelopedCms(new ContentInfo("Vertrag 2026-17"u8.ToArray())); outgoing.Encrypt(archive); byte[] envelope = outgoing.Encode(); var incoming = new KemEnvelopedCms(); incoming.Decode(envelope); incoming.Decrypt(archive); Console.WriteLine(System.Text.Encoding.UTF8.GetString(incoming.ContentInfo.Content));
Hinweise
- Nur mit
KemEnvelopedCmslesbar.EnvelopedCmsvon .NET kann Nachrichten mit KEMRecipientInfo nicht dekodieren, auch nicht für einen RSA-Empfänger derselben Nachricht. - Hybrid über Composite ML-KEM. Trägt das Empfängerzertifikat einen Composite-ML-KEM-Schlüssel, bleibt der Inhalt vertraulich, solange einer der beiden Anteile hält. Ordnen Sie den privaten Schlüssel dann mit
AttachPrivateCompositeMLKemKeyzu. Das Verschlüsseln für einen solchen Empfänger brauchtPostQuantumExemptions.NonRecommendedCombiners; das Entschlüsseln vorhandener Nachrichten braucht keine Freischaltung und meldet das EreignisPolicyDeviation. - Hybrid ohne CMS. Für ein eigenes Protokoll ohne CMS vereinbart
HybridKeyAgreementeinen Schlüssel aus ECDH und ML-KEM mit KeyCombine, ohne Freischaltung; siehe So vereinbaren Sie einen hybriden Schlüssel. - RSA-Empfänger in derselben Nachricht. Ein Empfänger mit RSA-Zertifikat erhält eine KeyTransRecipientInfo mit RSAES-OAEP. Auch er öffnet die Nachricht mit
KemEnvelopedCms. - Der private Schlüssel muss im Prozess sein.
Decryptbraucht den privaten ML-KEM-Schlüssel des Empfängers. Fehlt er, scheitert der Aufruf mit einerCryptographicException.