// =============================================================================
// Tesla.SecureConfig — First-boot secure provisioning  (assembly: TeslaSecureConfiguration)
// =============================================================================
// Reconstructed verbatim (ilspycmd) from the original proprietary
// TeslaSecureConfiguration.dll. Provides the Console-side pod provisioning
// protocol: UDP RQST/RPLY beacons, PBKDF2-from-passphrase key derivation, the
// OFB crypto-stream handshake (NegotiateCryptoStreams), and RSA session-key
// exchange. Previously consumed by the Console (and the Tesla.Contract client)
// as a vendored binary; now built from source as the single definition.
//
// The wire/crypto behaviour is load-bearing: it must stay byte-compatible with
// the pod-side counterpart (the Launcher's hand-written OFBDuplexStream /
// CryptoHelper in Launcher/SecureConfig.cs). Byte-identity against the original
// binary is asserted by SecureConfigCompatTests in the differential suite.
//
// NOTE: this is a faithful decompilation — local names and some control flow
// differ from the lost original source (e.g. the dead GetInterface(byte[])
// comparison loop is preserved as-is for behavioural fidelity).
// =============================================================================

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Timers;
using Microsoft.Win32;

namespace Tesla
{
	public class PodConfigurationClient : IDisposable
	{
		private static readonly Random sRandom = new Random();

		private static readonly char[] sPassphraseAlphabet = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ".ToCharArray();

		private Process mPasscodeDisplay;

		private string mPassphrase;

		private string mRequestId;

		private static TextWriter mLogger;

		public string Passphrase => mPassphrase;

		public string RequestId => mRequestId;

		public static TextWriter Logger
		{
			get
			{
				return mLogger;
			}
			set
			{
				mLogger = value;
			}
		}

		public PodConfigurationClient(uint passpharaseLength, uint requestIdLength)
		{
			mPassphrase = GenerateRandomString(passpharaseLength);
			mRequestId = GenerateRandomString(requestIdLength);
			mPasscodeDisplay = new Process();
			mPasscodeDisplay.StartInfo = new ProcessStartInfo("TeslaPasscodeDisplay.exe", $"{mRequestId} {mPassphrase}");
			mPasscodeDisplay.StartInfo.CreateNoWindow = false;
			mPasscodeDisplay.StartInfo.UseShellExecute = true;
			mPasscodeDisplay.StartInfo.WorkingDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			mPasscodeDisplay.Start();
		}

		private string GenerateRandomString(uint length)
		{
			char[] array = new char[length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = sPassphraseAlphabet[sRandom.Next(sPassphraseAlphabet.Length)];
			}
			return new string(array);
		}

