目的
将license信息在nodejs服务端加密,将license导入c#开发的window桌面应用程序进行license信息解密提取其中的激活信息,进行软件激活。
代码分享
c# 密钥生成和加密代码参考了 C# javascript js RSA非对称加解密的实现
我是使用的pem格式的公钥和密钥,使用在c#里生成,pkcs1和pkcs8都是可以的,nodejs生成的公钥密钥我还没有测试过。
nodejs端需要使用 node-jsencrypt 模块
npm i node-jsencrypt -s
C#代码
RSACryptoHelper.cs
public static class RSACryptoHelper
{
/// <summary>
/// 取得私钥和公钥 XML 格式,返回数组第一个是私钥,第二个是公钥.
/// </summary>
/// <param name="size">密钥长度,默认1024,可以为2048</param>
/// <returns></returns>
public static string[] CreateXmlKey(int size = 1024)
{
//密钥格式要生成pkcs#1格式的 而不是pkcs#8格式的
RSACryptoServiceProvider sp = new RSACryptoServiceProvider(size);
string privateKey = sp.ToXmlString(true);//private key
string publicKey = sp.ToXmlString(false);//public key
return new string[] { privateKey, publicKey };
}
/// <summary>
/// 取得私钥和公钥 CspBlob 格式,返回数组第一个是私钥,第二个是公钥.
/// </summary>
/// <param name="size"></param>
/// <returns></returns>
public static string[] CreateCspBlobKey(int size = 1024)
{
//密钥格式要生成pkcs#1格式的 而不是pkcs#8格式的
RSACryptoServiceProvider sp = new RSACryptoServiceProvider(size);
string privateKey = Convert.ToBase64String(sp.ExportCspBlob(true));//private key
string publicKey = Convert.ToBase64String(sp.ExportCspBlob(false));//public key
return new string[] { privateKey, publicKey };
}
/// <summary>
/// 导出PEM PKCS#1格式密钥对,返回数组第一个是私钥,第二个是公钥.
/// </summary>
public static string[] CreateKey_PEM_PKCS1(int size = 1024)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(size);
string privateKey = RSA_PEM.ToPEM(rsa, false, false);
string publicKey = RSA_PEM.ToPEM(rsa, true, false);
return new string[] { privateKey, publicKey };
}
/// <summary>
/// 导出PEM PKCS#8格式密钥对,返回数组第一个是私钥,第二个是公钥.
/// </summary>
public static string[] CreateKey_PEM_PKCS8(int size = 1024)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(size);
string privateKey = RSA_PEM.ToPEM(rsa, false, true);
string publicKey = RSA_PEM.ToPEM(rsa, true, true);
return new string[] { privateKey, publicKey };
}
/// <summary>
/// 加密 用的是PEM格式的密钥
/// </summary>
/// <param name="str_Plain_Text">要加密的数据</param>
/// <param name="str_Public_PEMKey"></param>
/// <returns></returns>
public static string Encrypt_PEMKey(string str_Plain_Text, string str_Public_PEMKey)
{
using (RSACryptoServiceProvider RSA = RSA_PEM.FromPEM(str_Public_PEMKey))
{
return Encrypt(str_Plain_Text, RSA);
}
}
/// <summary>
/// 加密 用的是Xml格式的密钥
/// </summary>
/// <param name="str_Plain_Text">要加密的数据</param>
/// <param name="str_Public_XmlKey">Xml格式的公钥</param>
/// <returns></returns>
public static string Encrypt_XmlKey(string str_Plain_Text, string str_Public_XmlKey)
{
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
RSA.FromXmlString(str_Public_XmlKey);//载入公钥
return Encrypt(str_Plain_Text, RSA);
}
}
private static string Encrypt(string str_Plain_Text, RSACryptoServiceProvider RSA)
{
var data = Encoding.UTF8.GetBytes(str_Plain_Text);
int buffersize = (RSA.KeySize / 8) - 11;
var buffer = new byte[buffersize];
using (MemoryStream input = new MemoryStream(data), output = new MemoryStream())
{
while (true)
{
int readsize = input.Read(buffer, 0, buffersize);
if (readsize <= 0)
{
break;
}
var temp = new byte[readsize];
Array.Copy(buffer, 0, temp, 0, readsize);
var EncBytes = RSA.Encrypt(temp, false);
output.Write(EncBytes, 0, EncBytes.Length);
}
return Convert.ToBase64String(output.ToArray());
}
}
/// <summary>
/// 解密 用的是Xml格式的密钥
/// </summary>
/// <param name="str_Cypher_Text">密文</param>
/// <param name="str_Private_Key">密钥</param>
/// <returns></returns>
public static string Decrypt_XmlKey(string str_Cypher_Text, string str_Private_XmlKey)
{
using (var RSA = new RSACryptoServiceProvider())
{
RSA.FromXmlString(str_Private_XmlKey);
return Decrypt(str_Cypher_Text, RSA);
}
}
/// <summary>
/// 解密 用的是PEM格式的密钥
/// </summary>
/// <param name="str_Cypher_Text">密文</param>
/// <param name="str_Private_Key">密钥</param>
/// <returns></returns>
public static string Decrypt_PEMKey(string str_Cypher_Text, string str_Private_PEMKey)
{
//using (var RSA = new RSACryptoServiceProvider())
using (var RSA = RSA_PEM.FromPEM(str_Private_PEMKey))
{
return Decrypt(str_Cypher_Text, RSA);
}
}
private static string Decrypt(string str_Cypher_Text, RSACryptoServiceProvider RSA)
{
var data = Convert.FromBase64String(str_Cypher_Text);
//RSA.FromXmlString(str_Private_Key);
int buffersize = RSA.KeySize / 8;
var buffer = new byte[buffersize];
using (MemoryStream input = new MemoryStream(data),
output = new MemoryStream())
{
while (true)
{
int readsize = input.Read(buffer, 0, buffersize);
if (readsize <= 0)
{
break;
}
var temp = new byte[readsize];
Array.Copy(buffer, 0, temp, 0, readsize);
var DecBytes = RSA.Decrypt(temp, false);
output.Write(DecBytes, 0, DecBytes.Length);
}
return Encoding.UTF8.GetString(output.ToArray());
}
}
}
RSA_Unit.cs
/// <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);
}
}
RSA_PEM.cs
/// <summary>
/// RSA PEM格式秘钥对的解析和导出
/// </summary>
public class RSA_PEM
{
/// <summary>
/// 用PEM格式密钥对创建RSA,支持PKCS#1、PKCS#8格式的PEM
/// </summary>
public static RSACryptoServiceProvider FromPEM(string pem)
{
var rsaParams = new CspParameters();
rsaParams.Flags = CspProviderFlags.UseMachineKeyStore;
var rsa = new RSACryptoServiceProvider(rsaParams);
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;
}
static private Regex _PEMCode = new Regex(@"--+.+?--+|\s+");
static private byte[] _SeqOID = new byte[] { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
static private byte[] _Ver = new byte[] { 0x02, 0x01, 0x00 };
/// <summary>
/// 将RSA中的密钥对转换成PEM格式,usePKCS8=false时返回PKCS#1格式,否则返回PKCS#8格式,如果convertToPublic含私钥的RSA将只返回公钥,仅含公钥的RSA不受影响
/// </summary>
public static string ToPEM(RSACryptoServiceProvider rsa, bool convertToPublic, bool usePKCS8)
{
//https://www.jianshu.com/p/25803dd9527d
//https://www.cnblogs.com/ylz8401/p/8443819.html
//https://blog.csdn.net/jiayanhui2877/article/details/47187077
//https://blog.csdn.net/xuanshao_/article/details/51679824
//https://blog.csdn.net/xuanshao_/article/details/51672547
var ms = new MemoryStream();
//写入一个长度字节码
Action<int> writeLenByte = (len) =>
{
if (len < 0x80)
{
ms.WriteByte((byte)len);
}
else if (len <= 0xff)
{
ms.WriteByte(0x81);
ms.WriteByte((byte)len);
}
else
{
ms.WriteByte(0x82);
ms.WriteByte((byte)(len >> 8 & 0xff));
ms.WriteByte((byte)(len & 0xff));
}
};
//写入一块数据
Action<byte[]> writeBlock = (byts) =>
{
var addZero = (byts[0] >> 4) >= 0x8;
ms.WriteByte(0x02);
var len = byts.Length + (addZero ? 1 : 0);
writeLenByte(len);
if (addZero)
{
ms.WriteByte(0x00);
}
ms.Write(byts, 0, byts.Length);
};
//根据后续内容长度写入长度数据
Func<int, byte[], byte[]> writeLen = (index, byts) =>
{
var len = byts.Length - index;
ms.SetLength(0);
ms.Write(byts, 0, index);
writeLenByte(len);
ms.Write(byts, index, len);
return ms.ToArray();
};
if (rsa.PublicOnly || convertToPublic)
{
/****生成公钥****/
var param = rsa.ExportParameters(false);
//写入总字节数,不含本段长度,额外需要24字节的头,后续计算好填入
ms.WriteByte(0x30);
var index1 = (int)ms.Length;
//固定内容
// encoded OID sequence for PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
ms.writeAll(_SeqOID);
//从0x00开始的后续长度
ms.WriteByte(0x03);
var index2 = (int)ms.Length;
ms.WriteByte(0x00);
//后续内容长度
ms.WriteByte(0x30);
var index3 = (int)ms.Length;
//写入Modulus
writeBlock(param.Modulus);
//写入Exponent
writeBlock(param.Exponent);
//计算空缺的长度
var byts = ms.ToArray();
byts = writeLen(index3, byts);
byts = writeLen(index2, byts);
byts = writeLen(index1, byts);
return "-----BEGIN PUBLIC KEY-----\n" + RSA_Unit.TextBreak(RSA_Unit.Base64EncodeBytes(byts), 64) + "\n-----END PUBLIC KEY-----";
}
else
{
/****生成私钥****/
var param = rsa.ExportParameters(true);
//写入总字节数,后续写入
ms.WriteByte(0x30);
int index1 = (int)ms.Length;
//写入版本号
ms.writeAll(_Ver);
//PKCS8 多一段数据
int index2 = -1, index3 = -1;
if (usePKCS8)
{
//固定内容
ms.writeAll(_SeqOID);
//后续内容长度
ms.WriteByte(0x04);
index2 = (int)ms.Length;
//后续内容长度
ms.WriteByte(0x30);
index3 = (int)ms.Length;
//写入版本号
ms.writeAll(_Ver);
}
//写入数据
writeBlock(param.Modulus);
writeBlock(param.Exponent);
writeBlock(param.D);
writeBlock(param.P);
writeBlock(param.Q);
writeBlock(param.DP);
writeBlock(param.DQ);
writeBlock(param.InverseQ);
//计算空缺的长度
var byts = ms.ToArray();
if (index2 != -1)
{
byts = writeLen(index3, byts);
byts = writeLen(index2, byts);
}
byts = writeLen(index1, byts);
var flag = " PRIVATE KEY";
if (!usePKCS8)
{
flag = " RSA" + flag;
}
return "-----BEGIN" + flag + "-----\n" + RSA_Unit.TextBreak(RSA_Unit.Base64EncodeBytes(byts), 64) + "\n-----END" + flag + "-----";
}
}
}
解密
string pkcs1_private = "-----BEGIN RSA PRIVATE KEY-----\n" +
"MIIEowIBAAKCAQEA9zhzkpG+YFDtm+MpNR17dHW2k+r8gzEJmU5IMUeiVOBAYGr+\n" +
"p6+bvRIGnNOdb4nZpdl/zgeuO1v/f5H0eTIW4E/xvDb2k81ucAcuJbX81p2sFtaP\n" +
"vH1NdVmXPLDsOrgQnF9W63WU25JZNp7F+47lX2wJLPcShJ8TIvmW5PA0JARMafpW\n" +
"wDL2zyraUAvJvIOdFWdhy+ejWLMckpyh2LuCnF41CAjPmg68PN4+McavQoTCXAZf\n" +
"IpmZuWrfK8Xfe1RWE6f3G7QQvlTN67NNR8NVjOrJEoL/MntMR4pfnRoCGIqzirTO\n" +
"vhpJes5/sntNM3zuqXF3POlgCEwI1/HxmQ7Y+QIDAQABAoIBAA1dcOoQlQEx/tZ5\n" +
"nmWvtVfjcT5n6sTQ5trx33dCjyUVhoVv41p/ZOUAz3i0/ALmqeyMaJtj0OiGnbZw\n" +
"1o2ixpfT2pa5RfVRmtHVoYoKX6PenEoTyWuAPqrEcCeozOyTvNonUVSjY6vHKqmI\n" +
"Rd3GqOHSvmA+7zJaQzeV1LGFxtvXgHKGSlStJaO+BE3wiJT6izfrYBt3+CHZeH4P\n" +
"drAxu8fjHOXrF7YaBFORS5neoB72hkQsRLyfYvaxPr1LNcfy0ks50ErHsZIySTg5\n" +
"v+lV20XDoHTqpcBe0GQACZ+7NXY6/6JfeY+44SKM+n74Z1gn2CqLDdRze6WG7ujq\n" +
"yvNUUb0CgYEA/Oja01UExw60GVRyMjzcRQcBKWZNEjxaAgMmSg+Vi1lpzm9I2R6z\n" +
"uHTmu9SZfEA3z46mIRFrkdnaUh8NdovPIxB0kuqC4e+KQFFs+dRn3k1MmwDd8us0\n" +
"XLGs/gmUbgdbOlRAI//JCTDnvL6Wfngv4bIPXqnBXSPRcW1ujLGHyUMCgYEA+j3M\n" +
"3Sl3STGRaaEl8iRQaCK7er0G5/l6PoFNrnHC5+YK0Ly7zHzR/PJobo3cM7BjjDjH\n" +
"3ORM6eG3nByxQFEX7pVdeoxhEAj3ibx0IDcvfaJl4JJ31xjrseSXiZ9Pu/4Tqj9D\n" +
"Ukn0aeBmk9iWrU8xkghGZTN3xiAMJ25vwBTiYxMCgYEA7BKXICj9+qj456PxrH8u\n" +
"xKgTJ4e8bUc0ZSh3dy4w0xA1OWKbRz/nVkiYj7+VPWvcLLvkyn0uQchuh7VApeU/\n" +
"BmX3yqNoZGlqTTs0U8c25USWOyGGC5gNGnEnH0Hl8Qag20OFU5URHKkvxvjIFWku\n" +
"mKfSvPQL8Frcx9n0FRQpwW0CgYAhJ4z8BGFsjiew8gvgABWzJl7mjSLcGz6qB2Gu\n" +
"ah4jsWPfchIDrsn3lHpno134bzdRPbilOI5EMoasJVUKq3PbRWjkMrMtd7KsSg6s\n" +
"sgMVxy1uSpmcIw4fPKUjM7tRsgES/lzCC1BZssSEdB7KiYKM0ZHaGK6Wzmot00D1\n" +
"Fw9DhwKBgDLss7dqk9tUfM3sjQbIVxLi+D0Vmi7jD4AIQQZoVQn390hZ75C/j02m\n" +
"4w/Lm065PASYxAN551AmpILzJSF3YdxzrAoAAP21itCLT0HVEU54UdqQwHsmsSEk\n" +
"0y+RbOs702xclseYd3hVG8mIaC3wIX31iDMAqz/qSsYUe4BCIb+5\n" +
"-----END RSA PRIVATE KEY-----";
string pkcs1_public = "-----BEGIN PUBLIC KEY-----\n" +
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9zhzkpG+YFDtm+MpNR17\n" +
"dHW2k+r8gzEJmU5IMUeiVOBAYGr+p6+bvRIGnNOdb4nZpdl/zgeuO1v/f5H0eTIW\n" +
"4E/xvDb2k81ucAcuJbX81p2sFtaPvH1NdVmXPLDsOrgQnF9W63WU25JZNp7F+47l\n" +
"X2wJLPcShJ8TIvmW5PA0JARMafpWwDL2zyraUAvJvIOdFWdhy+ejWLMckpyh2LuC\n" +
"nF41CAjPmg68PN4+McavQoTCXAZfIpmZuWrfK8Xfe1RWE6f3G7QQvlTN67NNR8NV\n" +
"jOrJEoL/MntMR4pfnRoCGIqzirTOvhpJes5/sntNM3zuqXF3POlgCEwI1/HxmQ7Y\n" +
"+QIDAQAB\n" +
"-----END PUBLIC KEY-----";
string pkcs8_private = "-----BEGIN PRIVATE KEY-----\n" +
"MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCvB5m7LDu1+u2X\n" +
"xqHMF20tqAseN0qwqbMPlw43GCh42uHFC2AXKqWvZCAJ8LaI5Ludk8IPwYVWz5Sz\n" +
"UDJxgvSGTXs2vFpSKnvM8dP2nUwTDKUt6gKRayBZnMVZcShz7aVk5VD7Uco/0224\n" +
"kqyQRaC675vLROIgLv0Bu87NqZ83uau2YcuGSbTtmn+JOBt52SuLfd9uFGCA+mRu\n" +
"/R0lYDLjFNjUUwCqKtqPWMDk1uPs8wIPfvBd4tz3TiwUgK1tCTjqvWrP36Wp2aeO\n" +
"wcyrTZJOol1uG8ZXtOJ/wWb3CUkeFT36m0Zs9+YKbXasee2CYrMeas5ywLVVjq6l\n" +
"KMCYeW05AgMBAAECggEANcDQzrHr+JyCoU0oXYSITDBCkdoLPywuyMfsXrE1pMAb\n" +
"/CbdMOAxGCdYy5S4ilws3l0FiU82gw2nLlaf10qPjDt5brrzxi4z7SILpb5zIZqN\n" +
"lAc9GKncuoix9yEQemHunIjskPJyeZ2WIcwx4PDxRtfVcdzK0XV80C58eZ7xPexu\n" +
"TSaj7W+JXr7gdhEC0+BeRTT62nOx/ElBZGtywAKj0AZmWO7phx44EcUGuTki6COV\n" +
"trY/HlkOLTHgu2uu6NufAVp6GYdNojj20ZvEyljuOTlWZjd/HizhxoiyHZD2rf9X\n" +
"wTEdINpEEIT5VNfAtvbBzWaztPvzbID1/Jt6iQg8jQKBgQDD0umeFL5SqZzAdpIR\n" +
"pTDzy4BYuOMiudYn0OD5B9m/4u5g5JPG2AL+94SOzsUexR6zgeBPo/WobiVBd3ZV\n" +
"BMG8+OrIQdaBEaAd4911fldX/rhn+tAXBmv+pbcC3LXNfYYNVR4CzcGEAHbXATL8\n" +
"HipBWsCeT0bXXOBjiDKZypKhbwKBgQDk0Nlm/0GaH/eZsRYIWA6Xz558wX9h+iFA\n" +
"ecXqTPNDtvlMOp8uJO+I3gmvvICal/FvjktU7MAb3riu0QgGt7D9730xsm7bSXju\n" +
"DZx1hbHayewgN9WlZpOkQBF657PaeZmcOAq/ss7JLpGfRu8cCuzrqdadbRyuR/46\n" +
"QL9eNys31wKBgCOcYVucDhheO+FMLrgCwGo1YbvAs52HCgjnlWH0KYcZr5vzNWR9\n" +
"t93CCVsnAvXbhv/B6JbTDEN69E95eA1x9gF1isysHGQQXnvRCl7pgNzBt6tBE0J8\n" +
"qnr+i897b5xU7WHTTsfXvw9QPkxPLYRnv+tuo4Smig10GGJBTGJnUk8FAoGBAKgB\n" +
"kR9HHOwFvM9kb0EBJvXgxAXmLZnLBs9ImkFG7vcxSirmgCpphFeCcKpQRj08g1Hd\n" +
"sQJSM1xDVGdHpBUKmzJYvhvXX/4zHE/uPosr90MmL/IYDQ69Gnrnb+5GYpBv6JID\n" +
"tCC9MYgWYWYJt1dnzj3bHnHIw95Tjh9HmzuaVmlRAoGBALFTaeGbhf8k6x/amSvV\n" +
"lowpsYgTAuR02GUIn80fG5blcAjIMCs8/J3E7p0qvZgW7+dMpHFWPUJzvQBD/iLF\n" +
"VqVdhjQAvoJT5dpTuHCaQObt7LwMpjdPB3W0vMNQx/z5RppKrIbA4ZH8KNNByvHI\n" +
"5PyXdToSZCKBULOYal41l5Va\n" +
"-----END PRIVATE KEY-----";
string pkcs8_public = "-----BEGIN PUBLIC KEY-----\n" +
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArweZuyw7tfrtl8ahzBdt\n" +
"LagLHjdKsKmzD5cONxgoeNrhxQtgFyqlr2QgCfC2iOS7nZPCD8GFVs+Us1AycYL0\n" +
"hk17NrxaUip7zPHT9p1MEwylLeoCkWsgWZzFWXEoc+2lZOVQ+1HKP9NtuJKskEWg\n" +
"uu+by0TiIC79AbvOzamfN7mrtmHLhkm07Zp/iTgbedkri33fbhRggPpkbv0dJWAy\n" +
"4xTY1FMAqiraj1jA5Nbj7PMCD37wXeLc904sFICtbQk46r1qz9+lqdmnjsHMq02S\n" +
"TqJdbhvGV7Tif8Fm9wlJHhU9+ptGbPfmCm12rHntgmKzHmrOcsC1VY6upSjAmHlt\n" +
"OQIDAQAB\n" +
"-----END PUBLIC KEY-----";
string data = "nodejs端使用公钥加密的密文";
string[] splitKey = { "-SPLIT-" };
string[] result = data.Split(splitKey, StringSplitOptions.RemoveEmptyEntries);
Console.WriteLine(result.Length);
string[] decryptArr = new string[result.Length];
//使用了-SPLIT-分割多份密文
for (var i = 0; i < result.Length; i++)
{
string encryptData = result[i];
string decryptData = RSACryptoHelper.Decrypt_PEMKey(encryptData, pkcs1_private);
decryptArr[i] = decryptData;
}
string decryptStr = string.Join("", decryptArr);
//原始字符串使用了base64编码了一次,解密是使用base64转码回去
string original = Encoding.UTF8.GetString(Convert.FromBase64String(decryptStr));
Console.WriteLine(original);
Nodejs代码
nodejs写的是测试代码,但实际逻辑代码基本就这样处理。
test.js
let util = require('./common/util');
const fs = require('fs');
let JSEncrypt = require('node-jsencrypt');
async function main() {
let splitKey = '-SPLIT-';
let publicKey = await fs.readFileSync('../key/pkcs1_public.pem');
let privateKey = await fs.readFileSync('../key/pkcs1_private.pem');
let aa = "需要加密的明文";
let start = 0, size = 100;
let encyptoArr = [];
let a = util.base64Encode(aa);
console.log(a);
if (a.length > 100) {
while (start < a.length) {
encyptoArr.push(a.slice(start, start + size));
start += size;
}
} else {
encyptoArr.push(a);
}
console.log(encyptoArr.join('') === a);
let result = [];
let encrypted = new JSEncrypt();
encrypted.setPublicKey(publicKey.toString());
console.log(encrypted);
encyptoArr.forEach(item => {
// let bf = Buffer.from(item, 'utf8');
// let encryptData = crypto.publicEncrypt(publicKey, bf).toString('base64');
let encryptData = encrypted.encrypt(item);
result.push(encryptData);
})
console.log(result.join(splitKey)); //result.join(splitKey)就是license信息
//这里是测试在nodejs使用密钥将密文解密
let decrypto = [];
let decrypted = new JSEncrypt();
decrypted.setPrivateKey(privateKey.toString());
result.forEach(item => {
// let bf = Buffer.from(item, 'base64');
// let decryptData = crypto.privateDecrypt(privateKey, bf).toString();
let decryptData = decrypted.decrypt(item);
decrypto.push(decryptData);
})
let oldstr = util.base64Decode(decrypto.join(''));
console.log(oldstr);
}
main().then(() => {
})
util.js
module.exports = {
base64Encode(str) {
if (this.isEmpty(str)) return '';
let data = Buffer.from(str, 'utf8');
return data.toString('base64');
},
base64Decode(str) {
if (this.isEmpty(str)) return '';
let data = Buffer.from(str, 'base64');
return data.toString('utf8');
},
}
前两天使用nodejs内置模块node-rsa和crypto加密后,将密文在c#代码里都不行,什么密文太长啊,这些问题,烦,不过总算是解决了,又可以进行下一个bug的编写了
网上轮子比较多,但是要找到适合自己轮毂的还是要花点心思,我也感谢找到的这个轮子。