145 lines
4.5 KiB
C#
145 lines
4.5 KiB
C#
using System;
|
|
using System.Text;
|
|
using System.Security.Cryptography;
|
|
|
|
namespace Inputs.ComSystem
|
|
{
|
|
/// <summary>
|
|
/// Ñòàòè÷åñêèé êëàññ äëÿ AES-256 ECB øèôðîâàíèÿ/äåøèôðîâàíèÿ
|
|
/// Èñïîëüçóåòñÿ äëÿ äâîéíîãî ðóêîïîæàòèÿ ñ ïëàòàìè ESP32
|
|
/// </summary>
|
|
public static class AESCrypto
|
|
{
|
|
// Çàøèôðîâàííûé AES êëþ÷ (XOR 0x37) - êàê â ïðîøèâêå ïëàòû
|
|
private static readonly byte[] AES_ENCRYPTED_KEY = new byte[]
|
|
{
|
|
0x69, 0x40, 0xC7, 0x0E, 0xF2, 0xC7, 0x45, 0x70,
|
|
0x72, 0xCD, 0x28, 0x58, 0x99, 0x8F, 0x73, 0xA8,
|
|
0x5F, 0x5F, 0xED, 0xB4, 0xC1, 0x62, 0xB4, 0x24,
|
|
0xAC, 0xD7, 0xA3, 0xD6, 0xD8, 0x0B, 0x50, 0x37
|
|
};
|
|
|
|
private static byte[] _aesKey32;
|
|
private static readonly object _lockObject = new object();
|
|
|
|
/// <summary>
|
|
/// Èíèöèàëèçàöèÿ AES êëþ÷à (ðàñøèôðîâêà ÷åðåç XOR 0x37)
|
|
/// Âûçûâàåòñÿ àâòîìàòè÷åñêè ïðè ïåðâîì èñïîëüçîâàíèè
|
|
/// </summary>
|
|
private static void InitCrypto()
|
|
{
|
|
lock (_lockObject)
|
|
{
|
|
if (_aesKey32 == null)
|
|
{
|
|
_aesKey32 = new byte[32];
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
_aesKey32[i] = (byte)(AES_ENCRYPTED_KEY[i] ^ 0x37);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Øèôðóåò 16-áàéòíûé áëîê (32 hex ñèìâîëà)
|
|
/// </summary>
|
|
public static string EncryptHexBlock16(string plainHex)
|
|
{
|
|
InitCrypto();
|
|
byte[] plain = HexToBytes(plainHex);
|
|
if (plain.Length != 16)
|
|
throw new ArgumentException("Plain must be 16 bytes (32 hex chars)");
|
|
|
|
byte[] cipher = Aes256EcbEncrypt(plain);
|
|
return BytesToHex(cipher);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ðàñøèôðîâûâàåò 16-áàéòíûé áëîê (32 hex ñèìâîëà)
|
|
/// </summary>
|
|
public static string DecryptHexBlock16(string cipherHex)
|
|
{
|
|
InitCrypto();
|
|
byte[] cipher = HexToBytes(cipherHex);
|
|
if (cipher.Length != 16)
|
|
throw new ArgumentException("Cipher must be 16 bytes (32 hex chars)");
|
|
|
|
byte[] plain = Aes256EcbDecrypt(cipher);
|
|
return BytesToHex(plain);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ãåíåðèðóåò ñëó÷àéíûé 16-áàéòíûé áëîê (32 hex ñèìâîëà)
|
|
/// </summary>
|
|
public static string GenerateRandomBlock16Hex()
|
|
{
|
|
byte[] buffer = new byte[16];
|
|
using (var rng = new RNGCryptoServiceProvider())
|
|
{
|
|
rng.GetBytes(buffer);
|
|
}
|
|
return BytesToHex(buffer);
|
|
}
|
|
|
|
// ========== Ïðèâàòíûå ìåòîäû AES ==========
|
|
|
|
private static byte[] Aes256EcbEncrypt(byte[] data)
|
|
{
|
|
using (var aes = Aes.Create())
|
|
{
|
|
aes.Key = _aesKey32;
|
|
aes.Mode = CipherMode.ECB;
|
|
aes.Padding = PaddingMode.None;
|
|
|
|
using (var encryptor = aes.CreateEncryptor())
|
|
{
|
|
return encryptor.TransformFinalBlock(data, 0, data.Length);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static byte[] Aes256EcbDecrypt(byte[] data)
|
|
{
|
|
using (var aes = Aes.Create())
|
|
{
|
|
aes.Key = _aesKey32;
|
|
aes.Mode = CipherMode.ECB;
|
|
aes.Padding = PaddingMode.None;
|
|
|
|
using (var decryptor = aes.CreateDecryptor())
|
|
{
|
|
return decryptor.TransformFinalBlock(data, 0, data.Length);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ========== Hex êîíâåðòàöèÿ ==========
|
|
|
|
private static byte[] HexToBytes(string hex)
|
|
{
|
|
hex = hex.Trim();
|
|
if (hex.Length % 2 != 0)
|
|
throw new ArgumentException("Hex string length must be even");
|
|
|
|
byte[] result = new byte[hex.Length / 2];
|
|
for (int i = 0; i < result.Length; i++)
|
|
{
|
|
result[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static string BytesToHex(byte[] bytes)
|
|
{
|
|
StringBuilder sb = new StringBuilder(bytes.Length * 2);
|
|
foreach (byte b in bytes)
|
|
{
|
|
sb.AppendFormat("{0:X2}", b);
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
}
|
|
}
|
|
|