		public byte[] WaitForEncryptionKey(ushort localPort, ushort remotePort, IPAddress identifyingAddress)
		{
			mLogger.WriteLine("Waiting for configuration. Request ID: {0}\tPassphrase: {1}", mRequestId, mPassphrase);
			mLogger.WriteLine("Configuring temporary ip address.");
			mLogger.Flush();
			string adapterName;
			byte[] @interface = GetInterface(identifyingAddress, out adapterName);
			try
			{
				ConfigureTempIp(adapterName);
			}
			catch (Exception innerException)
			{
				throw new Exception("Could not initalize temporary IP address.", innerException);
			}
			mLogger.WriteLine("Temp IP configured.");
			mLogger.Flush();
			byte[] array = PodConfigurationServer.GenerateKeyFromPassphrase(mPassphrase);
			mLogger.WriteLine("Setting up broadcast.");
			mLogger.Flush();
			byte[] bytes = Encoding.ASCII.GetBytes(mRequestId);
			byte[] array2 = new byte[@interface.Length + bytes.Length];
			@interface.CopyTo(array2, 0);
			bytes.CopyTo(array2, @interface.Length);
			UdpBeacon udpBeacon = new UdpBeacon(PodConfigurationServer.sMessageRequestID, array2, 10000.0, remotePort, null);
			udpBeacon.Start();
			mLogger.WriteLine("Broadcasting... waiting for packets.");
			mLogger.Flush();
			BasicConfigResponse basicConfigResponse = ReceiveUdpResponse(localPort, array);
			mLogger.WriteLine("Packets received.");
			mLogger.Flush();
			udpBeacon.Stop();
			mLogger.WriteLine("Attempting to configure final IP.");
			mLogger.Flush();
			try
			{
				SetNetworkProperties(adapterName, basicConfigResponse.Address, basicConfigResponse.Mask, basicConfigResponse.Gateway, basicConfigResponse.Dns, basicConfigResponse.HostName);
			}
			catch (Exception innerException2)
			{
				throw new Exception("Could not initalize final IP address.", innerException2);
			}
			mLogger.WriteLine("Waiting for console to connect.");
			mLogger.Flush();
			TcpListener tcpListener = new TcpListener(IPAddress.Any, localPort);
			tcpListener.Start();
			while (true)
			{
				TcpClient tcpClient = null;
				try
				{
					mLogger.WriteLine("Console connection received.  Negotiating...");
					mLogger.Flush();
					tcpClient = tcpListener.AcceptTcpClient();
					if (!PodConfigurationServer.NegotiateCryptoStreams(tcpClient.GetStream(), array, out var outStream, out var inStream))
					{
						continue;
					}
					BinaryWriter binaryWriter = new BinaryWriter(outStream);
					BinaryReader binaryReader = new BinaryReader(inStream);
					mLogger.WriteLine("Secure connection to console negotiated.");
					mLogger.Flush();
					RSACryptoServiceProvider rSACryptoServiceProvider = new RSACryptoServiceProvider();
					int dwKeySize = rSACryptoServiceProvider.KeySize;
					KeySizes[] legalKeySizes = rSACryptoServiceProvider.LegalKeySizes;
					foreach (KeySizes keySizes in legalKeySizes)
					{
						if (keySizes.MaxSize > rSACryptoServiceProvider.KeySize)
						{
							if (keySizes.MaxSize > 2048)
							{
								dwKeySize = 2048;
								break;
							}
							rSACryptoServiceProvider.KeySize = keySizes.MaxSize;
						}
					}
					mLogger.WriteLine("Sending console final key.");
					mLogger.Flush();
					rSACryptoServiceProvider = new RSACryptoServiceProvider(dwKeySize);
					binaryWriter.Write(rSACryptoServiceProvider.ToXmlString(includePrivateParameters: false));
					mLogger.WriteLine("Receiving console key.");
					mLogger.Flush();
					byte[] rgb = binaryReader.ReadBytes(binaryReader.ReadInt32());
					byte[] result = rSACryptoServiceProvider.Decrypt(rgb, fOAEP: false);
					mLogger.WriteLine("Console key received.");
					mLogger.Flush();
					return result;
				}
				finally
				{
					try
					{
						tcpClient.Close();
					}
					catch
					{
					}
					try
					{
						tcpListener.Stop();
					}
					catch
					{
					}
				}
			}
		}

		private static byte[] GetInterface(IPAddress identifyingAddress, out string adapterName)
		{
			NetworkInterface[] allNetworkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
			foreach (NetworkInterface networkInterface in allNetworkInterfaces)
			{
				foreach (UnicastIPAddressInformation unicastAddress in networkInterface.GetIPProperties().UnicastAddresses)
				{
					if (unicastAddress.Address == identifyingAddress)
					{
						adapterName = networkInterface.Name;
						return networkInterface.GetPhysicalAddress().GetAddressBytes();
					}
				}
			}
			NetworkInterface[] allNetworkInterfaces2 = NetworkInterface.GetAllNetworkInterfaces();
			foreach (NetworkInterface networkInterface2 in allNetworkInterfaces2)
			{
				if (networkInterface2.OperationalStatus == OperationalStatus.Up && networkInterface2.NetworkInterfaceType != NetworkInterfaceType.Loopback)
				{
					adapterName = networkInterface2.Name;
					return networkInterface2.GetPhysicalAddress().GetAddressBytes();
				}
			}
			throw new Exception("Could not find a valid network adapter.");
		}

		private static string GetInterface(byte[] identifyingMacAddress)
		{
			NetworkInterface[] allNetworkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
			int num = 0;
			if (num < allNetworkInterfaces.Length)
			{
				NetworkInterface networkInterface = allNetworkInterfaces[num];
				byte[] addressBytes = networkInterface.GetPhysicalAddress().GetAddressBytes();
				if (addressBytes.Length == identifyingMacAddress.Length)
				{
					for (int i = 0; i < addressBytes.Length; i++)
					{
						_ = addressBytes[i];
						_ = identifyingMacAddress[i];
					}
				}
				return networkInterface.Name;
			}
			NetworkInterface[] allNetworkInterfaces2 = NetworkInterface.GetAllNetworkInterfaces();
			foreach (NetworkInterface networkInterface2 in allNetworkInterfaces2)
			{
				if (networkInterface2.OperationalStatus == OperationalStatus.Up && networkInterface2.NetworkInterfaceType != NetworkInterfaceType.Loopback)
				{
					return networkInterface2.Name;
				}
			}
			throw new Exception("Could not find a valid network adapter.");
		}

