Files
Ramitta-lib/Ramitta/CryptoHelper.cs
2025-11-11 16:51:37 +08:00

262 lines
9.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace Ramitta.lib
{
public class CryptoHelper
{
/// <summary>
/// 通过OpenSSH格式私钥计算公钥Base64格式
/// </summary>
/// <param name="openSshPrivateKey">OpenSSH格式的Base64私钥不带PEM头尾</param>
/// <returns>Base64格式的公钥失败返回null</returns>
public static string? GetPublicKeyFromPrivate(string openSshPrivateKey)
{
try
{
using (var rsa = RSA.Create())
{
// 解析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);
return Convert.ToBase64String(signature);
}
}
catch (Exception ex)
{
return null;
}
}
/// <summary>
/// 使用OpenSSH格式私钥解密数据
/// </summary>
public static string? DecryptWithOpenSsh(string encryptedData, string openSshPrivateKey)
{
try
{
using (var rsa = RSA.Create())
{
ImportOpenSshPrivateKey(rsa, openSshPrivateKey);
byte[] encryptedBytes = Convert.FromBase64String(encryptedData);
byte[] decryptedBytes = rsa.Decrypt(encryptedBytes, RSAEncryptionPadding.OaepSHA256);
return Encoding.UTF8.GetString(decryptedBytes);
}
}
catch (Exception ex)
{
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;
}
}
// 其他方法...
}
}