更新标准库UDP等
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
@@ -11,39 +12,143 @@ namespace Ramitta.lib
|
||||
public class CryptoHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 生成RSA密钥对
|
||||
/// 通过OpenSSH格式私钥计算公钥(Base64格式)
|
||||
/// </summary>
|
||||
/// <param name="keySize">密钥长度(通常为2048、4096)</param>
|
||||
/// <returns>包含公钥和私钥的元组</returns>
|
||||
public static (string publicKey, string privateKey) GenerateKeyPair(int keySize = 2048)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var rsa = RSA.Create(keySize))
|
||||
{
|
||||
string publicKey = rsa.ToXmlString(false);
|
||||
string privateKey = rsa.ToXmlString(true);
|
||||
|
||||
return (publicKey, privateKey);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"密钥生成失败: {ex.Message}");
|
||||
return (null, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用私钥对数据进行签名
|
||||
/// </summary>
|
||||
public static string? SignData(string data, string privateKey)
|
||||
/// <param name="openSshPrivateKey">OpenSSH格式的Base64私钥(不带PEM头尾)</param>
|
||||
/// <returns>Base64格式的公钥,失败返回null</returns>
|
||||
public static string? GetPublicKeyFromPrivate(string openSshPrivateKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var rsa = RSA.Create())
|
||||
{
|
||||
rsa.FromXmlString(privateKey);
|
||||
// 解析OpenSSH私钥格式
|
||||
ImportOpenSshPrivateKey(rsa, openSshPrivateKey);
|
||||
|
||||
// 导出公钥为Base64
|
||||
byte[] publicKeyBytes = rsa.ExportRSAPublicKey();
|
||||
return Convert.ToBase64String(publicKeyBytes);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"从私钥提取公钥失败: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导入OpenSSH格式的私钥(纯Base64编码)
|
||||
/// </summary>
|
||||
private static void ImportOpenSshPrivateKey(RSA rsa, string openSshBase64)
|
||||
{
|
||||
byte[] keyData = Convert.FromBase64String(openSshBase64);
|
||||
|
||||
using (var reader = new BinaryReader(new MemoryStream(keyData)))
|
||||
{
|
||||
// 读取魔术字
|
||||
var magic = reader.ReadBytes(15);
|
||||
string magicString = Encoding.ASCII.GetString(magic);
|
||||
if (magicString != "openssh-key-v1\0")
|
||||
throw new FormatException("无效的OpenSSH私钥格式");
|
||||
|
||||
// 读取加密信息
|
||||
var cipherName = ReadLengthPrefixedString(reader);
|
||||
var kdfName = ReadLengthPrefixedString(reader);
|
||||
var kdfOptions = ReadLengthPrefixedData(reader);
|
||||
|
||||
// 检查是否加密
|
||||
if (cipherName != "none" || kdfName != "none")
|
||||
throw new FormatException("不支持加密的OpenSSH私钥");
|
||||
|
||||
// 读取密钥数量
|
||||
var keyCount = ReadUInt32BigEndian(reader);
|
||||
if (keyCount != 1)
|
||||
throw new FormatException("不支持多个密钥");
|
||||
|
||||
// 读取公钥(跳过)
|
||||
var publicKey = ReadLengthPrefixedData(reader);
|
||||
|
||||
// 读取私钥数据
|
||||
var privateKeyData = ReadLengthPrefixedData(reader);
|
||||
|
||||
// 解析私钥数据
|
||||
using (var privateReader = new BinaryReader(new MemoryStream(privateKeyData)))
|
||||
{
|
||||
// 检查字节序标记
|
||||
var check1 = privateReader.ReadUInt32();
|
||||
var check2 = privateReader.ReadUInt32();
|
||||
if (check1 != check2)
|
||||
throw new FormatException("私钥检查值不匹配");
|
||||
|
||||
// 读取密钥类型
|
||||
var keyType = ReadLengthPrefixedString(privateReader);
|
||||
if (keyType != "ssh-rsa")
|
||||
throw new FormatException("非RSA密钥");
|
||||
|
||||
// 读取RSA参数
|
||||
var modulus = ReadLengthPrefixedData(privateReader); // n
|
||||
var publicExponent = ReadLengthPrefixedData(privateReader); // e
|
||||
var privateExponent = ReadLengthPrefixedData(privateReader); // d
|
||||
var coefficient = ReadLengthPrefixedData(privateReader); // iqmp
|
||||
var prime1 = ReadLengthPrefixedData(privateReader); // p
|
||||
var prime2 = ReadLengthPrefixedData(privateReader); // q
|
||||
|
||||
// 创建RSA参数并导入
|
||||
var rsaParameters = new RSAParameters
|
||||
{
|
||||
Modulus = modulus,
|
||||
Exponent = publicExponent,
|
||||
D = privateExponent,
|
||||
P = prime1,
|
||||
Q = prime2,
|
||||
InverseQ = coefficient
|
||||
};
|
||||
|
||||
rsa.ImportParameters(rsaParameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取长度前缀字符串
|
||||
/// </summary>
|
||||
private static string ReadLengthPrefixedString(BinaryReader reader)
|
||||
{
|
||||
var data = ReadLengthPrefixedData(reader);
|
||||
return Encoding.ASCII.GetString(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取长度前缀数据
|
||||
/// </summary>
|
||||
private static byte[] ReadLengthPrefixedData(BinaryReader reader)
|
||||
{
|
||||
var length = ReadUInt32BigEndian(reader);
|
||||
return reader.ReadBytes((int)length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 以大端序读取uint32
|
||||
/// </summary>
|
||||
private static uint ReadUInt32BigEndian(BinaryReader reader)
|
||||
{
|
||||
var data = reader.ReadBytes(4);
|
||||
if (BitConverter.IsLittleEndian)
|
||||
Array.Reverse(data);
|
||||
return BitConverter.ToUInt32(data, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用OpenSSH格式私钥对数据进行签名
|
||||
/// </summary>
|
||||
public static string? SignDataWithOpenSsh(string data, string openSshPrivateKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var rsa = RSA.Create())
|
||||
{
|
||||
ImportOpenSshPrivateKey(rsa, openSshPrivateKey);
|
||||
|
||||
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
|
||||
byte[] signature = rsa.SignData(dataBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||
@@ -58,61 +163,15 @@ namespace Ramitta.lib
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用公钥验证签名
|
||||
/// 使用OpenSSH格式私钥解密数据
|
||||
/// </summary>
|
||||
public static bool? VerifySignature(string data, string signature, string publicKey)
|
||||
public static string? DecryptWithOpenSsh(string encryptedData, string openSshPrivateKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var rsa = RSA.Create())
|
||||
{
|
||||
rsa.FromXmlString(publicKey);
|
||||
|
||||
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
|
||||
byte[] signatureBytes = Convert.FromBase64String(signature);
|
||||
|
||||
return rsa.VerifyData(dataBytes, signatureBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用公钥加密数据
|
||||
/// </summary>
|
||||
public static string? Encrypt(string data, string publicKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var rsa = RSA.Create())
|
||||
{
|
||||
rsa.FromXmlString(publicKey);
|
||||
|
||||
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
|
||||
byte[] encryptedBytes = rsa.Encrypt(dataBytes, RSAEncryptionPadding.OaepSHA256);
|
||||
|
||||
return Convert.ToBase64String(encryptedBytes);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用私钥解密数据
|
||||
/// </summary>
|
||||
public static string? Decrypt(string encryptedData, string privateKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var rsa = RSA.Create())
|
||||
{
|
||||
rsa.FromXmlString(privateKey);
|
||||
ImportOpenSshPrivateKey(rsa, openSshPrivateKey);
|
||||
|
||||
byte[] encryptedBytes = Convert.FromBase64String(encryptedData);
|
||||
byte[] decryptedBytes = rsa.Decrypt(encryptedBytes, RSAEncryptionPadding.OaepSHA256);
|
||||
@@ -125,5 +184,79 @@ namespace Ramitta.lib
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取OpenSSH格式私钥的密钥长度
|
||||
/// </summary>
|
||||
public static int GetOpenSshKeySize(string openSshPrivateKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var rsa = RSA.Create())
|
||||
{
|
||||
ImportOpenSshPrivateKey(rsa, openSshPrivateKey);
|
||||
return rsa.KeySize;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"获取密钥长度失败: {ex.Message}");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// 其他原有方法保持不变...
|
||||
public static (string publicKey, string privateKey) GenerateKeyPair(int keySize = 2048)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var rsa = RSA.Create(keySize))
|
||||
{
|
||||
byte[] publicKeyBytes = rsa.ExportRSAPublicKey();
|
||||
byte[] privateKeyBytes = rsa.ExportRSAPrivateKey();
|
||||
|
||||
string publicKey = Convert.ToBase64String(publicKeyBytes);
|
||||
string privateKey = Convert.ToBase64String(privateKeyBytes);
|
||||
|
||||
return (publicKey, privateKey);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"密钥生成失败: {ex.Message}");
|
||||
return (null, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static string? SignData(string data, string privateKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var rsa = RSA.Create())
|
||||
{
|
||||
byte[] privateKeyBytes = Convert.FromBase64String(privateKey);
|
||||
|
||||
try
|
||||
{
|
||||
rsa.ImportRSAPrivateKey(privateKeyBytes, out _);
|
||||
}
|
||||
catch
|
||||
{
|
||||
rsa.ImportPkcs8PrivateKey(privateKeyBytes, out _);
|
||||
}
|
||||
|
||||
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
|
||||
byte[] signature = rsa.SignData(dataBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||
|
||||
return Convert.ToBase64String(signature);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 其他方法...
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ramitta.Excellib
|
||||
namespace Ramitta.lib
|
||||
{
|
||||
public static class Excel
|
||||
{
|
||||
|
||||
@@ -344,13 +344,32 @@ namespace Ramitta.lib
|
||||
#endregion
|
||||
|
||||
// 通过 UDP 发送消息
|
||||
public static void SendUdpMessage(string _serverIp, int _serverPort,string message)
|
||||
public static void SendUdpMessage(string _serverIp, int _serverPort, string message)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (UdpClient udpClient = new UdpClient())
|
||||
{
|
||||
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(_serverIp), _serverPort);
|
||||
IPEndPoint endPoint;
|
||||
|
||||
// 真正的自动识别:先尝试解析为IP地址,失败则当作域名处理
|
||||
if (IPAddress.TryParse(_serverIp, out IPAddress ipAddress))
|
||||
{
|
||||
// 输入的是IP地址
|
||||
endPoint = new IPEndPoint(ipAddress, _serverPort);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 输入的是域名,进行DNS解析
|
||||
IPAddress[] addresses = Dns.GetHostAddresses(_serverIp);
|
||||
if (addresses.Length == 0)
|
||||
{
|
||||
Debug.WriteLine($"无法解析域名: {_serverIp}");
|
||||
return;
|
||||
}
|
||||
endPoint = new IPEndPoint(addresses[0], _serverPort);
|
||||
}
|
||||
|
||||
byte[] messageBytes = Encoding.UTF8.GetBytes(message);
|
||||
udpClient.Send(messageBytes, messageBytes.Length, endPoint);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<PackageReference Include="System.Data.SQLite" Version="2.0.1" />
|
||||
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.119" />
|
||||
<PackageReference Include="System.Data.SQLite.EF6" Version="2.0.1" />
|
||||
<PackageReference Include="System.IO.Ports" Version="9.0.10" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
200
Ramitta/SerialPortHandler.cs
Normal file
200
Ramitta/SerialPortHandler.cs
Normal file
@@ -0,0 +1,200 @@
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
using System.Threading;
|
||||
|
||||
|
||||
namespace Ramitta.lib
|
||||
{
|
||||
|
||||
public class SerialPortHandler : IDisposable
|
||||
{
|
||||
private SerialPort _serialPort;
|
||||
private bool _isConnected = false;
|
||||
|
||||
// 串口连接状态事件
|
||||
public event Action<bool> ConnectionStatusChanged;
|
||||
public event Action<string> DataReceived;
|
||||
public event Action<string> ErrorOccurred;
|
||||
|
||||
public SerialPortHandler()
|
||||
{
|
||||
_serialPort = new SerialPort();
|
||||
_serialPort.DataReceived += SerialPort_DataReceived;
|
||||
_serialPort.ErrorReceived += SerialPort_ErrorReceived;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取可用的串口列表
|
||||
/// </summary>
|
||||
public string[] GetAvailablePorts()
|
||||
{
|
||||
return SerialPort.GetPortNames();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接串口
|
||||
/// </summary>
|
||||
public bool Connect(string portName, int baudRate = 9600, Parity parity = Parity.None,
|
||||
int dataBits = 8, StopBits stopBits = StopBits.One)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_isConnected)
|
||||
Disconnect();
|
||||
|
||||
_serialPort.PortName = portName;
|
||||
_serialPort.BaudRate = baudRate;
|
||||
_serialPort.Parity = parity;
|
||||
_serialPort.DataBits = dataBits;
|
||||
_serialPort.StopBits = stopBits;
|
||||
_serialPort.Handshake = Handshake.None;
|
||||
_serialPort.ReadTimeout = 1000;
|
||||
_serialPort.WriteTimeout = 1000;
|
||||
|
||||
_serialPort.Open();
|
||||
_isConnected = true;
|
||||
|
||||
ConnectionStatusChanged?.Invoke(true);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorOccurred?.Invoke($"连接串口失败: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 断开串口连接
|
||||
/// </summary>
|
||||
public void Disconnect()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_serialPort.IsOpen)
|
||||
{
|
||||
_serialPort.Close();
|
||||
_isConnected = false;
|
||||
ConnectionStatusChanged?.Invoke(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorOccurred?.Invoke($"断开串口失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送数据
|
||||
/// </summary>
|
||||
public bool SendData(string data)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_isConnected)
|
||||
{
|
||||
ErrorOccurred?.Invoke("串口未连接");
|
||||
return false;
|
||||
}
|
||||
|
||||
_serialPort.WriteLine(data);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorOccurred?.Invoke($"发送数据失败: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送字节数据
|
||||
/// </summary>
|
||||
public bool SendBytes(byte[] data)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_isConnected)
|
||||
{
|
||||
ErrorOccurred?.Invoke("串口未连接");
|
||||
return false;
|
||||
}
|
||||
|
||||
_serialPort.Write(data, 0, data.Length);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorOccurred?.Invoke($"发送字节数据失败: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取数据
|
||||
/// </summary>
|
||||
public string ReadData()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_isConnected)
|
||||
{
|
||||
ErrorOccurred?.Invoke("串口未连接");
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return _serialPort.ReadExisting();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorOccurred?.Invoke($"读取数据失败: {ex.Message}");
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取连接状态
|
||||
/// </summary>
|
||||
public bool IsConnected => _isConnected;
|
||||
|
||||
/// <summary>
|
||||
/// 获取串口信息
|
||||
/// </summary>
|
||||
public string GetPortInfo()
|
||||
{
|
||||
if (!_isConnected)
|
||||
return "串口未连接";
|
||||
|
||||
return $"{_serialPort.PortName} - {_serialPort.BaudRate}bps, {_serialPort.DataBits}数据位, {_serialPort.StopBits}停止位";
|
||||
}
|
||||
|
||||
// 数据接收事件处理
|
||||
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
string data = _serialPort.ReadExisting();
|
||||
DataReceived?.Invoke(data);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorOccurred?.Invoke($"数据接收错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// 错误接收事件处理
|
||||
private void SerialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
|
||||
{
|
||||
ErrorOccurred?.Invoke($"串口错误: {e.EventType}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Disconnect();
|
||||
_serialPort?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user