		public static void SetNetworkProperties(byte[] macAddress, IPAddress address, IPAddress mask, IPAddress gateway, IPAddress dns, string hostName)
		{
			SetNetworkProperties(GetInterface(macAddress), address, mask, gateway, dns, hostName);
		}

		public static void SetNetworkProperties(string adapterName, IPAddress address, IPAddress mask, IPAddress gateway, IPAddress dns, string hostName)
		{
			if (adapterName == null)
			{
				throw new ArgumentNullException("adapterName");
			}
			if (adapterName.Length == 0)
			{
				throw new ArgumentOutOfRangeException("adapterName", "Adapter name can not be empty.");
			}
			if (address.AddressFamily != AddressFamily.InterNetwork)
			{
				throw new ArgumentOutOfRangeException("address", "Address must be an IPv4 address.");
			}
			if (mask.AddressFamily != AddressFamily.InterNetwork)
			{
				throw new ArgumentOutOfRangeException("mask", "Mask must be an IPv4 address.");
			}
			if (gateway.AddressFamily != AddressFamily.InterNetwork)
			{
				throw new ArgumentOutOfRangeException("gateway", "Default gateway must be an IPv4 address.");
			}
			if (dns.AddressFamily != AddressFamily.InterNetwork)
			{
				throw new ArgumentOutOfRangeException("dns", "DNS server address must be an IPv4 address.");
			}
			mLogger.WriteLine(string.Format("Setting data for adapter \"{0}\": IP {1}, Mask {2}, Gateway {3}, DNS {4}, Host {5}.", adapterName, address.ToString(), mask.ToString(), gateway.Equals(IPAddress.Any) ? "none" : gateway.ToString(), dns.Equals(IPAddress.Any) ? "none" : dns.ToString(), string.IsNullOrEmpty(hostName) ? "no change" : hostName));
			mLogger.Flush();
			using (Process process = new Process())
			{
				process.StartInfo.FileName = "netsh";
				process.StartInfo.Arguments = string.Format("interface ip set address \"{0}\" static {1} {2} {3}", adapterName, address, mask, gateway.Equals(IPAddress.Any) ? "none" : (gateway.ToString() + " 1"));
				process.Start();
				process.WaitForExit();
				if (process.ExitCode != 0)
				{
					throw new Exception("Could not initalize IP address.");
				}
			}
			mLogger.WriteLine("IP Set");
			mLogger.Flush();
			using (Process process2 = new Process())
			{
				process2.StartInfo.FileName = "netsh";
				process2.StartInfo.Arguments = string.Format("interface ip set dns \"{0}\" static {1}", adapterName, dns.Equals(IPAddress.Any) ? "none" : dns.ToString());
				process2.Start();
				process2.WaitForExit();
				if (process2.ExitCode != 0)
				{
					throw new Exception("Could not set DNS server.");
				}
			}
			mLogger.WriteLine("DNS set.");
			mLogger.Flush();
			if (string.IsNullOrEmpty(hostName))
			{
				return;
			}
			using (RegistryKey registryKey = Registry.LocalMachine.OpenSubKey("SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ComputerName", writable: true))
			{
				try
				{
					registryKey.SetValue("ComputerName", hostName, RegistryValueKind.String);
				}
				catch (Exception innerException)
				{
					throw new Exception("Could not set host name.", innerException);
				}
				finally
				{
					registryKey.Close();
				}
			}
			using (RegistryKey registryKey2 = Registry.LocalMachine.OpenSubKey("SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters", writable: true))
			{
				try
				{
					registryKey2.SetValue("NV Hostname", hostName, RegistryValueKind.String);
				}
				catch (Exception innerException2)
				{
					throw new Exception("Could not set host name.", innerException2);
				}
				finally
				{
					registryKey2.Close();
				}
			}
			mLogger.WriteLine("Host set.");
			mLogger.Flush();
		}

