Example #1
0
        public Packet Auth(PublicKey remoteNodeId, EncryptionHandshake handshake)
        {
            handshake.RemoteNodeId        = remoteNodeId;
            handshake.InitiatorNonce      = _cryptoRandom.GenerateRandomBytes(32);
            handshake.EphemeralPrivateKey = _ephemeralGenerator.Generate();

            byte[] staticSharedSecret = Proxy.EcdhSerialized(remoteNodeId.Bytes, _privateKey.KeyBytes);
            byte[] forSigning         = staticSharedSecret.Xor(handshake.InitiatorNonce);

            AuthEip8Message authMessage = new AuthEip8Message();

            authMessage.Nonce     = handshake.InitiatorNonce;
            authMessage.PublicKey = _privateKey.PublicKey;
            authMessage.Signature = _ecdsa.Sign(handshake.EphemeralPrivateKey, new Keccak(forSigning));

            byte[] authData = _messageSerializationService.Serialize(authMessage);
            int    size     = authData.Length + 32 + 16 + 65; // data + MAC + IV + pub

            byte[] sizeBytes  = size.ToBigEndianByteArray().Slice(2, 2);
            byte[] packetData = _eciesCipher.Encrypt(
                remoteNodeId,
                authData,
                sizeBytes);

            handshake.AuthPacket = new Packet(Bytes.Concat(sizeBytes, packetData));
            return(handshake.AuthPacket);
        }
        public void Agree(EncryptionHandshake handshake, Packet ack)
        {
            handshake.AckPacket = ack;

            try
            {
                byte[]     plaintextOld = _eciesCipher.Decrypt(_privateKey, ack.Data);
                AckMessage ackMessage   = _messageSerializationService.Deserialize <AckMessage>(plaintextOld);
                _logger.Debug($"Received ACK old");

                handshake.RemoteEphemeralPublicKey = ackMessage.EphemeralPublicKey;
                handshake.RecipientNonce           = ackMessage.Nonce;
            }
            catch (Exception)
            {
                byte[]         sizeData   = ack.Data.Slice(0, 2);
                byte[]         plaintext  = _eciesCipher.Decrypt(_privateKey, ack.Data.Slice(2), sizeData);
                AckEip8Message ackMessage = _messageSerializationService.Deserialize <AckEip8Message>(plaintext);
                _logger.Debug($"Received ACK v{ackMessage.Version}");

                handshake.RemoteEphemeralPublicKey = ackMessage.EphemeralPublicKey;
                handshake.RecipientNonce           = ackMessage.Nonce;
            }

            SetSecrets(handshake, EncryptionHandshakeRole.Initiator);
        }
