ektrah / nsec

A modern and easy-to-use cryptographic library for .NET 8+ based on libsodium
https://nsec.rocks
MIT License
374 stars 52 forks source link

Shared Secret Key for TLS 1.3 Purpouses #74

Closed PiotrKowalski93 closed 8 months ago

PiotrKowalski93 commented 1 year ago

Is it possible to create shared secret key on the server side when Public Key will come over tcp? Belows code throw exception: 'Cannot use a key created for a different algorithm instance. (key.Algorithm must be the same object as the current object.) (Parameter 'key')'

Documentation lack of examples and explanations unfortunately

static void Main(string[] args)
        {
            var algorythm = KeyAgreementAlgorithm.X25519;
            var creationParameters = new KeyCreationParameters
            {
                ExportPolicy = KeyExportPolicies.AllowPlaintextArchiving
            };

            var clientRandom = RandomNumberGenerator.GetBytes(32);
            using var clientKey = Key.Create(algorythm, creationParameters);

            var publicClientKey = clientKey.Export(KeyBlobFormat.RawPublicKey);
            var privateClientKey = clientKey.Export(KeyBlobFormat.RawPrivateKey);

            Console.WriteLine($"Client Random: {Convert.ToBase64String(clientRandom)}");
            Console.WriteLine($"Client Public Key: {Convert.ToBase64String(publicClientKey)}");
            Console.WriteLine($"Client Private Key: {Convert.ToBase64String(privateClientKey)}");
            Console.WriteLine();

            var serverRandom = RandomNumberGenerator.GetBytes(32);
            using var serverKey = Key.Create(algorythm, creationParameters);
            var publicServerKey = serverKey.Export(KeyBlobFormat.RawPublicKey);
            var privateServerKey = serverKey.Export(KeyBlobFormat.RawPrivateKey);

            Console.WriteLine($"Server Random: {Convert.ToBase64String(serverRandom)}");
            Console.WriteLine($"Server Public Key: {Convert.ToBase64String(publicServerKey)}");
            Console.WriteLine($"Server Private Key: {Convert.ToBase64String(privateServerKey)}");
            Console.WriteLine();

            var clientSSK = CreateSSK(algorythm, publicServerKey, privateClientKey);
            var serverSSK = CreateSSK(algorythm, publicClientKey, privateServerKey);
            Console.WriteLine();
            Console.WriteLine($"Client SSK: {Convert.ToBase64String(clientSSK)}");
            Console.WriteLine($"Server SSK: {Convert.ToBase64String(serverSSK)}");

            Console.ReadKey();
        }

        public static byte[] CreateSSK(X25519 algorythm, byte[] publicKey, byte[] privateKey)
        {
            var publicKeyObj = PublicKey.Import(SignatureAlgorithm.Ed25519, publicKey, KeyBlobFormat.RawPublicKey);
            var privateKeyObj = Key.Import(SignatureAlgorithm.Ed25519, privateKey, KeyBlobFormat.RawPrivateKey);

            var sharedSecretKey = algorythm.Agree(privateKeyObj, publicKeyObj);

            byte[] SSK = sharedSecretKey.Export(SharedSecretBlobFormat.RawSharedSecret);

            return SSK;
        }
ektrah commented 1 year ago

First, it seems you're importing the byte arrays in CreateSSK as Ed25519 keys but then performing key agreement using X25519. That won't work: Ed25519 keys are for signatures, not for key agreement. Second, if you want to do algorythm.Agree(privateKeyObj, publicKeyObj), then both privateKeyObj and publicKeyObj must be created/import using algorythm. Try changing ...Import(SignatureAlgorithm.Ed25519, ... to ...Import(algorythm, ....

PiotrKowalski93 commented 1 year ago

Oh yes, I changed that and got:

System.InvalidOperationException: 'The key cannot be exported.' for byte[] SSK = sharedSecretKey.Export(SharedSecretBlobFormat.RawSharedSecret);

BinkersSoft commented 11 months ago

Exceptions related to Keys are documented here https://nsec.rocks/docs/api/nsec.cryptography.key