		private static void ConfigureTempIp(string adapterName)
		{
			byte[] array = new byte[4];
			sRandom.NextBytes(array);
			array[0] = 172;
			array[1] = (byte)((array[1] & 0xFu) | 0x10u);
			IPAddress address = new IPAddress(array);
			IPAddress mask = IPAddress.Parse("255.240.0.0");
			SetNetworkProperties(adapterName, address, mask, IPAddress.Any, IPAddress.Any, null);
		}

		private static BasicConfigResponse ReceiveUdpResponse(ushort localPort, byte[] weakAesKey)
		{
			UdpBeaconListener udpBeaconListener = new UdpBeaconListener(PodConfigurationServer.sMessageReplyID, localPort, weakAesKey);
			BasicConfigResponse basicConfigResponse;
			do
			{
				basicConfigResponse = new BasicConfigResponse(udpBeaconListener.Receive());
			}
			while (basicConfigResponse == null);
			return basicConfigResponse;
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (disposing && mPasscodeDisplay != null && mPasscodeDisplay.Responding)
			{
				mPasscodeDisplay.Kill();
			}
		}
	}
	public delegate void ConfigurationRequestReceivedDelegate(byte[] macAddress, string reqeustId);
	public class PodConfigurationServer
	{
		internal static readonly byte[] sMessageRequestID = Encoding.UTF8.GetBytes("RQST");

		internal static readonly byte[] sMessageReplyID = Encoding.UTF8.GetBytes("RPLY");

		private static readonly byte[] sMessageConfID = Encoding.UTF8.GetBytes("CONF");

		private static readonly byte[] mPassphraseSalt = new byte[32]
		{
			23, 171, 81, 217, 236, 209, 212, 116, 169, 9,
			74, 52, 39, 251, 31, 242, 222, 196, 249, 241,
			166, 216, 158, 218, 21, 17, 71, 101, 50, 231,
			231, 239
		};

		private readonly ushort mLocalPort;

		private readonly ushort mRemotePort;

		private readonly ConfigurationRequestReceivedDelegate mRequestDelegate;

		private UdpBeaconListener mBeaconListener;

		private List<long> mActiveConfigPods = new List<long>();

		internal static byte[] GenerateKeyFromPassphrase(string passphrase)
		{
			return new Rfc2898DeriveBytes(passphrase, mPassphraseSalt, 1000).GetBytes(32);
		}

		public static bool NegotiateCryptoStreams(NetworkStream clientStream, byte[] key, out Stream outStream, out Stream inStream)
		{
			outStream = null;
			inStream = null;
			Rijndael rijndael = Rijndael.Create();
			rijndael.Mode = CipherMode.ECB;
			rijndael.Key = key;
			rijndael.GenerateIV();
			clientStream.Write(rijndael.IV, 0, rijndael.IV.Length);
			inStream = new OFBCryptoStream(clientStream, rijndael.CreateEncryptor(), CryptoStreamMode.Read, rijndael.IV);
			byte[] array = new byte[rijndael.IV.Length];
			for (int i = 0; i < array.Length; i += clientStream.Read(array, i, array.Length - i))
			{
			}
			rijndael.IV = array;
			outStream = new OFBCryptoStream(clientStream, rijndael.CreateEncryptor(), CryptoStreamMode.Write, array);
			outStream.Write(sMessageConfID, 0, sMessageConfID.Length);
			byte[] array2 = new byte[sMessageConfID.Length];
			for (int j = 0; j < array2.Length; j += inStream.Read(array2, j, array2.Length - j))
			{
			}
			for (int k = 0; k < array2.Length; k++)
			{
				if (array2[k] != sMessageConfID[k])
				{
					return false;
				}
			}
			return true;
		}

		public PodConfigurationServer(ushort localPort, ushort remotePort, ConfigurationRequestReceivedDelegate requestDelegate)
		{
			if (requestDelegate == null)
			{
				throw new ArgumentNullException("requestDelegate");
			}
			mLocalPort = localPort;
			mRemotePort = remotePort;
			mRequestDelegate = requestDelegate;
			mBeaconListener = new UdpBeaconListener(sMessageRequestID, mLocalPort, null);
			mBeaconListener.BeginReceive(BeaconReceived, null);
		}