Example #3
0
        private void SetSecrets(EncryptionHandshake handshake, HandshakeRole handshakeRole)
        {
            byte[] ephemeralSharedSecret = Proxy.EcdhSerialized(handshake.RemoteEphemeralPublicKey.Bytes, handshake.EphemeralPrivateKey.KeyBytes);
            byte[] nonceHash             = Keccak.Compute(Bytes.Concat(handshake.RecipientNonce, handshake.InitiatorNonce)).Bytes;
            byte[] sharedSecret          = Keccak.Compute(Bytes.Concat(ephemeralSharedSecret, nonceHash)).Bytes;
            byte[] token     = Keccak.Compute(sharedSecret).Bytes;
            byte[] aesSecret = Keccak.Compute(Bytes.Concat(ephemeralSharedSecret, sharedSecret)).Bytes;
            Array.Clear(sharedSecret, 0, sharedSecret.Length);                   // TODO: it was passed in the concat for Keccak so not good enough
            byte[] macSecret = Keccak.Compute(Bytes.Concat(ephemeralSharedSecret, aesSecret)).Bytes;
            Array.Clear(ephemeralSharedSecret, 0, ephemeralSharedSecret.Length); // TODO: it was passed in the concat for Keccak so not good enough
            handshake.Secrets           = new EncryptionSecrets();
            handshake.Secrets.Token     = token;
            handshake.Secrets.AesSecret = aesSecret;
            handshake.Secrets.MacSecret = macSecret;

            KeccakDigest mac1 = new KeccakDigest(MacBitsSize);

            mac1.BlockUpdate(macSecret.Xor(handshake.RecipientNonce), 0, macSecret.Length);
            mac1.BlockUpdate(handshake.AuthPacket.Data, 0, handshake.AuthPacket.Data.Length);

            KeccakDigest mac2 = new KeccakDigest(MacBitsSize);

            mac2.BlockUpdate(macSecret.Xor(handshake.InitiatorNonce), 0, macSecret.Length);
            mac2.BlockUpdate(handshake.AckPacket.Data, 0, handshake.AckPacket.Data.Length);

            if (handshakeRole == HandshakeRole.Initiator)
            {
                handshake.Secrets.EgressMac  = mac1;
                handshake.Secrets.IngressMac = mac2;
            }
            else
            {
                handshake.Secrets.EgressMac  = mac2;
                handshake.Secrets.IngressMac = mac1;
            }

            if (_logger.IsTrace)
            {
                _logger.Trace($"Agreed secrets with {handshake.RemoteNodeId}");
            }
            #if DEBUG
            if (_logger.IsTrace)
            {
                _logger.Trace($"{handshake.RemoteNodeId} ephemeral private key {handshake.EphemeralPrivateKey}");
                _logger.Trace($"{handshake.RemoteNodeId} initiator nonce {handshake.InitiatorNonce.ToHexString()}");
                _logger.Trace($"{handshake.RemoteNodeId} recipient nonce {handshake.RecipientNonce.ToHexString()}");
                _logger.Trace($"{handshake.RemoteNodeId} remote ephemeral public key {handshake.RemoteEphemeralPublicKey}");
                _logger.Trace($"{handshake.RemoteNodeId} remote public key {handshake.RemoteNodeId}");
                _logger.Trace($"{handshake.RemoteNodeId} auth packet {handshake.AuthPacket.Data.ToHexString()}");
                _logger.Trace($"{handshake.RemoteNodeId} ack packet {handshake.AckPacket.Data.ToHexString()}");
            }
            #endif
        }
Example #4
0
        public void Agree(EncryptionHandshake handshake, Packet ack)
        {
            handshake.AckPacket = ack;

            bool isOld = false;

            byte[] plainText = null;
            try
            {
                (isOld, plainText) = _eciesCipher.Decrypt(_privateKey, ack.Data);
            }
            catch (Exception ex)
            {
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Exception when decrypting agree {ex.Message}");
                }
            }

            if (isOld)
            {
                AckMessage ackMessage = _messageSerializationService.Deserialize <AckMessage>(plainText);
                if (_logger.IsTrace)
                {
                    _logger.Trace("Received ACK old");
                }

                handshake.RemoteEphemeralPublicKey = ackMessage.EphemeralPublicKey;
                handshake.RecipientNonce           = ackMessage.Nonce;
            }
            else
            {
                byte[] sizeData = ack.Data.Slice(0, 2);
                (_, plainText) = _eciesCipher.Decrypt(_privateKey, ack.Data.Slice(2), sizeData);

                AckEip8Message ackEip8Message = _messageSerializationService.Deserialize <AckEip8Message>(plainText);
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Received ACK v{ackEip8Message.Version}");
                }

                handshake.RemoteEphemeralPublicKey = ackEip8Message.EphemeralPublicKey;
                handshake.RecipientNonce           = ackEip8Message.Nonce;
            }

            SetSecrets(handshake, HandshakeRole.Initiator);
        }
