.net core linux下的RSA解密
2019-06-20 本文已影响0人
a9b854aded01
基础部分参考https://blog.csdn.net/sD7O95O/article/details/78412745?locationNum=8&fps=1
但是由于这里的RSA加密/解密主要是针对于由OpenSSL生成的公钥/私钥字符串。ssh-keygen -t rsa 命令生成的公钥私钥是不行的。
如果使用带签名的加密方式字符串就会出现
rsa.ImportParameters(rsaParameters);
无法解析到相应byte的问题
如果使用
rsa = new RSACryptoServiceProvider(keySize, rsaParams);
可以解析带签名的RSA加密字符串,但是在linux下会出现错误
解析出错:System.PlatformNotSupportedException: 'CspParameters' requires Windows Cryptographic API (CAPI), which is not available on this platform.
有依赖包依赖于windows环境下的dll,linux下无法解析。
解决方案:
将参考部分的RSAHelper中rsa.ImportParameters(rsaParameters);获取公钥私钥byte的解析方案用下面解析方式替换掉
/// <summary>
/// 用PEM格式密钥对创建RSA,支持PKCS#1、PKCS#8格式的PEM
/// </summary>
public static System.Security.Cryptography.RSA FromPEM(string pem)
{
var rsa = System.Security.Cryptography.RSA.Create();
var param = new RSAParameters();
var base64 = _PEMCode.Replace(pem, "");
var data = RSA_Unit.Base64DecodeBytes(base64);
if (data == null)
{
throw new Exception("PEM内容无效");
}
var idx = 0;
//读取长度
Func<byte, int> readLen = (first) => {
if (data[idx] == first)
{
idx++;
if (data[idx] == 0x81)
{
idx++;
return data[idx++];
}
else if (data[idx] == 0x82)
{
idx++;
return (((int)data[idx++]) << 8) + data[idx++];
}
else if (data[idx] < 0x80)
{
return data[idx++];
}
}
throw new Exception("PEM未能提取到数据");
};
//读取块数据
Func<byte[]> readBlock = () => {
var len = readLen(0x02);
if (data[idx] == 0x00)
{
idx++;
len--;
}
var val = data.sub(idx, len);
idx += len;
return val;
};
//比较data从idx位置开始是否是byts内容
Func<byte[], bool> eq = (byts) => {
for (var i = 0; i < byts.Length; i++, idx++)
{
if (idx >= data.Length)
{
return false;
}
if (byts[i] != data[idx])
{
return false;
}
}
return true;
};
if (pem.Contains("PUBLIC KEY"))
{
/****使用公钥****/
//读取数据总长度
readLen(0x30);
if (!eq(_SeqOID))
{
throw new Exception("PEM未知格式");
}
//读取1长度
readLen(0x03);
idx++;//跳过0x00
//读取2长度
readLen(0x30);
//Modulus
param.Modulus = readBlock();
//Exponent
param.Exponent = readBlock();
}
else if (pem.Contains("PRIVATE KEY"))
{
/****使用私钥****/
//读取数据总长度
readLen(0x30);
//读取版本号
if (!eq(_Ver))
{
throw new Exception("PEM未知版本");
}
//检测PKCS8
var idx2 = idx;
if (eq(_SeqOID))
{
//读取1长度
readLen(0x04);
//读取2长度
readLen(0x30);
//读取版本号
if (!eq(_Ver))
{
throw new Exception("PEM版本无效");
}
}
else
{
idx = idx2;
}
//读取数据
param.Modulus = readBlock();
param.Exponent = readBlock();
param.D = readBlock();
param.P = readBlock();
param.Q = readBlock();
param.DP = readBlock();
param.DQ = readBlock();
param.InverseQ = readBlock();
}
else
{
throw new Exception("pem需要BEGIN END标头");
}
rsa.ImportParameters(param);
return rsa;
}
依赖方法
/// <summary>
/// 封装的一些通用方法
/// </summary>
public class RSA_Unit
{
static public string Base64EncodeBytes(byte[] byts)
{
return Convert.ToBase64String(byts);
}
static public byte[] Base64DecodeBytes(string str)
{
try
{
return Convert.FromBase64String(str);
}
catch
{
return null;
}
}
/// <summary>
/// 把字符串按每行多少个字断行
/// </summary>
static public string TextBreak(string text, int line)
{
var idx = 0;
var len = text.Length;
var str = new StringBuilder();
while (idx < len)
{
if (idx > 0)
{
str.Append('\n');
}
if (idx + line >= len)
{
str.Append(text.Substring(idx));
}
else
{
str.Append(text.Substring(idx, line));
}
idx += line;
}
return str.ToString();
}
}
static public class Extensions
{
/// <summary>
/// 从数组start开始到指定长度复制一份
/// </summary>
static public T[] sub<T>(this T[] arr, int start, int count)
{
T[] val = new T[count];
for (var i = 0; i < count; i++)
{
val[i] = arr[start + i];
}
return val;
}
static public void writeAll(this Stream stream, byte[] byts)
{
stream.Write(byts, 0, byts.Length);
}
}
这样经过测试上线可以在linux下解析出带签名的RSA加密字符串
var rsa = new RSAHelper(RSAType.RSA, Encoding.UTF8, rsaprivate);
Console.WriteLine("原始字符串:" + connection);
//加密
// string enStr = rsa.Encrypt(str);
// Console.WriteLine("加密字符串:" + enStr);
//解密
// string deStr = rsa.DecodeOrNull(connection);
var deStr = rsa.Decrypt(connection);
Console.WriteLine("解密字符串:" + deStr);
string finalconnection = MySqlHelper(deStr);
被坑了一下午,在同事的帮助下解决这个问题,希望能帮助到那些还再坑里的同学吧O(∩_∩)O哈哈~