		private void BeaconReceived(IAsyncResult ar)
		{
			byte[] array;
			try
			{
				array = mBeaconListener.EndReceive(ar);
			}
			catch
			{
				mBeaconListener = new UdpBeaconListener(sMessageRequestID, mLocalPort, null);
				mBeaconListener.BeginReceive(BeaconReceived, null);
				return;
			}
			mBeaconListener.BeginReceive(BeaconReceived, null);
			byte[] array2 = new byte[6];
			byte[] array3 = new byte[array.Length - array2.Length];
			Buffer.BlockCopy(array, 0, array2, 0, array2.Length);
			Buffer.BlockCopy(array, array2.Length, array3, 0, array3.Length);
			byte[] array4 = new byte[8];
			Array.Copy(array2, array4, array2.Length);
			long item = BitConverter.ToInt64(array4, 0);
			lock (mActiveConfigPods)
			{
				if (mActiveConfigPods.Contains(item))
				{
					return;
				}
				mActiveConfigPods.Add(item);
			}
			try
			{
				mRequestDelegate(array2, Encoding.ASCII.GetString(array3));
			}
			finally
			{
				lock (mActiveConfigPods)
				{
					mActiveConfigPods.Remove(item);
				}
			}
		}

		public byte[] SendEncryptionKey(string passphrase, IPAddress ipAddress, IPAddress mask, IPAddress gateway, IPAddress dns, string hostName, TimeSpan timeout)
		{
			DateTime dateTime = DateTime.Now + timeout;
			byte[] array = GenerateKeyFromPassphrase(passphrase);
			UdpBeacon udpBeacon = new UdpBeacon(sMessageReplyID, new BasicConfigResponse(ipAddress, mask, gateway, dns, hostName).ToBytes(), 10000.0, mRemotePort, array);
			udpBeacon.Start();
			try
			{
				do
				{
					TcpClient tcpClient = null;
					try
					{
						tcpClient = new TcpClient(AddressFamily.InterNetwork);
						tcpClient.Connect(new IPEndPoint(ipAddress, mRemotePort));
						if (NegotiateCryptoStreams(tcpClient.GetStream(), array, out var outStream, out var inStream))
						{
							BinaryWriter binaryWriter = new BinaryWriter(outStream);
							BinaryReader binaryReader = new BinaryReader(inStream);
							RSACryptoServiceProvider rSACryptoServiceProvider = new RSACryptoServiceProvider();
							rSACryptoServiceProvider.FromXmlString(binaryReader.ReadString());
							Rijndael rijndael = Rijndael.Create();
							rijndael.KeySize = 256;
							rijndael.GenerateKey();
							byte[] key = rijndael.Key;
							byte[] array2 = rSACryptoServiceProvider.Encrypt(key, fOAEP: false);
							binaryWriter.Write(array2.Length);
							binaryWriter.Write(array2);
							return key;
						}
					}
					catch (SocketException)
					{
					}
					finally
					{
						try
						{
							tcpClient.Close();
						}
						catch
						{
						}
					}
				}
				while (DateTime.Now < dateTime);
				throw new TimeoutException();
			}
			finally
			{
				udpBeacon.Stop();
			}
		}
	}
	public class UdpBeaconListener
	{
		private class InternalAsyncResult : IAsyncResult
		{
			public AsyncCallback UserCallback;

			public IAsyncResult UdpAsyncResult;

			public Exception ThrownException;

			public byte[] ReceivedMessage;

			private object mState;

			public EventWaitHandle WaitHandle = new EventWaitHandle(initialState: false, EventResetMode.ManualReset);

			private bool mIsCompleted;

			public object AsyncState => mState;

			public WaitHandle AsyncWaitHandle => WaitHandle;

			public bool CompletedSynchronously => false;

			public bool IsCompleted
			{
				get
				{
					return mIsCompleted;
				}
				set
				{
					mIsCompleted = value;
				}
			}

			public InternalAsyncResult(AsyncCallback userCallback, object userState)
			{
				UserCallback = userCallback;
				mState = userState;
			}
		}

		private readonly byte[] mHeader;

		private readonly Rijndael mAes;

		private readonly SHA1 mSha1;

		private UdpClient mClient;

