Exemplo n.º 1
0
        const ushort Magic16_responderToRequester = 0x60C1; // is used to validate decrypted data

        /// <summary>
        /// when sending ACK1
        /// </summary>
        public byte[] Encrypt_ack1_ToResponderTxParametersEncrypted_AtResponder_DeriveSharedDhSecret(Logger logger, RegisterRequestPacket req, RegisterAck1Packet ack1, ConnectionToNeighbor neighbor)
        {
            IPEndPoint localResponderEndpoint;

            if (neighbor != null)
            {
                localResponderEndpoint = neighbor.LocalEndpoint;
            }
            else
            {
                localResponderEndpoint = req.EpEndpoint;
            }

            if (localResponderEndpoint.Address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork)
            {
                throw new NotImplementedException();
            }

            SharedDhSecret = _engine.CryptoLibrary.DeriveEcdh25519SharedSecret(LocalEcdhe25519PrivateKey, req.RequesterEcdhePublicKey.Ecdh25519PublicKey);

            #region key, iv
            BinaryProcedures.CreateBinaryWriter(out var ms, out var writer);

            req.GetSharedSignedFields(writer, true);
            ack1.GetSharedSignedFields(writer, false, false);

            var iv = _engine.CryptoLibrary.GetHashSHA256(ms.ToArray()).Take(16).ToArray();;
            ms.Write(SharedDhSecret, 0, SharedDhSecret.Length);

            var aesKey = _engine.CryptoLibrary.GetHashSHA256(ms.ToArray()); // here SHA256 is used as KDF, together with common fields from packets, including both ECDH public keys and timestamp
            #endregion

            // encode localRxParameters
            BinaryProcedures.CreateBinaryWriter(out var msRxParameters, out var wRxParameters);
            BinaryProcedures.EncodeIPEndPoint(wRxParameters, localResponderEndpoint); // max 19
            LocalNeighborToken32.Encode(wRxParameters);                               // +4   max 23
            _engine.LocalNatBehaviour.Encode(wRxParameters);                          // +2 max 25

            if (logger.WriteToLog_detail_enabled)
            {
                logger.WriteToLog_detail($"encrypting local responder endpoint={localResponderEndpoint}, localNeighborToken={LocalNeighborToken32} into ACK1");
            }

            wRxParameters.Write(Magic16_responderToRequester);    // +2 max 27
            var bytesRemaining = RegisterAck1Packet.ToResponderTxParametersEncryptedLength - (int)msRxParameters.Length;

            wRxParameters.Write(_engine.CryptoLibrary.GetRandomBytes(bytesRemaining));

            var localRxParametersDecrypted = msRxParameters.ToArray(); // total 32 bytes = RegisterAck1Packet.ToResponderTxParametersEncryptedLength
            var localRxParametersEncrypted = new byte[localRxParametersDecrypted.Length];
            _engine.CryptoLibrary.ProcessAesCbcBlocks(true, aesKey, iv, localRxParametersDecrypted, localRxParametersEncrypted);

            if (localRxParametersEncrypted.Length != RegisterAck1Packet.ToResponderTxParametersEncryptedLength)
            {
                throw new Exception();
            }
            return(localRxParametersEncrypted);
        }
Exemplo n.º 2
0
        /// <summary>
        /// when sending ACK
        /// </summary>
        public byte[] Encrypt_ack2_ToRequesterTxParametersEncrypted_AtRequester(Logger logger, RegisterRequestPacket req, RegisterAck1Packet ack1, RegisterAck2Packet ack2)
        {
            if (SharedDhSecret == null)
            {
                throw new InvalidOperationException();
            }

            #region aes key, iv
            PacketProcedures.CreateBinaryWriter(out var ms, out var writer);
            req.GetSharedSignedFields(writer, true);
            ack1.GetSharedSignedFields(writer, true, true);
            ack2.GetSharedSignedFields(writer, false, false);

            var iv = _engine.CryptoLibrary.GetHashSHA256(ms.ToArray()).Take(16).ToArray();

            ms.Write(SharedDhSecret, 0, SharedDhSecret.Length);
            var aesKey = _engine.CryptoLibrary.GetHashSHA256(ms.ToArray()); // here SHA256 is used as KDF, together with common fields from packets, including both ECDH public keys and timestamp
            #endregion

            // encode localRxParameters
            PacketProcedures.CreateBinaryWriter(out var msRxParameters, out var wRxParameters);
            PacketProcedures.EncodeIPEndPoint(wRxParameters, LocalEndpoint); // max 19
            LocalNeighborToken32.Encode(wRxParameters);                      // +4 max 23
            if (logger.WriteToLog_detail_enabled)
            {
                logger.WriteToLog_detail($"encrypting local requester endpoint={LocalEndpoint}, localNeighborToken={LocalNeighborToken32} into ACK2");
            }
            wRxParameters.Write(Magic16_ipv4_requesterToResponder); // +2 max 25
            var bytesRemaining = RegisterAck2Packet.ToRequesterTxParametersEncryptedLength - (int)msRxParameters.Length;
            wRxParameters.Write(_engine.CryptoLibrary.GetRandomBytes(bytesRemaining));

            var localRxParametersDecrypted = msRxParameters.ToArray();
            var localRxParametersEncrypted = new byte[localRxParametersDecrypted.Length];
            _engine.CryptoLibrary.ProcessAesCbcBlocks(true, aesKey, iv, localRxParametersDecrypted, localRxParametersEncrypted);

            if (localRxParametersEncrypted.Length != RegisterAck2Packet.ToRequesterTxParametersEncryptedLength)
            {
                throw new Exception();
            }
            return(localRxParametersEncrypted);
        }