Example #5
0
        public static void SetSecrets(EncryptionHandshake handshake, HandshakeRole handshakeRole)
        {
            Span <byte> tempConcat            = stackalloc byte[64];
            Span <byte> ephemeralSharedSecret = Proxy.EcdhSerialized(handshake.RemoteEphemeralPublicKey.Bytes, handshake.EphemeralPrivateKey.KeyBytes);
            Span <byte> nonceHash             = ValueKeccak.Compute(Bytes.Concat(handshake.RecipientNonce, handshake.InitiatorNonce)).BytesAsSpan;

            ephemeralSharedSecret.CopyTo(tempConcat.Slice(0, 32));
            nonceHash.CopyTo(tempConcat.Slice(32, 32));
            Span <byte> sharedSecret = ValueKeccak.Compute(tempConcat).BytesAsSpan;

//            byte[] token = Keccak.Compute(sharedSecret).Bytes;
            sharedSecret.CopyTo(tempConcat.Slice(32, 32));
            byte[] aesSecret = Keccak.Compute(tempConcat).Bytes;

            sharedSecret.Clear();
            aesSecret.CopyTo(tempConcat.Slice(32, 32));
            byte[] macSecret = Keccak.Compute(tempConcat).Bytes;

            ephemeralSharedSecret.Clear();
            handshake.Secrets = new EncryptionSecrets();
//            handshake.Secrets.Token = token;
            handshake.Secrets.AesSecret = aesSecret;
            handshake.Secrets.MacSecret = macSecret;

            KeccakDigest mac1 = new KeccakDigest(MacBitsSize);

            mac1.BlockUpdate(macSecret.Xor(handshake.RecipientNonce), 0, macSecret.Length);
            mac1.BlockUpdate(handshake.AuthPacket.Data, 0, handshake.AuthPacket.Data.Length);

            KeccakDigest mac2 = new KeccakDigest(MacBitsSize);

            mac2.BlockUpdate(macSecret.Xor(handshake.InitiatorNonce), 0, macSecret.Length);
            mac2.BlockUpdate(handshake.AckPacket.Data, 0, handshake.AckPacket.Data.Length);

            if (handshakeRole == HandshakeRole.Initiator)
            {
                handshake.Secrets.EgressMac  = mac1;
                handshake.Secrets.IngressMac = mac2;
            }
            else
            {
                handshake.Secrets.EgressMac  = mac2;
                handshake.Secrets.IngressMac = mac1;
            }
        }
Example #6
0
        public static void SetSecrets(EncryptionHandshake handshake, HandshakeRole handshakeRole)
        {
            byte[] ephemeralSharedSecret = Proxy.EcdhSerialized(handshake.RemoteEphemeralPublicKey.Bytes, handshake.EphemeralPrivateKey.KeyBytes);
            byte[] nonceHash             = Keccak.Compute(Bytes.Concat(handshake.RecipientNonce, handshake.InitiatorNonce)).Bytes;
            byte[] sharedSecret          = Keccak.Compute(Bytes.Concat(ephemeralSharedSecret, nonceHash)).Bytes;
            byte[] token     = Keccak.Compute(sharedSecret).Bytes;
            byte[] aesSecret = Keccak.Compute(Bytes.Concat(ephemeralSharedSecret, sharedSecret)).Bytes;
            Array.Clear(sharedSecret, 0, sharedSecret.Length);                   // TODO: it was passed in the concat for Keccak so not good enough
            byte[] macSecret = Keccak.Compute(Bytes.Concat(ephemeralSharedSecret, aesSecret)).Bytes;
            Array.Clear(ephemeralSharedSecret, 0, ephemeralSharedSecret.Length); // TODO: it was passed in the concat for Keccak so not good enough
            handshake.Secrets           = new EncryptionSecrets();
            handshake.Secrets.Token     = token;
            handshake.Secrets.AesSecret = aesSecret;
            handshake.Secrets.MacSecret = macSecret;

            KeccakDigest mac1 = new KeccakDigest(MacBitsSize);

            mac1.BlockUpdate(macSecret.Xor(handshake.RecipientNonce), 0, macSecret.Length);
            mac1.BlockUpdate(handshake.AuthPacket.Data, 0, handshake.AuthPacket.Data.Length);

            KeccakDigest mac2 = new KeccakDigest(MacBitsSize);

            mac2.BlockUpdate(macSecret.Xor(handshake.InitiatorNonce), 0, macSecret.Length);
            mac2.BlockUpdate(handshake.AckPacket.Data, 0, handshake.AckPacket.Data.Length);

            if (handshakeRole == HandshakeRole.Initiator)
            {
                handshake.Secrets.EgressMac  = mac1;
                handshake.Secrets.IngressMac = mac2;
            }
            else
            {
                handshake.Secrets.EgressMac  = mac2;
                handshake.Secrets.IngressMac = mac1;
            }
        }