		public UdpBeaconListener(byte[] header, ushort port, byte[] encryptionKey)
		{
			mHeader = (byte[])header.Clone();
			mClient = new UdpClient(port);
			mClient.EnableBroadcast = true;
			if (encryptionKey != null)
			{
				mAes = UdpBeacon.CreateRijndael(encryptionKey);
				mSha1 = SHA1.Create();
			}
		}

		public IAsyncResult BeginReceive(AsyncCallback requestCallback, object state)
		{
			InternalAsyncResult internalAsyncResult = new InternalAsyncResult(requestCallback, state);
			internalAsyncResult.UdpAsyncResult = mClient.BeginReceive(InternalEndReceive, internalAsyncResult);
			return internalAsyncResult;
		}

		public byte[] EndReceive(IAsyncResult ar)
		{
			InternalAsyncResult internalAsyncResult = (InternalAsyncResult)ar;
			internalAsyncResult.AsyncWaitHandle.WaitOne();
			if (internalAsyncResult.ThrownException != null)
			{
				throw internalAsyncResult.ThrownException;
			}
			return internalAsyncResult.ReceivedMessage;
		}

		public byte[] Receive()
		{
			return EndReceive(BeginReceive(null, null));
		}

		private void InternalEndReceive(IAsyncResult udpAr)
		{
			InternalAsyncResult internalAsyncResult = (InternalAsyncResult)udpAr.AsyncState;
			ReceiveAndTransform(internalAsyncResult);
			if (internalAsyncResult.ThrownException != null || internalAsyncResult.ReceivedMessage != null)
			{
				internalAsyncResult.IsCompleted = true;
				internalAsyncResult.WaitHandle.Set();
				if (internalAsyncResult.UserCallback != null)
				{
					internalAsyncResult.UserCallback(internalAsyncResult);
				}
			}
			else
			{
				internalAsyncResult.UdpAsyncResult = mClient.BeginReceive(InternalEndReceive, internalAsyncResult);
			}
		}

