12 private const string preHashAlgorithm =
"SHAKE-256";
14 private readonly
ML_KEM keyEncapsulationMechanism;
15 private readonly
ML_DSA signatureAlgorithm;
16 private readonly
ML_KEM_Keys keyEncapsulationMechanismKeys;
17 private readonly
ML_DSA_Keys signatureAlgorithmKeys;
18 private readonly
bool hasPrivateKey;
19 private readonly
byte[] publicKey;
20 private readonly
string publicKeyBase64;
36 this.keyEncapsulationMechanismKeys = KeyEncapsulationMechanismKeys;
38 this.signatureAlgorithmKeys = SignatureAlgorithmKeys;
40 this.hasPrivateKey = this.keyEncapsulationMechanismKeys.HasDecapsulationKey &&
43 if (this.keyEncapsulationMechanismKeys.EncapsulationKey is
null ||
44 this.signatureAlgorithmKeys.PublicKey is
null)
46 this.publicKey =
null;
47 this.publicKeyBase64 =
null;
51 this.publicKey =
new byte[this.keyEncapsulationMechanism.PublicKeyLength +
52 this.signatureAlgorithm.PublicKeyLength];
54 Buffer.BlockCopy(this.keyEncapsulationMechanismKeys.EncapsulationKey, 0,
55 this.publicKey, 0,
this.keyEncapsulationMechanism.PublicKeyLength);
57 Buffer.BlockCopy(this.signatureAlgorithmKeys.PublicKey, 0,
58 this.publicKey,
this.keyEncapsulationMechanism.PublicKeyLength,
59 this.signatureAlgorithm.PublicKeyLength);
61 this.publicKeyBase64 = Convert.ToBase64String(this.publicKey);
77 throw new ArgumentNullException(nameof(
PublicKey));
82 throw new ArgumentException(
"Public key length does not match expected length for the specified key encapsulation mechanism and signature algorithm.", nameof(
PublicKey));
87 this.hasPrivateKey =
false;
89 this.publicKeyBase64 = Convert.ToBase64String(
PublicKey);
91 byte[] EncapsulationKey =
new byte[this.keyEncapsulationMechanism.PublicKeyLength];
92 byte[] SignaturePublicKey =
new byte[this.signatureAlgorithm.PublicKeyLength];
94 Buffer.BlockCopy(
PublicKey, 0, EncapsulationKey, 0, EncapsulationKey.Length);
95 Buffer.BlockCopy(
PublicKey, EncapsulationKey.Length, SignaturePublicKey, 0, SignaturePublicKey.Length);
138 throw new ArgumentException(
"Remote endpoint is not a Module Lattice endpoint.", nameof(RemoteEndpoint));
140 if (!this.keyEncapsulationMechanismKeys.HasDecapsulationKey)
141 throw new InvalidOperationException(
"Local endpoint does not have a private key for shared secret calculation.");
143 if (this.keyEncapsulationMechanism.PublicKeyLength !=
144 RemoteModuleLatticeEndpoint.keyEncapsulationMechanism.PublicKeyLength ||
145 this.signatureAlgorithm.PublicKeyLength !=
146 RemoteModuleLatticeEndpoint.signatureAlgorithm.PublicKeyLength)
148 throw new ArgumentException(
"Key lengths do not match.", nameof(RemoteEndpoint));
152 RemoteModuleLatticeEndpoint.keyEncapsulationMechanismKeys.EncapsulationKey);
154 CipherText = Encapsulation.CipherText;
156 return Encapsulation.SharedSecret;
170 throw new ArgumentException(
"Remote endpoint is not a Module Lattice endpoint.", nameof(RemoteEndpoint));
172 if (!this.keyEncapsulationMechanismKeys.HasDecapsulationKey)
173 throw new InvalidOperationException(
"Local endpoint does not have a private key for shared secret calculation.");
175 if (this.keyEncapsulationMechanism.PublicKeyLength !=
176 RemoteModuleLatticeEndpoint.keyEncapsulationMechanism.PublicKeyLength ||
177 this.signatureAlgorithm.PublicKeyLength !=
178 RemoteModuleLatticeEndpoint.signatureAlgorithm.PublicKeyLength)
180 throw new ArgumentException(
"Key lengths do not match.", nameof(RemoteEndpoint));
183 return this.keyEncapsulationMechanism.Decapsulate(
184 this.keyEncapsulationMechanismKeys.DecapsulationKey, CipherText);
197 public override byte[]
Sign(
byte[] Data)
199 if (!this.hasPrivateKey)
200 throw new InvalidOperationException(
"Signing requires private key.");
207 Signature = this.signatureAlgorithm.Sign(this.signatureAlgorithmKeys,
208 Data,
null, preHashAlgorithm, out
_);
209 Valid = this.signatureAlgorithm.Verify(this.signatureAlgorithmKeys, Data,
210 Signature,
null, preHashAlgorithm);
222 public override byte[]
Sign(Stream Data)
224 if (!this.hasPrivateKey)
225 throw new InvalidOperationException(
"Signing requires private key.");
232 Signature = this.signatureAlgorithm.Sign(this.signatureAlgorithmKeys,
233 Data,
null, preHashAlgorithm, out
_);
234 Valid = this.signatureAlgorithm.Verify(this.signatureAlgorithmKeys, Data,
235 Signature,
null, preHashAlgorithm);
252 Signature,
null, preHashAlgorithm);
265 Signature,
null, preHashAlgorithm);
274 public override bool Verify(
byte[] Data,
byte[] Signature)
276 return this.signatureAlgorithm.Verify(this.signatureAlgorithmKeys, Data,
277 Signature,
null, preHashAlgorithm);
286 public override bool Verify(Stream Data,
byte[] Signature)
288 return this.signatureAlgorithm.Verify(this.signatureAlgorithmKeys, Data,
289 Signature,
null, preHashAlgorithm);
296 this.publicKeyBase64 == MlObj.publicKeyBase64 &&
297 this.hasPrivateKey == MlObj.hasPrivateKey;
303 int Result = this.publicKeyBase64.GetHashCode();
304 Result ^= Result << 5 ^ this.hasPrivateKey.GetHashCode();
319 throw new ArgumentNullException(nameof(Secret));
321 if (Secret.Length == 96)
323 byte[] SeedKem =
new byte[64];
324 byte[] SeedDsa =
new byte[32];
326 Buffer.BlockCopy(Secret, 0, SeedKem, 0, 64);
327 Buffer.BlockCopy(Secret, 64, SeedDsa, 0, 32);
329 KemKeys = this.keyEncapsulationMechanism.KeyGen_FromSeed(SeedKem,
true);
330 DsaKeys = this.signatureAlgorithm.KeyGen_Internal(SeedDsa,
true);
332 Array.Clear(SeedKem, 0, SeedKem.Length);
333 Array.Clear(SeedDsa, 0, SeedDsa.Length);
336 throw new ArgumentException(
"Invalid private key length.", nameof(Secret));
345 if (!(this.keyEncapsulationMechanismKeys?.HasDecapsulationKey ??
false) ||
348 throw new InvalidOperationException(
"Endpoint has no private keys.");
351 if (this.keyEncapsulationMechanismKeys.Seed is
null ||
352 this.signatureAlgorithmKeys.Seed is
null)
354 throw new InvalidOperationException(
"Endpoint has no seeds, which is required to export private key.");
357 byte[] KemKey = this.keyEncapsulationMechanismKeys.Seed;
358 byte[] DsaKey = this.signatureAlgorithmKeys.Seed;
360 int c = KemKey.Length;
361 int d = DsaKey.Length;
363 byte[] Result =
new byte[c + d];
365 Buffer.BlockCopy(KemKey, 0, Result, 0, c);
366 Buffer.BlockCopy(DsaKey, 0, Result, c, d);
Abstract base class for End-to-End encryption schemes.
virtual IE2eSymmetricCipher DefaultSymmetricCipher
Default symmetric cipher.
Abstract base class for Module Lattice endpoints.
override byte[] GetSharedSecretForEncryption(IE2eEndpoint RemoteEndpoint, IE2eSymmetricCipher Cipher, out byte[] CipherText)
Gets a shared secret for encryption, and optionally a corresponding cipher text.
override byte[] PublicKey
Remote public key.
byte[] ExportPrivateKey()
Exports the private key (seed) of the endpoint.
override byte[] Sign(Stream Data)
Signs binary data using the local private key.
override bool SharedSecretUseCipherText
If the recipient needs a cipher text to generate the same shared secret.
bool Verify(Stream Data, byte[] PublicKey, byte[] Signature)
Verifies a signature.
override bool Verify(byte[] Data, byte[] Signature)
Verifies a signature.
override int GetHashCode()
override byte[] GetSharedSecretForDecryption(IE2eEndpoint RemoteEndpoint, byte[] CipherText)
Gets a shared secret for decryption.
ModuleLatticeEndpoint(ML_KEM KeyEncapsulationMechanism, ML_KEM_Keys KeyEncapsulationMechanismKeys, ML_DSA SignatureAlgorithm, ML_DSA_Keys SignatureAlgorithmKeys, IE2eSymmetricCipher DefaultSymmetricCipher)
Abstract base class for Module Lattice endpoints.
bool HasPrivateKey
If the key contains a private key.
ML_DSA SignatureAlgorithm
Signature Algorithm used for signing.
void GeneratePrivateKeys(byte[] Secret, out ML_KEM_Keys KemKeys, out ML_DSA_Keys DsaKeys)
Generates private keys from a 96-byte secret.
override bool Equals(object obj)
override string PublicKeyBase64
Remote public key, as a Base64 string.
bool Verify(byte[] Data, byte[] PublicKey, byte[] Signature)
Verifies a signature.
ModuleLatticeEndpoint(byte[] PublicKey, ML_KEM KeyEncapsulationMechanism, ML_DSA SignatureAlgorithm, IE2eSymmetricCipher DefaultSymmetricCipher)
Abstract base class for Module Lattice endpoints.
override byte[] Sign(byte[] Data)
Signs binary data using the local private key.
ML_KEM KeyEncapsulationMechanism
Key Encapsulation Mechanism used for key exchange.
override bool Verify(Stream Data, byte[] Signature)
Verifies a signature.
ML-DSA public and private keys, as defined in §6.1.
static ML_DSA_Keys FromPublicKey(byte[] PublicKey)
Creates a key object instance from a public key.
bool HasPrivateKey
If the key contains a private key.
Implements the ML-DSA algorithm for post-quantum cryptography, as defined in NIST FIPS 204: https://n...
override int PublicKeyLength
Length of the public key.
ML_KEM encapsulation keys, as defined in §7.2.
ML_KEM encryption and decryption keys, as defined in §6.1.
static ML_KEM_Keys FromEncapsulationKey(byte[] EncapsulationKey)
Creates a key object instance from an encapsulation key.
Implements the ML-KEM algorithm for post-quantum cryptography, as defined in NIST FIPS 203: https://n...
override int PublicKeyLength
Length of the public key.
Abstract base class for End-to-End encryption schemes.
Interface for symmetric ciphers.
IElement Encapsulate(ChunkedList< IElement > Elements, ScriptNode Node)
Encapsulates a set of elements into a similar structure as that provided by the current element.