Example #7
0
        public void Agree(EncryptionHandshake handshake, Packet ack)
        {
            handshake.AckPacket = ack;

            bool preEip8Format = false;

            byte[] plainText = null;
            try
            {
                (preEip8Format, plainText) = _eciesCipher.Decrypt(_privateKey, ack.Data);
            }
            catch (Exception ex)
            {
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Exception when decrypting agree {ex.Message}");
                }
            }

            if (preEip8Format)
            {
                AckMessage ackMessage = _messageSerializationService.Deserialize <AckMessage>(plainText);
                if (_logger.IsTrace)
                {
                    _logger.Trace("Received ACK old");
                }

                handshake.RemoteEphemeralPublicKey = ackMessage.EphemeralPublicKey;
                handshake.RecipientNonce           = ackMessage.Nonce;
            }
            else
            {
                byte[] sizeData = ack.Data.Slice(0, 2);
                (_, plainText) = _eciesCipher.Decrypt(_privateKey, ack.Data.Slice(2), sizeData);

                AckEip8Message ackEip8Message = _messageSerializationService.Deserialize <AckEip8Message>(plainText);
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Received ACK v{ackEip8Message.Version}");
                }

                handshake.RemoteEphemeralPublicKey = ackEip8Message.EphemeralPublicKey;
                handshake.RecipientNonce           = ackEip8Message.Nonce;
            }

            SetSecrets(handshake, HandshakeRole.Initiator);

            if (_logger.IsTrace)
            {
                _logger.Trace($"Agreed secrets with {handshake.RemoteNodeId}");
            }
#if DEBUG
            if (_logger.IsTrace)
            {
                _logger.Trace($"{handshake.RemoteNodeId} ephemeral private key {handshake.EphemeralPrivateKey}");
                _logger.Trace($"{handshake.RemoteNodeId} initiator nonce {handshake.InitiatorNonce.ToHexString()}");
                _logger.Trace($"{handshake.RemoteNodeId} recipient nonce {handshake.RecipientNonce.ToHexString()}");
                _logger.Trace($"{handshake.RemoteNodeId} remote ephemeral public key {handshake.RemoteEphemeralPublicKey}");
                _logger.Trace($"{handshake.RemoteNodeId} remote public key {handshake.RemoteNodeId}");
                _logger.Trace($"{handshake.RemoteNodeId} auth packet {handshake.AuthPacket.Data.ToHexString()}");
                _logger.Trace($"{handshake.RemoteNodeId} ack packet {handshake.AckPacket.Data.ToHexString()}");
            }
#endif
        }