		private void ReceiveAndTransform(InternalAsyncResult ar)
		{
			IPEndPoint remoteEP = new IPEndPoint(0L, 0);
			byte[] array;
			try
			{
				array = mClient.EndReceive(ar.UdpAsyncResult, ref remoteEP);
			}
			catch (Exception thrownException)
			{
				Exception ex = (ar.ThrownException = thrownException);
				return;
			}
			finally
			{
				ar.UdpAsyncResult = null;
			}
			try
			{
				if (array.Length < mHeader.Length)
				{
					return;
				}
				for (int i = 0; i < mHeader.Length; i++)
				{
					if (array[i] != mHeader[i])
					{
						return;
					}
				}
				if (mAes == null)
				{
					ar.ReceivedMessage = new byte[array.Length - mHeader.Length];
					Buffer.BlockCopy(array, mHeader.Length, ar.ReceivedMessage, 0, ar.ReceivedMessage.Length);
					return;
				}
				byte[] array2 = new byte[mAes.IV.Length];
				if (array.Length < mHeader.Length + array2.Length)
				{
					return;
				}
				Buffer.BlockCopy(array, mHeader.Length, array2, 0, array2.Length);
				ICryptoTransform transform = mAes.CreateDecryptor(mAes.Key, array2);
				MemoryStream memoryStream = new MemoryStream();
				CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write);
				cryptoStream.Write(array, mHeader.Length + array2.Length, array.Length - (mHeader.Length + array2.Length));
				cryptoStream.FlushFinalBlock();
				byte[] array3 = memoryStream.ToArray();
				int num = array3.Length - mSha1.HashSize / 8;
				if (num <= 0)
				{
					return;
				}
				byte[] array4 = mSha1.ComputeHash(array3, 0, num);
				for (int j = 0; j < array4.Length; j++)
				{
					if (array3[j + num] != array4[j])
					{
						return;
					}
				}
				ar.ReceivedMessage = new byte[num];
				Buffer.BlockCopy(array3, 0, ar.ReceivedMessage, 0, num);
			}
			catch
			{
			}
		}
	}
	public class UdpBeacon
	{
		private readonly byte[] mHeader;

		private readonly byte[] mMessage;

		private readonly double mMilliseconds;

		private readonly IPEndPoint mBroadcast;

		private readonly object mSynchronizer;

		private readonly Rijndael mAes;

		private readonly SHA1 mSha1;

		private UdpClient mClient;

		private System.Timers.Timer mTimer;

		internal static Rijndael CreateRijndael(byte[] encryptionKey)
		{
			Rijndael rijndael = Rijndael.Create();
			rijndael.Key = (byte[])encryptionKey.Clone();
			return rijndael;
		}

		public UdpBeacon(byte[] header, byte[] message, double milliseconds, ushort port, byte[] encryptionKey)
		{
			mHeader = (byte[])header.Clone();
			mMessage = (byte[])message.Clone();
			if (encryptionKey != null)
			{
				mAes = CreateRijndael(encryptionKey);
				mSha1 = SHA1.Create();
			}
			mMilliseconds = milliseconds;
			mBroadcast = new IPEndPoint(IPAddress.Broadcast, port);
			mSynchronizer = new object();
		}

		public void Start()
		{
			lock (mSynchronizer)
			{
				Initalize();
				BroadcastBeacon(allowReset: false);
				mTimer.Start();
			}
		}

		public void Stop()
		{
			lock (mSynchronizer)
			{
				if (mTimer != null)
				{
					mTimer.Stop();
				}
				mTimer = null;
				if (mClient != null)
				{
					mClient.Close();
				}
				mClient = null;
			}
		}

		private void Initalize()
		{
			try
			{
				Stop();
			}
			catch
			{
			}
			mClient = new UdpClient();
			mClient.EnableBroadcast = true;
			mTimer = new System.Timers.Timer(mMilliseconds);
			mTimer.Elapsed += mTimer_Elapsed;
			mTimer.AutoReset = true;
		}

		private void mTimer_Elapsed(object sender, ElapsedEventArgs e)
		{
			lock (mSynchronizer)
			{
				BroadcastBeacon(allowReset: true);
			}
		}

		private void BroadcastBeacon(bool allowReset)
		{
			try
			{
				List<byte> list = new List<byte>(mHeader);
				if (mAes == null)
				{
					list.AddRange(mMessage);
				}
				else
				{
					mAes.GenerateIV();
					list.AddRange(mAes.IV);
					byte[] array = mSha1.ComputeHash(mMessage);
					byte[] array2 = new byte[mMessage.Length + array.Length];
					mMessage.CopyTo(array2, 0);
					array.CopyTo(array2, mMessage.Length);
					MemoryStream memoryStream = new MemoryStream();
					CryptoStream cryptoStream = new CryptoStream(memoryStream, mAes.CreateEncryptor(), CryptoStreamMode.Write);
					cryptoStream.Write(array2, 0, array2.Length);
					cryptoStream.FlushFinalBlock();
					list.AddRange(memoryStream.ToArray());
				}
				byte[] array3 = list.ToArray();
				mClient.Send(array3, array3.Length, mBroadcast);
			}
			catch
			{
				if (allowReset)
				{
					Stop();
					Initalize();
					Start();
				}
			}
		}
	}
}
namespace System.Security.Cryptography
{
	public class OFBCryptoStream : Stream
	{
		private Stream mStream;

		private ICryptoTransform mTransform;

		private CryptoStreamMode mStreamMode;

		private byte[] mOutputBuffer;

		private byte[] mOutputBufferAlternate;

		private int mOutputBufferPosition;

		public override bool CanRead => mStreamMode == CryptoStreamMode.Read;

		public override bool CanSeek => false;

		public override bool CanWrite => mStreamMode == CryptoStreamMode.Write;

		public override long Length
		{
			get
			{
				throw new NotSupportedException();
			}
		}

		public override long Position
		{
			get
			{
				throw new NotSupportedException();
			}
			set
			{
				throw new NotSupportedException();
			}
		}

		public OFBCryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode, byte[] IV)
		{
			if (transform.InputBlockSize != transform.OutputBlockSize)
			{
				throw new ArgumentException("transform");
			}
			if (!transform.CanTransformMultipleBlocks)
			{
				throw new ArgumentException("transform");
			}
			if (mode != 0 && mode != CryptoStreamMode.Write)
			{
				throw new ArgumentOutOfRangeException("mode");
			}
			if ((mode == CryptoStreamMode.Read && !stream.CanRead) || (mode != CryptoStreamMode.Write && !stream.CanWrite))
			{
				throw new ArgumentException("mode");
			}
			mStream = stream;
			mTransform = transform;
			mStreamMode = mode;
			mOutputBuffer = IV;
			mOutputBufferAlternate = new byte[mTransform.OutputBlockSize];
			NextBuffer();
		}

