初始化

This commit is contained in:
2025-12-11 14:04:39 +08:00
commit 1f65bbf628
2676 changed files with 838983 additions and 0 deletions

612
ViewModels/CSAES-CTR.cs Normal file
View File

@@ -0,0 +1,612 @@
using System.Collections.Immutable;
using System.Security.Cryptography;
using System.Runtime.Intrinsics;
using System.Runtime.CompilerServices; // For MethodImplOptions.AggressiveInlining
namespace ViewModels;
/// <summary>
/// Class that can be used for AES CTR encryption / decryption
/// </summary>
public sealed class AES_CTR : IDisposable
{
/// <summary>
/// What are allowed key lengths in bytes (128, 192 and 256 bits)
/// </summary>
/// <value></value>
public static readonly ImmutableArray<int> allowedKeyLengths = [16, 24, 32];
/// <summary>
/// What is allowed initial counter length in bytes
/// </summary>
public const int allowedCounterLength = 16;
/// <summary>
/// Only allowed Initialization vector length in bytes
/// </summary>
private const int ivLength = 16;
/// <summary>
/// How many bytes are processed at time
/// </summary>
private const int processBytesAtTime = 16;
/// <summary>
/// Internal counter
/// </summary>
private readonly byte[] counter = new byte[allowedCounterLength];
/// <summary>
/// Internal transformer for doing encrypt/decrypt transforming
/// </summary>
private readonly ICryptoTransform counterEncryptor;
/// <summary>
/// Determines if the objects in this class have been disposed of. Set to true by the Dispose() method.
/// </summary>
private bool isDisposed;
/// <summary>
/// Changes counter behaviour according endianess.
/// </summary>
private readonly bool isLittleEndian;
/// <summary>
/// AES_CTR constructor
/// </summary>
/// <param name="key">Key as readonlyspan. (128, 192 or 256 bits)</param>
/// <param name="initialCounter">Initial counter as readonlyspan. 16 bytes</param>
/// <param name="littleEndian">Is initial counter little endian (default false)</param>
/// <returns></returns>
public AES_CTR(ReadOnlySpan<byte> key, ReadOnlySpan<byte> initialCounter, bool littleEndian = false) : this(key.ToArray(), initialCounter.ToArray(), littleEndian)
{
}
/// <summary>
/// AES_CTR constructor
/// </summary>
/// <param name="key">Key as byte array. (128, 192 or 256 bits)</param>
/// <param name="initialCounter">Initial counter as byte array. 16 bytes</param>
/// <param name="littleEndian">Is initial counter little endian (default false)</param>
public AES_CTR(byte[] key, byte[] initialCounter, bool littleEndian = false)
{
if (key == null)
{
throw new ArgumentNullException("Key is null");
}
if (!allowedKeyLengths.Contains(key.Length))
{
throw new ArgumentException($"Key length must be either {allowedKeyLengths[0]}, {allowedKeyLengths[1]} or {allowedKeyLengths[2]} bytes. Actual: {key.Length}");
}
if (initialCounter == null)
{
throw new ArgumentNullException("Initial counter is null");
}
if (allowedCounterLength != initialCounter.Length)
{
throw new ArgumentException($"Initial counter must be {allowedCounterLength} bytes");
}
this.isDisposed = false;
SymmetricAlgorithm aes = Aes.Create();
aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.None;
// Create copy of initial counter since state is kept during the lifetime of AES_CTR
Buffer.BlockCopy(initialCounter, 0, this.counter, 0, allowedCounterLength);
this.isLittleEndian = littleEndian;
// Initialization vector is always full of zero bytes in CTR mode
var zeroIv = new byte[ivLength];
this.counterEncryptor = aes.CreateEncryptor(key, zeroIv);
}
#region Encrypt
/// <summary>
/// Encrypt arbitrary-length byte array (input), writing the resulting byte array to preallocated output buffer.
/// </summary>
/// <remarks>Since this is symmetric operation, it doesn't really matter if you use Encrypt or Decrypt method</remarks>
/// <param name="output">Output byte array, must have enough bytes</param>
/// <param name="input">Input byte array</param>
/// <param name="numBytes">Number of bytes to encrypt</param>
/// <param name="useSIMD">Use SIMD (true by default)</param>
public void EncryptBytes(byte[] output, byte[] input, int numBytes, bool useSIMD = true)
{
if (input == null)
{
throw new ArgumentNullException("input", "Input cannot be null");
}
if (output == null)
{
throw new ArgumentNullException("output", "Output cannot be null");
}
if (numBytes < 0 || numBytes > input.Length)
{
throw new ArgumentOutOfRangeException("numBytes", "The number of bytes to read must be between [0..input.Length]");
}
if (output.Length < numBytes)
{
throw new ArgumentOutOfRangeException("output", $"Output byte array should be able to take at least {numBytes}");
}
this.WorkBytes(output, input, numBytes, useSIMD);
}
/// <summary>
/// Encrypt arbitrary-length byte stream (input), writing the resulting bytes to another stream (output)
/// </summary>
/// <param name="output">Output stream</param>
/// <param name="input">Input stream</param>
/// <param name="howManyBytesToProcessAtTime">How many bytes to read and write at time, default is 1024</param>
/// <param name="useSIMD">Use SIMD (true by default)</param>
public void EncryptStream(Stream output, Stream input, int howManyBytesToProcessAtTime = 1024, bool useSIMD = true)
{
this.WorkStreams(output, input, useSIMD, howManyBytesToProcessAtTime);
}
/// <summary>
/// Async encrypt arbitrary-length byte stream (input), writing the resulting bytes to another stream (output)
/// </summary>
/// <param name="output">Output stream</param>
/// <param name="input">Input stream</param>
/// <param name="howManyBytesToProcessAtTime">How many bytes to read and write at time, default is 1024</param>
/// <param name="useSIMD">Use SIMD (true by default)</param>
/// <returns></returns>
public async Task EncryptStreamAsync(Stream output, Stream input, int howManyBytesToProcessAtTime = 1024, bool useSIMD = true)
{
await this.WorkStreamsAsync(output, input, useSIMD, howManyBytesToProcessAtTime);
}
/// <summary>
/// Encrypt arbitrary-length byte array (input), writing the resulting byte array to preallocated output buffer.
/// </summary>
/// <remarks>Since this is symmetric operation, it doesn't really matter if you use Encrypt or Decrypt method</remarks>
/// <param name="output">Output byte array, must have enough bytes</param>
/// <param name="input">Input byte array</param>
/// <param name="useSIMD">Use SIMD (true by default)</param>
public void EncryptBytes(byte[] output, byte[] input, bool useSIMD = true)
{
if (input == null)
{
throw new ArgumentNullException("input", "Input cannot be null");
}
if (output == null)
{
throw new ArgumentNullException("output", "Output cannot be null");
}
this.WorkBytes(output, input, input.Length, useSIMD);
}
/// <summary>
/// Encrypt arbitrary-length byte array (input), writing the resulting byte array that is allocated by method.
/// </summary>
/// <remarks>Since this is symmetric operation, it doesn't really matter if you use Encrypt or Decrypt method</remarks>
/// <param name="input">Input byte array</param>
/// <param name="numBytes">Number of bytes to encrypt</param>
/// <param name="useSIMD">Use SIMD (true by default)</param>
/// <returns>Byte array that contains encrypted bytes</returns>
public byte[] EncryptBytes(byte[] input, int numBytes, bool useSIMD = true)
{
if (input == null)
{
throw new ArgumentNullException("input", "Input cannot be null");
}
if (numBytes < 0 || numBytes > input.Length)
{
throw new ArgumentOutOfRangeException("numBytes", "The number of bytes to read must be between [0..input.Length]");
}
byte[] returnArray = new byte[numBytes];
this.WorkBytes(returnArray, input, numBytes, useSIMD);
return returnArray;
}
/// <summary>
/// Encrypt arbitrary-length byte array (input), writing the resulting byte array that is allocated by method.
/// </summary>
/// <remarks>Since this is symmetric operation, it doesn't really matter if you use Encrypt or Decrypt method</remarks>
/// <param name="input">Input byte array</param>
/// <param name="useSIMD">Use SIMD (true by default)</param>
/// <returns>Byte array that contains encrypted bytes</returns>
public byte[] EncryptBytes(byte[] input, bool useSIMD = true)
{
if (input == null)
{
throw new ArgumentNullException("input", "Input cannot be null");
}
byte[] returnArray = new byte[input.Length];
this.WorkBytes(returnArray, input, input.Length, useSIMD);
return returnArray;
}
/// <summary>
/// Encrypt string as UTF8 byte array, returns byte array that is allocated by method.
/// </summary>
/// <remarks>Here you can NOT swap encrypt and decrypt methods, because of bytes-string transform</remarks>
/// <param name="input">Input string</param>
/// <param name="useSIMD">Use SIMD (true by default)</param>
/// <returns>Byte array that contains encrypted bytes</returns>
public byte[] EncryptString(string input, bool useSIMD = true)
{
if (input == null)
{
throw new ArgumentNullException("input", "Input cannot be null");
}
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(input);
byte[] returnArray = new byte[utf8Bytes.Length];
this.WorkBytes(returnArray, utf8Bytes, utf8Bytes.Length, useSIMD);
return returnArray;
}
#endregion // Encrypt
#region Decrypt
/// <summary>
/// Decrypt arbitrary-length byte array (input), writing the resulting byte array to preallocated output buffer.
/// </summary>
/// <remarks>Since this is symmetric operation, it doesn't really matter if you use Encrypt or Decrypt method</remarks>
/// <param name="output">Output byte array, must have enough bytes</param>
/// <param name="input">Input byte array</param>
/// <param name="numBytes">Number of bytes to encrypt</param>
/// <param name="useSIMD">Use SIMD (true by default)</param>
public void DecryptBytes(byte[] output, byte[] input, int numBytes, bool useSIMD = true)
{
if (input == null)
{
throw new ArgumentNullException("input", "Input cannot be null");
}
if (output == null)
{
throw new ArgumentNullException("output", "Output cannot be null");
}
if (numBytes < 0 || numBytes > input.Length)
{
throw new ArgumentOutOfRangeException("numBytes", "The number of bytes to read must be between [0..input.Length]");
}
if (output.Length < numBytes)
{
throw new ArgumentOutOfRangeException("output", $"Output byte array should be able to take at least {numBytes}");
}
this.WorkBytes(output, input, numBytes, useSIMD);
}
/// <summary>
/// Decrypt arbitrary-length byte stream (input), writing the resulting bytes to another stream (output)
/// </summary>
/// <param name="output">Output stream</param>
/// <param name="input">Input stream</param>
/// <param name="howManyBytesToProcessAtTime">How many bytes to read and write at time, default is 1024</param>
/// <param name="useSIMD">Use SIMD (true by default)</param>
public void DecryptStream(Stream output, Stream input, int howManyBytesToProcessAtTime = 1024, bool useSIMD = true)
{
this.WorkStreams(output, input, useSIMD, howManyBytesToProcessAtTime);
}
/// <summary>
/// Async decrypt arbitrary-length byte stream (input), writing the resulting bytes to another stream (output)
/// </summary>
/// <param name="output">Output stream</param>
/// <param name="input">Input stream</param>
/// <param name="howManyBytesToProcessAtTime">How many bytes to read and write at time, default is 1024</param>
/// <param name="useSIMD">Use SIMD (true by default)</param>
/// <returns></returns>
public async Task DecryptStreamAsync(Stream output, Stream input, int howManyBytesToProcessAtTime = 1024, bool useSIMD = true)
{
await this.WorkStreamsAsync(output, input, useSIMD, howManyBytesToProcessAtTime);
}
/// <summary>
/// Decrypt arbitrary-length byte array (input), writing the resulting byte array to preallocated output buffer.
/// </summary>
/// <remarks>Since this is symmetric operation, it doesn't really matter if you use Encrypt or Decrypt method</remarks>
/// <param name="output">Output byte array, must have enough bytes</param>
/// <param name="input">Input byte array</param>
/// <param name="useSIMD">Use SIMD (true by default)</param>
public void DecryptBytes(byte[] output, byte[] input, bool useSIMD = true)
{
if (input == null)
{
throw new ArgumentNullException("input", "Input cannot be null");
}
if (output == null)
{
throw new ArgumentNullException("output", "Output cannot be null");
}
this.WorkBytes(output, input, input.Length, useSIMD);
}
/// <summary>
/// Decrypt arbitrary-length byte array (input), writing the resulting byte array that is allocated by method.
/// </summary>
/// <remarks>Since this is symmetric operation, it doesn't really matter if you use Encrypt or Decrypt method</remarks>
/// <param name="input">Input byte array</param>
/// <param name="numBytes">Number of bytes to encrypt</param>
/// <param name="useSIMD">Use SIMD (true by default)</param>
/// <returns>Byte array that contains decrypted bytes</returns>
public byte[] DecryptBytes(byte[] input, int numBytes, bool useSIMD = true)
{
if (input == null)
{
throw new ArgumentNullException("input", "Input cannot be null");
}
if (numBytes < 0 || numBytes > input.Length)
{
throw new ArgumentOutOfRangeException("numBytes", "The number of bytes to read must be between [0..input.Length]");
}
byte[] returnArray = new byte[numBytes];
this.WorkBytes(returnArray, input, numBytes, useSIMD);
return returnArray;
}
/// <summary>
/// Decrypt arbitrary-length byte array (input), writing the resulting byte array that is allocated by method.
/// </summary>
/// <remarks>Since this is symmetric operation, it doesn't really matter if you use Encrypt or Decrypt method</remarks>
/// <param name="input">Input byte array</param>
/// <param name="useSIMD">Use SIMD (true by default)</param>
/// <returns>Byte array that contains decrypted bytes</returns>
public byte[] DecryptBytes(byte[] input, bool useSIMD = true)
{
if (input == null)
{
throw new ArgumentNullException("input", "Input cannot be null");
}
byte[] returnArray = new byte[input.Length];
this.WorkBytes(returnArray, input, input.Length, useSIMD);
return returnArray;
}
/// <summary>
/// Decrypt UTF8 byte array to string.
/// </summary>
/// <remarks>Here you can NOT swap encrypt and decrypt methods, because of bytes-string transform</remarks>
/// <param name="input">Byte array</param>
/// <param name="useSIMD">Use SIMD (true by default)</param>
/// <returns>Byte array that contains encrypted bytes</returns>
public string DecryptUTF8ByteArray(byte[] input, bool useSIMD = true)
{
if (input == null)
{
throw new ArgumentNullException("input", "Input cannot be null");
}
byte[] tempArray = new byte[input.Length];
this.WorkBytes(tempArray, input, input.Length, useSIMD);
return System.Text.Encoding.UTF8.GetString(tempArray);
}
#endregion // Decrypt
/// <summary>
/// Decrypt / Encrypt arbitrary-length byte stream (input), writing the resulting bytes to another stream (output)
/// </summary>
/// <param name="output">Output stream</param>
/// <param name="input">Input stream</param>
/// <param name="useSIMD">Use SIMD (true by default)</param>
/// <param name="howManyBytesToProcessAtTime">How many bytes to read and write at time, default is 1024</param>
private void WorkStreams(Stream output, Stream input, bool useSIMD, int howManyBytesToProcessAtTime = 1024)
{
int readBytes;
byte[] inputBuffer = new byte[howManyBytesToProcessAtTime];
byte[] outputBuffer = new byte[howManyBytesToProcessAtTime];
while ((readBytes = input.Read(inputBuffer, 0, howManyBytesToProcessAtTime)) > 0)
{
// Encrypt or decrypt
this.WorkBytes(output: outputBuffer, input: inputBuffer, numBytes: readBytes, useSIMD);
// Write buffer
output.Write(outputBuffer, 0, readBytes);
}
}
private async Task WorkStreamsAsync(Stream output, Stream input, bool useSIMD, int howManyBytesToProcessAtTime = 1024)
{
byte[] readBytesBuffer = new byte[howManyBytesToProcessAtTime];
byte[] writeBytesBuffer = new byte[howManyBytesToProcessAtTime];
int howManyBytesWereRead = await input.ReadAsync(readBytesBuffer, 0, howManyBytesToProcessAtTime);
while (howManyBytesWereRead > 0)
{
// Encrypt or decrypt
this.WorkBytes(output: writeBytesBuffer, input: readBytesBuffer, numBytes: howManyBytesWereRead, useSIMD);
// Write
await output.WriteAsync(writeBytesBuffer, 0, howManyBytesWereRead);
// Read more
howManyBytesWereRead = await input.ReadAsync(readBytesBuffer, 0, howManyBytesToProcessAtTime);
}
}
private void WorkBytes(byte[] output, byte[] input, int numBytes, bool useSIMD)
{
if (isDisposed)
{
throw new ObjectDisposedException("state", "AES_CTR has already been disposed");
}
int offset = 0;
var tmp = new byte[allowedCounterLength];
int howManyFullLoops = numBytes / processBytesAtTime;
int tailByteCount = numBytes - (howManyFullLoops * processBytesAtTime);
for (int loop = 0; loop < howManyFullLoops; loop++)
{
// Generate new XOR mask for next processBytesAtTime
this.counterEncryptor.TransformBlock(counter, 0, allowedCounterLength, tmp, 0);
this.IncreaseCounter();
if (useSIMD)
{
// 1 x 16 bytes
Vector128<byte> inputV = Vector128.Create(input, offset);
Vector128<byte> tmpV = Vector128.Create(tmp, 0);
Vector128<byte> outputV = inputV ^ tmpV;
outputV.CopyTo(output, offset);
}
else
{
for (int i = 0; i < processBytesAtTime; i++)
{
output[i + offset] = (byte)(input[i + offset] ^ tmp[i]);
}
}
offset += processBytesAtTime;
}
// In case there are some bytes left
if (tailByteCount > 0)
{
// Generate new XOR mask for next processBytesAtTime
this.counterEncryptor.TransformBlock(counter, 0, allowedCounterLength, tmp, 0);
this.IncreaseCounter();
for (int i = 0; i < tailByteCount; i++)
{
output[i + offset] = (byte)(input[i + offset] ^ tmp[i]);
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void IncreaseCounter()
{
// Increase counter (basically this increases the last index first and continues to one before that if 255 -> 0, better solution would be to use uint128, but it does not exist yet)
if (this.isLittleEndian)
{
// LittleEndian
for (int i = 0; i < allowedCounterLength; i++)
{
if (++counter[i] != 0)
{
break;
}
}
}
else
{
// BigEndian
for (int i = allowedCounterLength - 1; i >= 0; i--)
{
if (++counter[i] != 0)
{
break;
}
}
}
}
/// <summary>
/// <20><><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9>
/// </summary>
void test()
{
byte[] mySimpleTextAsBytes = System.Text.Encoding.ASCII.GetBytes("CM:GPIO_WRITE:5:0x19:0x01:1sdfghasada\r\n");
// example data
var IV = new byte[] { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };
byte[] key = new byte[] { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
// Encrypt
AES_CTR forEncrypting = new AES_CTR(key, IV);
byte[] encryptedContent = new byte[mySimpleTextAsBytes.Length];
forEncrypting.EncryptBytes(encryptedContent, mySimpleTextAsBytes);
// Decrypt
AES_CTR forDecrypting = new AES_CTR(key, IV);
byte[] decryptedContent = new byte[encryptedContent.Length];
forDecrypting.DecryptBytes(decryptedContent, encryptedContent);
Console.WriteLine("Hello, World!");
}
#region Destructor and Disposer
/// <summary>
/// Clear and dispose of the internal variables. The finalizer is only called if Dispose() was never called on this cipher.
/// </summary>
~AES_CTR()
{
Dispose(false);
}
/// <summary>
/// Clear and dispose of the internal state. Also request the GC not to call the finalizer, because all cleanup has been taken care of.
/// </summary>
public void Dispose()
{
Dispose(true);
/*
* The Garbage Collector does not need to invoke the finalizer because Dispose(bool) has already done all the cleanup needed.
*/
GC.SuppressFinalize(this);
}
/// <summary>
/// This method should only be invoked from Dispose() or the finalizer. This handles the actual cleanup of the resources.
/// </summary>
/// <param name="disposing">
/// Should be true if called by Dispose(); false if called by the finalizer
/// </param>
private void Dispose(bool disposing)
{
if (!isDisposed)
{
if (disposing)
{
/* Cleanup managed objects by calling their Dispose() methods */
if (this.counterEncryptor != null)
{
this.counterEncryptor.Dispose();
}
}
/* Cleanup here */
Array.Clear(this.counter, 0, allowedCounterLength);
}
isDisposed = true;
}
#endregion // Destructor and Disposer
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ViewModels.Data
{
public class BooliveDevice
{
public long? Id { get; set; }
public string? ProductID { get; set; }
public string? DeviceName { get; set; }
public string? DeviceSecret { get; set; }
}
public class QueryData
{
public string? HotelCode { get; set; }
}
}

540
ViewModels/Tools.cs Normal file
View File

@@ -0,0 +1,540 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace ViewModels
{
public class Tools
{
/// <summary>
/// 时间戳转本地时间-时间戳精确到秒
/// </summary>
public static DateTime ToLocalTimeDateBySeconds(long unix)
{
var dto = DateTimeOffset.FromUnixTimeSeconds(unix);
return dto.ToLocalTime().DateTime;
}
/// <summary>
/// 时间转时间戳Unix-时间戳精确到秒
/// </summary>
public static long ToUnixTimestampBySeconds(DateTime dt)
{
DateTimeOffset dto = new DateTimeOffset(dt);
return dto.ToUnixTimeSeconds();
}
/// <summary>
/// 时间戳转本地时间-时间戳精确到毫秒
/// </summary>
public static DateTime ToLocalTimeDateByMilliseconds(long unix)
{
var dto = DateTimeOffset.FromUnixTimeMilliseconds(unix);
return dto.ToLocalTime().DateTime;
}
/// <summary>
/// 时间转时间戳Unix-时间戳精确到毫秒
/// </summary>
public static long ToUnixTimestampByMilliseconds(DateTime dt)
{
DateTimeOffset dto = new DateTimeOffset(dt);
return dto.ToUnixTimeMilliseconds();
}
/// <summary>
/// 生成CRC16校验
/// </summary>
/// <param name="buffer"></param>
/// <param name="len"></param>
/// <returns></returns>
public static ushort CRC16(byte[] buffer, int len)
{
uint xda, xdapoly;
byte xdabit;
xda = 0xFFFF;
xdapoly = 0xA001; // (X**16 + X**15 + X**2 + 1)
for (int i = 0; i < len; i++)
{
xda ^= buffer[i];
for (int j = 0; j < 8; j++)
{
xdabit = (byte)(xda & 0x01);
xda >>= 1;
if (xdabit == 1)
{
xda ^= xdapoly;
}
}
}
return Convert.ToUInt16(xda & 0xffff);
}
/// <summary>
/// 计算文件的MD5值
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public static byte[] MD5(string file)
{
using (Stream stream = File.Open(file, FileMode.Open))
{
return MD5(stream);
}
}
/// <summary>
/// 计算流的MD5值
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
public static byte[] MD5(Stream stream)
{
using (MD5 md5 = new MD5CryptoServiceProvider())
{
return md5.ComputeHash(stream);
}
}
/// <summary>
/// 计算文件MD5
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
public static string ComputeFileHash(Stream stream)
{
byte[] retVal = Tools.MD5(stream);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("x2"));
}
return sb.ToString();
}
/// <summary>
/// 将MD5字符串转换成整型数组表示
/// </summary>
/// <param name="md5"></param>
/// <returns></returns>
public static uint[] MD5StringToUIntArray(string md5)
{
if (String.IsNullOrWhiteSpace(md5))
{
throw new ArgumentException("参数不能为空。", "md5");
}
try
{
uint[] md5Arr = new uint[4] { 0, 0, 0, 0 };
md5Arr[0] = Convert.ToUInt32(md5.Substring(0, 8), 16);
md5Arr[1] = Convert.ToUInt32(md5.Substring(8, 8), 16);
md5Arr[2] = Convert.ToUInt32(md5.Substring(16, 8), 16);
md5Arr[3] = Convert.ToUInt32(md5.Substring(24, 8), 16);
return md5Arr;
}
catch (Exception ex)
{
throw new ApplicationException("转换MD5出错。", ex);
}
}
/// <summary>
/// 用MD5加密字符串
/// </summary>
/// <param name="str">待加密的字符串</param>
/// <returns></returns>
public static string MD5Encrypt(string str)
{
MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();
byte[] hashedDataBytes;
hashedDataBytes = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(str));
StringBuilder tmp = new StringBuilder();
foreach (byte i in hashedDataBytes)
{
tmp.Append(i.ToString("x2"));
}
return tmp.ToString();
}
/// <summary>
/// 获取指定长的的字符串对应的16进制字节码如果长度不够末位自动补0
/// </summary>
/// <param name="s"></param>
/// <param name="length"></param>
/// <returns></returns>
public static byte[] GetBytes(String str, int length)
{
byte[] s = System.Text.Encoding.GetEncoding("gb2312").GetBytes(str);
int fixLength = length - s.Length;
if (s.Length < length)
{
byte[] S_bytes = new byte[length];
Array.Copy(s, 0, S_bytes, 0, s.Length);
for (int x = length - fixLength; x < length; x++)
{
S_bytes[x] = 0x00;
}
return S_bytes;
}
return s;
}
/// 获取一个随机数组
/// </summary>
/// <param name="num">数组个数</param>
/// <param name="minValue"></param>
/// <param name="maxValue"></param>
/// <returns></returns>
public static int[] GetRandomNum(int num, int minValue, int maxValue)
{
Random ra = new Random(unchecked((int)DateTime.Now.Ticks));
int[] arrNum = new int[num];
int tmp = 0;
for (int i = 0; i <= num - 1; i++)
{
tmp = ra.Next(minValue, maxValue); //随机取数
arrNum[i] = tmp;
}
return arrNum;
}
/// <summary>
/// 字节内容转换为字符串
/// </summary>
/// <param name="bytesData"></param>
/// <returns></returns>
public static string ByteToString(byte[] bytesData)
{
StringBuilder result = new StringBuilder();
foreach (byte r in bytesData)
{
result.Append(r.ToString("X2") + " ");
}
return result.ToString().Trim();
}
/// <summary>
/// 把int32类型的数据转存到2个字节的byte数组中
/// </summary>
/// <param name="m">int32类型的数据</param>
/// <param name="arry">2个字节大小的byte数组</param>
/// <returns></returns>
public static byte[] Int32ToByte(Int32 data)
{
byte[] arry = new byte[2];
arry[0] = (byte)((data & 0xFF00) >> 8);
arry[1] = (byte)(data & 0xFF);
return arry;
}
/// <summary>
/// 把int32类型的数据转存到2个字节的byte数组中小端
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static byte[] Int32ToByte2(Int32 data)
{
byte[] arry = new byte[2];
arry[0] = (byte)(data & 0xFF);
arry[1] = (byte)((data & 0xFF00) >> 8);
//arry[2] = (byte)((data & 0xFF0000) >> 16);
//arry[3] = (byte)((data >> 24) & 0xFF);
return arry;
}
/// <summary>
/// 2位byte转换为int类型
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static int ByteToInt(byte[] data)
{
return (data[1] & 0xFF) << 8 | data[0];
}
/// <summary>
/// 4位byte转换为long类型
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static long Byte4ToLong(byte[] data)
{
return (data[3] << 24) & 0xFF | (data[2] & 0xFF00) << 16 | (data[1] & 0xFF) << 8 | data[0];
}
/// <summary>
/// long类型转换为4位byte
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static byte[] LongToByte4(long data)
{
byte[] arry = new byte[4];
arry[0] = (byte)(data & 0xFF);
arry[1] = (byte)((data & 0xFF00) >> 8);
arry[2] = (byte)((data & 0xFF0000) >> 16);
arry[3] = (byte)((data >> 24) & 0xFF);
return arry;
}
/// <summary>
/// 得到字符串的长度一个汉字算2个字符
/// </summary>
/// <param name="str">字符串</param>
/// <returns>返回字符串长度</returns>
public static int GetLength(string str)
{
if (str.Length == 0) return 0;
ASCIIEncoding ascii = new ASCIIEncoding();
int tempLen = 0;
byte[] s = ascii.GetBytes(str);
for (int i = 0; i < s.Length; i++)
{
if ((int)s[i] == 63)
{
tempLen += 2;
}
else
{
tempLen += 1;
}
}
return tempLen;
}
/// <summary>
/// HEX编码转换为——>ASCII编码
/// </summary>
/// <param name="Msg"></param>
/// <returns></returns>
public static string HexToASCII(string Msg)
{
byte[] buff = new byte[Msg.Length / 2];
string Message = "";
for (int i = 0; i < buff.Length; i++)
{
buff[i] = byte.Parse(Msg.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber);
}
System.Text.Encoding chs = System.Text.Encoding.ASCII;
Message = chs.GetString(buff);
return Message;
}
/// <summary>
/// HEX编码转换为——>字符串
/// </summary>
/// <param name="Msg"></param>
/// <returns></returns>
public static string HexToStr(string Msg)
{
byte[] buff = new byte[Msg.Length / 2];
string Message = "";
for (int i = 0; i < buff.Length; i++)
{
buff[i] = byte.Parse(Msg.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber);
}
System.Text.Encoding chs = System.Text.Encoding.GetEncoding("gb2312");
Message = chs.GetString(buff);
return Message;
}
/// <summary>
/// 字符串转化为——>HEX编码
/// </summary>
/// <param name="Msg"></param>
/// <returns></returns>
public static string StrToHex(string Msg)
{
byte[] bytes = System.Text.Encoding.Default.GetBytes(Msg);//转换为字节(十进制)
string str = "";
for (int i = 0; i < bytes.Length; i++)
{
str += string.Format("{0:X}", bytes[i]); //转换为十六进制
}
return str;
}
public static string GetCurrentTimeStamp()
{
TimeSpan ts = DateTime.Now.ToLocalTime() - new DateTime(1970, 1, 1, 8, 0, 0, 0, DateTimeKind.Utc);
string current_timestamp = Convert.ToInt64(ts.TotalSeconds).ToString();
return current_timestamp;
}
/// <summary>
/// 16进制字符串 转换成 byte 数组
/// </summary>
/// <param name="hexString"></param>
/// <returns></returns>
public static byte[] HEXString2ByteArray(string hexString)
{
char[] hexCharacters = hexString.ToCharArray();
byte[] byteArray = new byte[hexCharacters.Length / 2];
for (int i = 0; i < byteArray.Length; i++)
{
string hexVal = string.Concat(hexCharacters[i * 2], hexCharacters[i * 2 + 1]);
byteArray[i] = Convert.ToByte(hexVal, 16);
}
return byteArray;
}
public static byte CombineBitsToByte(bool bit0, bool bit1, bool bit2, bool bit3)
{
byte result = (byte)((bit0 ? 1 : 0) << 3); // 将bit0移到第4位高位
result |= (byte)((bit1 ? 1 : 0) << 2); // 将bit1移到第3位
result |= (byte)((bit2 ? 1 : 0) << 1); // 将bit2移到第2位
result |= (byte)(bit3 ? 1 : 0); // 将bit3移到第1位低位
return result;
}
/// <summary>
/// AES 加密
/// </summary>
/// <param name="str"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string AesEncrypt(string str, string key)
{
if (string.IsNullOrEmpty(str)) return null;
Byte[] toEncryptArray = Encoding.UTF8.GetBytes(str);
System.Security.Cryptography.RijndaelManaged rm = new System.Security.Cryptography.RijndaelManaged
{
Key = Encoding.UTF8.GetBytes(key),
Mode = System.Security.Cryptography.CipherMode.ECB,
Padding = System.Security.Cryptography.PaddingMode.PKCS7
};
System.Security.Cryptography.ICryptoTransform cTransform = rm.CreateEncryptor();
Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
public static readonly byte[] IV = new byte[] { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };
/// <summary>
/// AES CTR 加密
/// </summary>
/// <param name="str"></param>
/// <param name="key"></param>
/// <returns></returns>
public static byte[] AesEncryptCTR(byte[] str, byte[] key)
{
//byte[] mySimpleTextAsBytes = System.Text.Encoding.ASCII.GetBytes(str);
//byte[] key = new byte[] { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
// Encrypt
AES_CTR forEncrypting = new AES_CTR(key, IV);
byte[] encryptedContent = new byte[str.Length];
forEncrypting.EncryptBytes(encryptedContent, str);
return encryptedContent;
}
/// <summary>
/// AES CRT解密
/// </summary>
/// <param name="encryptedContent"></param>
/// <param name="key"></param>
/// <returns></returns>
public static byte[] AesDecryptCTR(byte[] encryptedContent, byte[] key)
{
// Decrypt
AES_CTR forDecrypting = new AES_CTR(key, IV);
byte[] decryptedContent = new byte[encryptedContent.Length];
forDecrypting.DecryptBytes(decryptedContent, encryptedContent);
return decryptedContent;
}
/// <summary>
/// AES 解密
/// </summary>
/// <param name="str"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string AesDecrypt(string str, string key)
{
if (string.IsNullOrEmpty(str)) return null;
Byte[] toEncryptArray = Convert.FromBase64String(str);
System.Security.Cryptography.RijndaelManaged rm = new System.Security.Cryptography.RijndaelManaged
{
Key = Encoding.UTF8.GetBytes(key),
Mode = System.Security.Cryptography.CipherMode.ECB,
Padding = System.Security.Cryptography.PaddingMode.PKCS7
};
System.Security.Cryptography.ICryptoTransform cTransform = rm.CreateDecryptor();
Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return Encoding.UTF8.GetString(resultArray);
}
public static string GetMD5(string str)
{
//创建MD5对象
MD5 mD5 = System.Security.Cryptography.MD5.Create();
byte[] buffer = Encoding.Default.GetBytes(str);
var MD5Buffer = mD5.ComputeHash(buffer);
//将字节数组转换为字符串
//法一:将字节数组中每个元素按照指定的编码格式解析成字符串
//return Encoding.Default.GetString(MD5Buffer);(会造成乱码)
//法二直接将数组tostring
//法三直接将数组中的每个元素ToString()
string s = "";
for (int i = 0; i < MD5Buffer.Length; i++)
{
s += MD5Buffer[i].ToString("x");//tostring中的参数x是将10进制转化为16进制
}
return s;
}
/// <summary>
/// IOT 加密 方法
/// </summary>
/// <param name="sn"></param>
/// <param name="skey"></param>
/// <param name="data"></param>
/// <param name="alen"></param>
/// <returns></returns>
public static byte[] IHIOT_Message_Content_Encrypt(ushort sn, byte[] skey, byte[] data)
{
byte[] newdata = new byte[data.Length];
Buffer.BlockCopy(data, 0, newdata, 0, newdata.Length);
byte key = skey[sn % 16];
int alen = newdata.Length;
for (int i = 0; i < alen; i++)
{
newdata[i] ^= key; // 使用固定密钥字节进行异或加密
}
return newdata;
}
/// <summary>
/// 解密方法
/// </summary>
/// <param name="sn"></param>
/// <param name="skey"></param>
/// <param name="data"></param>
/// <param name="alen"></param>
/// <returns></returns>
public byte[] IHIOT_Message_Content_DEncrypt(ushort sn, byte[] skey, byte[] data, ushort alen)
{
byte[] newdata = new byte[data.Length];
Buffer.BlockCopy(data, 0, newdata, 0, newdata.Length);
byte key = skey[sn % 16];
for (int i = 0; i < alen; i++)
{
newdata[i] ^= key; // 使用固定密钥字节进行异或加密
}
return newdata;
}
}
}

View File

@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>