Example #8
0
        public Packet Ack(EncryptionHandshake handshake, Packet auth)
        {
            handshake.AuthPacket = auth;

            AuthMessageBase authMessage;
            bool            preEip8Format = false;

            byte[] plainText = null;
            try
            {
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Trying to decrypt an old version of {nameof(AuthMessage)}");
                }
                (preEip8Format, plainText) = _eciesCipher.Decrypt(_privateKey, auth.Data);
            }
            catch (Exception ex)
            {
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Exception when decrypting ack {ex.Message}");
                }
            }

            if (preEip8Format)
            {
                authMessage = _messageSerializationService.Deserialize <AuthMessage>(plainText);
            }
            else
            {
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Trying to decrypt version 4 of {nameof(AuthEip8Message)}");
                }
                byte[] sizeData = auth.Data.Slice(0, 2);
                (_, plainText) = _eciesCipher.Decrypt(_privateKey, auth.Data.Slice(2), sizeData);
                authMessage    = _messageSerializationService.Deserialize <AuthEip8Message>(plainText);
            }

            var nodeId = authMessage.PublicKey;

            if (_logger.IsTrace)
            {
                _logger.Trace($"Received AUTH v{authMessage.Version} from {nodeId}");
            }

            handshake.RemoteNodeId        = nodeId;
            handshake.RecipientNonce      = _cryptoRandom.GenerateRandomBytes(32);
            handshake.EphemeralPrivateKey = _ephemeralGenerator.Generate();

            handshake.InitiatorNonce = authMessage.Nonce;
            byte[] staticSharedSecret = Proxy.EcdhSerialized(handshake.RemoteNodeId.Bytes, _privateKey.KeyBytes);
            byte[] forSigning         = staticSharedSecret.Xor(handshake.InitiatorNonce);

            handshake.RemoteEphemeralPublicKey = _ecdsa.RecoverPublicKey(authMessage.Signature, new Keccak(forSigning));

            byte[] data;
            if (preEip8Format)
            {
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Building an {nameof(AckMessage)}");
                }
                AckMessage ackMessage = new AckMessage();
                ackMessage.EphemeralPublicKey = handshake.EphemeralPrivateKey.PublicKey;
                ackMessage.Nonce = handshake.RecipientNonce;
                var ackData = _messageSerializationService.Serialize(ackMessage);

                data = _eciesCipher.Encrypt(handshake.RemoteNodeId, ackData, Array.Empty <byte>());
            }
            else
            {
                if (_logger.IsTrace)
                {
                    _logger.Trace($"Building an {nameof(AckEip8Message)}");
                }
                AckEip8Message ackMessage = new AckEip8Message();
                ackMessage.EphemeralPublicKey = handshake.EphemeralPrivateKey.PublicKey;
                ackMessage.Nonce = handshake.RecipientNonce;
                var ackData = _messageSerializationService.Serialize(ackMessage);

                int    size      = ackData.Length + 32 + 16 + 65; // data + MAC + IV + pub
                byte[] sizeBytes = size.ToBigEndianByteArray().Slice(2, 2);
                data = Bytes.Concat(sizeBytes, _eciesCipher.Encrypt(handshake.RemoteNodeId, ackData, sizeBytes));
            }

            handshake.AckPacket = new Packet(data);
            SetSecrets(handshake, HandshakeRole.Recipient);
            return(handshake.AckPacket);
        }
        public Packet Ack(EncryptionHandshake handshake, Packet auth)
        {
            handshake.AuthPacket = auth;

            AuthMessageBase authMessage;
            bool            isOld = false;

            try
            {
                _logger.Info($"Trying to decrypt an old version of {nameof(AuthMessage)}");
                byte[] plaintextOld = _eciesCipher.Decrypt(_privateKey, auth.Data);
                authMessage = _messageSerializationService.Deserialize <AuthMessage>(plaintextOld);
                isOld       = true;
            }
            catch (Exception)
            {
                _logger.Info($"Trying to decrypt version 4 of {nameof(AuthEip8Message)}");
                byte[] sizeData  = auth.Data.Slice(0, 2);
                byte[] plaintext = _eciesCipher.Decrypt(_privateKey, auth.Data.Slice(2), sizeData);
                authMessage = _messageSerializationService.Deserialize <AuthEip8Message>(plaintext);
            }

            var nodeId = new NodeId(authMessage.PublicKey);

            _logger.Debug($"Received AUTH v{authMessage.Version} from {nodeId}");

            handshake.RemoteNodeId        = nodeId;
            handshake.RecipientNonce      = _cryptoRandom.GenerateRandomBytes(32);
            handshake.EphemeralPrivateKey = new PrivateKey(_cryptoRandom.GenerateRandomBytes(32));

            handshake.InitiatorNonce = authMessage.Nonce;
            byte[] staticSharedSecret = BouncyCrypto.Agree(_privateKey, handshake.RemoteNodeId.PublicKey);
            byte[] forSigning         = staticSharedSecret.Xor(handshake.InitiatorNonce);

            handshake.RemoteEphemeralPublicKey = _signer.RecoverPublicKey(authMessage.Signature, new Keccak(forSigning));

            byte[] ackData;
            if (isOld) // what was the difference? shall I really include ephemeral public key in v4?
            {
                _logger.Debug($"Building an {nameof(AckMessage)}");
                AckMessage ackMessage = new AckMessage();
                ackMessage.EphemeralPublicKey = handshake.EphemeralPrivateKey.PublicKey;
                ackMessage.Nonce = handshake.RecipientNonce;
                ackData          = _messageSerializationService.Serialize(ackMessage);
            }
            else
            {
                _logger.Debug($"Building an {nameof(AckEip8Message)}");
                AckEip8Message ackMessage = new AckEip8Message();
                ackMessage.EphemeralPublicKey = handshake.EphemeralPrivateKey.PublicKey;
                ackMessage.Nonce = handshake.RecipientNonce;
                ackData          = _messageSerializationService.Serialize(ackMessage);
            }

            int size = ackData.Length + 32 + 16 + 65; // data + MAC + IV + pub

            byte[] sizeBytes  = size.ToBigEndianByteArray().Slice(2, 2);
            byte[] packetData = _eciesCipher.Encrypt(handshake.RemoteNodeId.PublicKey, ackData, sizeBytes);
            handshake.AckPacket = new Packet(Bytes.Concat(sizeBytes, packetData));
            SetSecrets(handshake, EncryptionHandshakeRole.Recipient);
            return(handshake.AckPacket);
        }