		private void NextBuffer()
		{
			mTransform.TransformBlock(mOutputBuffer, 0, mOutputBuffer.Length, mOutputBufferAlternate, 0);
			byte[] array = mOutputBuffer;
			mOutputBuffer = mOutputBufferAlternate;
			mOutputBufferAlternate = array;
			mOutputBufferPosition = 0;
		}

		public override void Flush()
		{
			mStream.Flush();
		}

		public override long Seek(long offset, SeekOrigin origin)
		{
			throw new NotSupportedException();
		}

		public override void SetLength(long value)
		{
			throw new NotSupportedException();
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
			if (!CanRead)
			{
				throw new NotSupportedException();
			}
			byte[] array = new byte[count];
			int num = mStream.Read(array, 0, count);
			int num2 = 0;
			while (num2 < num)
			{
				if (mOutputBufferPosition >= mOutputBuffer.Length)
				{
					NextBuffer();
				}
				while (mOutputBufferPosition < mOutputBuffer.Length && num2 < num)
				{
					buffer[offset++] = (byte)(mOutputBuffer[mOutputBufferPosition++] ^ array[num2++]);
				}
			}
			return num;
		}

		public override void Write(byte[] buffer, int offset, int count)
		{
			if (!CanWrite)
			{
				throw new NotSupportedException();
			}
			byte[] array = new byte[count];
			int num = 0;
			while (num < count)
			{
				if (mOutputBufferPosition >= mOutputBuffer.Length)
				{
					NextBuffer();
				}
				while (mOutputBufferPosition < mOutputBuffer.Length && num < count)
				{
					array[num++] = (byte)(mOutputBuffer[mOutputBufferPosition++] ^ buffer[offset++]);
				}
			}
			mStream.Write(array, 0, count);
		}
	}
}
namespace Tesla
{
	public class BasicConfigResponse
	{
		private IPAddress mAddress;

		private IPAddress mMask;

		private IPAddress mGateway;

		private IPAddress mDns;

		private string mHostName;

		public IPAddress Address => mAddress;

		public IPAddress Mask => mMask;

		public IPAddress Gateway => mGateway;

		public IPAddress Dns => mDns;

		public string HostName => mHostName;

		public BasicConfigResponse(IPAddress address, IPAddress mask, IPAddress gateway, IPAddress dns, string hostName)
		{
			if (address.AddressFamily != AddressFamily.InterNetwork)
			{
				throw new ArgumentOutOfRangeException("address", "Address must be an IPv4 address.");
			}
			if (mask.AddressFamily != AddressFamily.InterNetwork)
			{
				throw new ArgumentOutOfRangeException("mask", "Address mask must be an IPv4 address.");
			}
			if (gateway.AddressFamily != AddressFamily.InterNetwork)
			{
				throw new ArgumentOutOfRangeException("gateway", "Default gateway must be an IPv4 address.");
			}
			if (dns.AddressFamily != AddressFamily.InterNetwork)
			{
				throw new ArgumentOutOfRangeException("dns", "DNS server must be an IPv4 address.");
			}
			if (hostName == null)
			{
				throw new ArgumentNullException("hostName");
			}
			mAddress = address;
			mMask = mask;
			mGateway = gateway;
			mDns = dns;
			mHostName = hostName;
		}

		public byte[] ToBytes()
		{
			List<byte> list = new List<byte>(8);
			list.AddRange(mAddress.GetAddressBytes());
			list.AddRange(mMask.GetAddressBytes());
			list.AddRange(mGateway.GetAddressBytes());
			list.AddRange(mDns.GetAddressBytes());
			list.AddRange(Encoding.UTF8.GetBytes(mHostName));
			return list.ToArray();
		}

		public BasicConfigResponse(byte[] data)
		{
			byte[] array = new byte[4];
			Buffer.BlockCopy(data, 0, array, 0, array.Length);
			mAddress = new IPAddress(array);
			Buffer.BlockCopy(data, 4, array, 0, array.Length);
			mMask = new IPAddress(array);
			Buffer.BlockCopy(data, 8, array, 0, array.Length);
			mGateway = new IPAddress(array);
			Buffer.BlockCopy(data, 12, array, 0, array.Length);
			mDns = new IPAddress(array);
			mHostName = Encoding.UTF8.GetString(data, 16, data.Length - 16);
		}
	}
}
