Ruyi_client_new/wb_unity_pro_jx/Assets/Scripts/RSAHelper.cs

236 lines
12 KiB
C#
Raw Normal View History

2025-12-04 15:59:26 +08:00
using System;
using System.Text;
using System.Security.Cryptography;
public static class RSAHelper
{
private static string publicKey =
"MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAmZLmb4paD13E2uOueFStT1g8OnA4JQYkN4PZl/il7Nb05EbZrRbQz/5VbiZxc+S4asfFrrU0d++gjiluiAbBBhgtQSi+eNZuJ2wrBxjvN3W9d14XMmZKDg21Knu7tDUwOlEfCPVMZ/nJ+9YU6mnEvme29UgpI4RbEIIWPuDW3DavbaOvZ/cYP+0m2pxU3mETwDbVpbM3LimJ4JOBIs7XhV2UqEUfRVCYiuZUkydOCs1TgTJRJC5qgYpx4wUZ0ja7t9jP3klg/vjjyA1SDnC98bQLR5QzVJE1LvI2Rr3AHfZS0hckg0WAR87D1R8sGjmQ0TUi4qanpQYhEL4dBH8a6TX/xssobM7M+XgFsGiT4fWG18JhJM98rhVEk2AUaXgnFNf3OyLP+NuYrqjYamuug00s2azCl/rQCkvnLWO4W+lPn27ZinnBRg1+r2fNws7dPPa/8tWScRcTtfaidYsQP2lnYJvFgc299HdQL7iFgL336NihUxll09Hhm7vf8+N0ZP5TLE8SRoSfHNgHup6k9YG5e+V9bW4VckQFgPPBlHSS0mDEOvD9d54+F1cBg/sG8XMduW5WhfroYsMbRzB9a4rIfctn6yqpM+ot2EW8CKgiOVM5lJQhBwX5rMKnMTaApt6EIigY6jRVFNCOtQPDZ9prLBsp3asQxf7Vg9kfrVUCAwEAAQ==";
private static string privateKey =
"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";
// 公钥加密
public static string Encrypt(string plainText)
{
using (RSACryptoServiceProvider rsa = RSAHelper.CreateFromBase64PublicKey(publicKey))
{
byte[] data = Encoding.UTF8.GetBytes(plainText);
byte[] enc = rsa.Encrypt(data, false);
Debugger.Log(Convert.ToBase64String(rsa.Encrypt(Encoding.UTF8.GetBytes("{\"password\":\"111111\",\"deviceCode\":\"281a228fac1c29d25c1a3e572b15ad47d5f66811\",\"id\":777777}"),false)));
return Convert.ToBase64String(enc);
}
}
/// <summary>
/// 将 Base64 公钥DER 格式)转换成 RSACryptoServiceProvider 可用的 XML 公钥
/// </summary>
/// <param name="base64PublicKey">Base64 编码的 DER 公钥</param>
/// <returns>RSACryptoServiceProvider 实例</returns>
private static RSACryptoServiceProvider CreateFromBase64PublicKey(string base64PublicKey)
{
byte[] keyBytes = Convert.FromBase64String(base64PublicKey);
// 解析 DER 格式的公钥,获取 Modulus 和 Exponent
int offset = 0;
if (keyBytes[offset++] != 0x30) throw new Exception("Invalid public key format");
ReadLengthPublic(keyBytes, ref offset); // 跳过序列长度
// 跳过算法标识部分
if (keyBytes[offset++] != 0x30) throw new Exception("Invalid public key format");
ReadLengthPublic(keyBytes, ref offset);
offset += 13; // rsaEncryption OID + NULL
if (keyBytes[offset++] != 0x03) throw new Exception("Invalid public key format");
int bitStringLength = ReadLengthPublic(keyBytes, ref offset);
offset++; // unused bits
if (keyBytes[offset++] != 0x30) throw new Exception("Invalid public key format");
ReadLengthPublic(keyBytes, ref offset);
// 读取 Modulus
if (keyBytes[offset++] != 0x02) throw new Exception("Invalid public key format");
int modulusLength = ReadLengthPublic(keyBytes, ref offset);
byte[] modulus = new byte[modulusLength];
Array.Copy(keyBytes, offset, modulus, 0, modulusLength);
offset += modulusLength;
// 读取 Exponent
if (keyBytes[offset++] != 0x02) throw new Exception("Invalid public key format");
int exponentLength = ReadLengthPublic(keyBytes, ref offset);
byte[] exponent = new byte[exponentLength];
Array.Copy(keyBytes, offset, exponent, 0, exponentLength);
// 构造 XML
string xml = $"<RSAKeyValue><Modulus>{Convert.ToBase64String(modulus)}</Modulus><Exponent>{Convert.ToBase64String(exponent)}</Exponent></RSAKeyValue>";
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(xml);
return rsa;
}
private static int ReadLengthPublic(byte[] data, ref int offset)
{
int length = data[offset++];
if ((length & 0x80) == 0x80)
{
int bytesCount = length & 0x7F;
length = 0;
for (int i = 0; i < bytesCount; i++)
{
length = (length << 8) | data[offset++];
}
}
return length;
}
/// <summary>
/// 从 Base64 私钥PKCS#1 或 PKCS#8得到 RSACryptoServiceProvider适用于 Unity2019.4
/// </summary>
public static RSACryptoServiceProvider LoadPrivateKeyFromBase64(string base64)
{
if (string.IsNullOrEmpty(base64)) throw new ArgumentNullException(nameof(base64));
byte[] data = Convert.FromBase64String(base64);
// 先尝试解析为 PKCS#8PrivateKeyInfo -> OCTET STRING 包 PKCS#1
try
{
byte[] pkcs1 = TryExtractPkcs1FromPkcs8(data);
return LoadPkcs1(pkcs1);
}
catch (Exception)
{
// 如果不是 PKCS#8再尝试直接解析 PKCS#1
return LoadPkcs1(data);
}
}
private static byte[] TryExtractPkcs1FromPkcs8(byte[] data)
{
int offset = 0;
// Expect: SEQUENCE
if (data[offset++] != 0x30) throw new Exception("Not a valid ASN.1 SEQUENCE (PKCS#8)");
ReadLength(data, ref offset); // skip top-level length
// Optional version INTEGER (usually present)
if (data[offset] == 0x02)
{
offset++; // tag
int verLen = ReadLength(data, ref offset);
offset += verLen;
}
// Next should be algorithmIdentifier (SEQUENCE) — skip it properly
if (data[offset] != 0x30) throw new Exception("Invalid PKCS#8, missing alg sequence");
offset++; // tag
int algLen = ReadLength(data, ref offset);
offset += algLen;
// Next should be OCTET STRING (privateKey)
if (data[offset++] != 0x04) throw new Exception("Invalid PKCS#8, missing privateKey OCTET STRING");
int pkcs1Len = ReadLength(data, ref offset);
if (offset + pkcs1Len > data.Length) throw new Exception("Invalid lengths in PKCS#8");
byte[] inner = new byte[pkcs1Len];
Buffer.BlockCopy(data, offset, inner, 0, pkcs1Len);
return inner;
}
private static RSACryptoServiceProvider LoadPkcs1(byte[] data)
{
int offset = 0;
if (data[offset++] != 0x30) throw new Exception("Invalid PKCS#1: no SEQUENCE");
ReadLength(data, ref offset);
// version INTEGER (skip)
if (data[offset] == 0x02)
{
offset++; // tag
int vlen = ReadLength(data, ref offset);
offset += vlen;
}
RSAParameters p = new RSAParameters();
p.Modulus = ReadInteger(data, ref offset, "Modulus");
p.Exponent = ReadInteger(data, ref offset, "Public Exponent");
p.D = ReadInteger(data, ref offset, "Private Exponent");
p.P = ReadInteger(data, ref offset, "P");
p.Q = ReadInteger(data, ref offset, "Q");
p.DP = ReadInteger(data, ref offset, "DP");
p.DQ = ReadInteger(data, ref offset, "DQ");
p.InverseQ = ReadInteger(data, ref offset, "InverseQ");
var rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(p);
return rsa;
}
private static byte[] ReadInteger(byte[] data, ref int offset, string nameForError = null)
{
if (data[offset] != 0x02)
{
// 报错时输出附近几个字节,便于调试
string hexSnippet = GetHexSnippet(data, offset, 12);
throw new Exception($"Expected INTEGER at offset {offset} ({nameForError ?? ""}), but found 0x{data[offset]:X2}. Nearby: {hexSnippet}");
}
offset++; // skip INTEGER tag
int len = ReadLength(data, ref offset);
// 如果有前导 0x00, 去掉(去除符号位)
if (len > 0 && data[offset] == 0x00)
{
offset++;
len--;
}
if (len < 0 || offset + len > data.Length) throw new Exception("Invalid integer length");
byte[] value = new byte[len];
Buffer.BlockCopy(data, offset, value, 0, len);
offset += len;
return value;
}
private static int ReadLength(byte[] data, ref int offset)
{
if (offset >= data.Length) throw new Exception("Invalid offset while reading length");
int length = data[offset++];
if ((length & 0x80) == 0) // short form
{
return length;
}
int bytesCount = length & 0x7F;
if (bytesCount <= 0 || bytesCount > 4) throw new Exception("Invalid length bytes");
if (offset + bytesCount > data.Length) throw new Exception("Invalid length (overflow)");
int val = 0;
for (int i = 0; i < bytesCount; i++)
{
val = (val << 8) | data[offset++];
}
return val;
}
private static string GetHexSnippet(byte[] data, int offset, int maxLen)
{
int start = Math.Max(0, offset - 6);
int end = Math.Min(data.Length, offset + maxLen);
System.Text.StringBuilder sb = new System.Text.StringBuilder();
for (int i = start; i < end; i++)
{
sb.AppendFormat("{0:X2} ", data[i]);
}
return sb.ToString().Trim();
}
// 私钥解密
public static string Decrypt(string cipherText)
{
using (RSACryptoServiceProvider rsa = RSAHelper.LoadPrivateKeyFromBase64(privateKey))
{
byte[] data = Convert.FromBase64String(cipherText);
byte[] dec = rsa.Decrypt(data, false);
return Encoding.UTF8.GetString(dec);
}
}
}