public sealed class SHA1withRSA
{

/// <summary>
/// pem SHA1withRSA签名
/// </summary>
/// <param name="content">待签名字符串</param>
/// <param name="privateKey">私钥</param>
/// <param name="input_charset">编码格式</param>
/// <returns>签名后字符串</returns>
public static string sign(string content, string privateKey, string input_charset)
{
byte[] Data = Encoding.GetEncoding(input_charset).GetBytes(content);
RSACryptoServiceProvider rsa = DecodePemPrivateKey(privateKey);
using (var sh = SHA1.Create())
{
byte[] signData = rsa.SignData(Data, sh);
return Convert.ToBase64String(signData);
}

}
/// <summary>
/// pem格式公钥验签
/// </summary>
/// <param name="content">待验签字符串</param>
/// <param name="signedString">签名</param>
/// <param name="publicKey">公钥</param>
/// <param name="input_charset">编码格式</param>
/// <returns>true(通过),false(不通过)</returns>
public static bool verify(string content, string signedString, string publicKey, string input_charset)
{
bool result = false;
byte[] Data = Encoding.GetEncoding(input_charset).GetBytes(content);
byte[] data = Convert.FromBase64String(signedString);
RSAParameters paraPub = ConvertFromPublicKey(publicKey);
RSACryptoServiceProvider rsaPub = new RSACryptoServiceProvider();
rsaPub.ImportParameters(paraPub);
using (var sh = SHA1.Create())
{
result = rsaPub.VerifyData(Data, sh, data);
return result;
}

}

/// <summary>
/// RSA加密
/// </summary>
/// <param name="publickey"></param>
/// <param name="content"></param>
/// <returns></returns>
public static string encrypt(string publickey, string content)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
byte[] cipherbytes;
rsa.ImportParameters(ConvertFromPublicKey(publickey));
cipherbytes = rsa.Encrypt(Encoding.UTF8.GetBytes(content), false);
return Convert.ToBase64String(cipherbytes);
}

/// <summary>
/// 解密
/// </summary>
/// <param name="resData">加密字符串</param>
/// <param name="privateKey">私钥</param>
/// <param name="input_charset">编码格式</param>
/// <returns>明文</returns>
public static string decryptData(string resData, string privateKey, string input_charset)
{
byte[] DataToDecrypt = Convert.FromBase64String(resData);
string result = "";
for (int j = 0; j < DataToDecrypt.Length / 128; j++)
{
byte[] buf = new byte[128];
for (int i = 0; i < 128; i++)
{

buf[i] = DataToDecrypt[i + 128 * j];
}
result += decrypt(buf, privateKey, input_charset);
}
return result;
}

#region 内部方法

private static string decrypt(byte[] data, string privateKey, string input_charset)
{
string result = "";
RSACryptoServiceProvider rsa = DecodePemPrivateKey(privateKey);
using (var sh = SHA1.Create())
{
byte[] source = rsa.Decrypt(data, false);
char[] asciiChars = new char[Encoding.GetEncoding(input_charset).GetCharCount(source, 0, source.Length)];
Encoding.GetEncoding(input_charset).GetChars(source, 0, source.Length, asciiChars, 0);
result = new string(asciiChars);
//result = ASCIIEncoding.ASCII.GetString(source);
return result;
}

}

private static RSACryptoServiceProvider DecodePemPrivateKey(String pemstr)
{
RSACryptoServiceProvider rsa = DecodeRSAPrivateKey(Convert.FromBase64String(pemstr));
return rsa;
}
private static RSACryptoServiceProvider DecodePrivateKeyInfo(byte[] pkcs8)
{
byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
byte[] seq = new byte[15];

MemoryStream mem = new MemoryStream(pkcs8);
int lenstream = (int)mem.Length;
BinaryReader binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading
byte bt = 0;
ushort twobytes = 0;

try
{
twobytes = binr.ReadUInt16();
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
binr.ReadByte(); //advance 1 byte
else if (twobytes == 0x8230)
binr.ReadInt16(); //advance 2 bytes
else
return null;

bt = binr.ReadByte();
if (bt != 0x02)
return null;

twobytes = binr.ReadUInt16();

if (twobytes != 0x0001)
return null;

seq = binr.ReadBytes(15); //read the Sequence OID
if (!CompareBytearrays(seq, SeqOID)) //make sure Sequence for OID is correct
return null;

bt = binr.ReadByte();
if (bt != 0x04) //expect an Octet string
return null;

bt = binr.ReadByte(); //read next byte, or next 2 bytes is 0x81 or 0x82; otherwise bt is the byte count
if (bt == 0x81)
binr.ReadByte();
else
if (bt == 0x82)
binr.ReadUInt16();
//------ at this stage, the remaining sequence should be the RSA private key

byte[] rsaprivkey = binr.ReadBytes((int)(lenstream - mem.Position));
RSACryptoServiceProvider rsacsp = DecodeRSAPrivateKey(rsaprivkey);
return rsacsp;
}

catch (Exception)
{
return null;
}

finally { binr.Dispose(); }

}

private static bool CompareBytearrays(byte[] a, byte[] b)
{
if (a.Length != b.Length)
return false;
int i = 0;
foreach (byte c in a)
{
if (c != b[i])
return false;
i++;
}
return true;
}

private static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
{
byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;

// --------- Set up stream to decode the asn.1 encoded RSA private key ------
MemoryStream mem = new MemoryStream(privkey);
BinaryReader binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading
byte bt = 0;
ushort twobytes = 0;
int elems = 0;
try
{
twobytes = binr.ReadUInt16();
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
binr.ReadByte(); //advance 1 byte
else if (twobytes == 0x8230)
binr.ReadInt16(); //advance 2 bytes
else
return null;

twobytes = binr.ReadUInt16();
if (twobytes != 0x0102) //version number
return null;
bt = binr.ReadByte();
if (bt != 0x00)
return null;

//------ all private key components are Integer sequences ----
elems = GetIntegerSize(binr);
MODULUS = binr.ReadBytes(elems);

elems = GetIntegerSize(binr);
E = binr.ReadBytes(elems);

elems = GetIntegerSize(binr);
D = binr.ReadBytes(elems);

elems = GetIntegerSize(binr);
P = binr.ReadBytes(elems);

elems = GetIntegerSize(binr);
Q = binr.ReadBytes(elems);

elems = GetIntegerSize(binr);
DP = binr.ReadBytes(elems);

elems = GetIntegerSize(binr);
DQ = binr.ReadBytes(elems);

elems = GetIntegerSize(binr);
IQ = binr.ReadBytes(elems);

// ------- create RSACryptoServiceProvider instance and initialize with public key -----
CspParameters CspParameters = new CspParameters();
CspParameters.Flags = CspProviderFlags.UseMachineKeyStore;
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(1024, CspParameters);
RSAParameters RSAparams = new RSAParameters();
RSAparams.Modulus = MODULUS;
RSAparams.Exponent = E;
RSAparams.D = D;
RSAparams.P = P;
RSAparams.Q = Q;
RSAparams.DP = DP;
RSAparams.DQ = DQ;
RSAparams.InverseQ = IQ;
RSA.ImportParameters(RSAparams);
return RSA;
}
catch
{
return null;
}
finally
{
binr.Dispose();
}
}

private static int GetIntegerSize(BinaryReader binr)
{
byte bt = 0;
byte lowbyte = 0x00;
byte highbyte = 0x00;
int count = 0;
bt = binr.ReadByte();
if (bt != 0x02) //expect integer
return 0;
bt = binr.ReadByte();

if (bt == 0x81)
count = binr.ReadByte(); // data size in next byte
else
if (bt == 0x82)
{
highbyte = binr.ReadByte(); // data size in next 2 bytes
lowbyte = binr.ReadByte();
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
count = BitConverter.ToInt32(modint, 0);
}
else
{
count = bt; // we already have the data size
}

while (binr.ReadByte() == 0x00)
{ //remove high order zeros in data
count -= 1;
}
binr.BaseStream.Seek(-1, SeekOrigin.Current); //last ReadByte wasn't a removed zero, so back up a byte
return count;
}

#endregion

#region 解析.net 生成的Pem
private static RSAParameters ConvertFromPublicKey(string pemFileConent)
{

if (string.IsNullOrEmpty(pemFileConent))
{
throw new ArgumentNullException("pemFileConent", "This arg cann't be empty.");
}
pemFileConent = pemFileConent.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", "").Replace("\n", "").Replace("\r", "");
byte[] keyData = Convert.FromBase64String(pemFileConent);
bool keySize1024 = (keyData.Length == 162);
bool keySize2048 = (keyData.Length == 294);
if (!(keySize1024 || keySize2048))
{
throw new ArgumentException("pem file content is incorrect, Only support the key size is 1024 or 2048");
}
byte[] pemModulus = (keySize1024 ? new byte[128] : new byte[256]);
byte[] pemPublicExponent = new byte[3];
Array.Copy(keyData, (keySize1024 ? 29 : 33), pemModulus, 0, (keySize1024 ? 128 : 256));
Array.Copy(keyData, (keySize1024 ? 159 : 291), pemPublicExponent, 0, 3);
RSAParameters para = new RSAParameters();
para.Modulus = pemModulus;
para.Exponent = pemPublicExponent;
return para;
}
/// <summary>
/// 将pem格式私钥(1024 or 2048)转换为RSAParameters
/// </summary>
/// <param name="pemFileConent">pem私钥内容</param>
/// <returns>转换得到的RSAParamenters</returns>
private static RSAParameters ConvertFromPrivateKey(string pemFileConent)
{
if (string.IsNullOrEmpty(pemFileConent))
{
throw new ArgumentNullException("pemFileConent", "This arg cann't be empty.");
}
pemFileConent = pemFileConent.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "").Replace("\n", "").Replace("\r", "");
byte[] keyData = Convert.FromBase64String(pemFileConent);

bool keySize1024 = (keyData.Length == 609 || keyData.Length == 610);
bool keySize2048 = (keyData.Length == 1190 || keyData.Length == 1192);

if (!(keySize1024 || keySize2048))
{
throw new ArgumentException("pem file content is incorrect, Only support the key size is 1024 or 2048");
}

int index = (keySize1024 ? 11 : 12);
byte[] pemModulus = (keySize1024 ? new byte[128] : new byte[256]);
Array.Copy(keyData, index, pemModulus, 0, pemModulus.Length);

index += pemModulus.Length;
index += 2;
byte[] pemPublicExponent = new byte[3];
Array.Copy(keyData, index, pemPublicExponent, 0, 3);

index += 3;
index += 4;
if ((int)keyData[index] == 0)
{
index++;
}
byte[] pemPrivateExponent = (keySize1024 ? new byte[128] : new byte[256]);
Array.Copy(keyData, index, pemPrivateExponent, 0, pemPrivateExponent.Length);

index += pemPrivateExponent.Length;
index += (keySize1024 ? ((int)keyData[index + 1] == 64 ? 2 : 3) : ((int)keyData[index + 2] == 128 ? 3 : 4));
byte[] pemPrime1 = (keySize1024 ? new byte[64] : new byte[128]);
Array.Copy(keyData, index, pemPrime1, 0, pemPrime1.Length);

index += pemPrime1.Length;
index += (keySize1024 ? ((int)keyData[index + 1] == 64 ? 2 : 3) : ((int)keyData[index + 2] == 128 ? 3 : 4));
byte[] pemPrime2 = (keySize1024 ? new byte[64] : new byte[128]);
Array.Copy(keyData, index, pemPrime2, 0, pemPrime2.Length);

index += pemPrime2.Length;
index += (keySize1024 ? ((int)keyData[index + 1] == 64 ? 2 : 3) : ((int)keyData[index + 2] == 128 ? 3 : 4));
byte[] pemExponent1 = (keySize1024 ? new byte[64] : new byte[128]);
Array.Copy(keyData, index, pemExponent1, 0, pemExponent1.Length);

index += pemExponent1.Length;
index += (keySize1024 ? ((int)keyData[index + 1] == 64 ? 2 : 3) : ((int)keyData[index + 2] == 128 ? 3 : 4));
byte[] pemExponent2 = (keySize1024 ? new byte[64] : new byte[128]);
Array.Copy(keyData, index, pemExponent2, 0, pemExponent2.Length);

index += pemExponent2.Length;
index += (keySize1024 ? ((int)keyData[index + 1] == 64 ? 2 : 3) : ((int)keyData[index + 2] == 128 ? 3 : 4));
byte[] pemCoefficient = (keySize1024 ? new byte[64] : new byte[128]);
Array.Copy(keyData, index, pemCoefficient, 0, pemCoefficient.Length);

RSAParameters para = new RSAParameters();
para.Modulus = pemModulus;
para.Exponent = pemPublicExponent;
para.D = pemPrivateExponent;
para.P = pemPrime1;
para.Q = pemPrime2;
para.DP = pemExponent1;
para.DQ = pemExponent2;
para.InverseQ = pemCoefficient;
return para;
}
#endregion

}

asp.net core实现SHA1withRSA的更多相关文章

  1. ASP.NET Core 之 Identity 入门(一)

    前言 在 ASP.NET Core 中,仍然沿用了 ASP.NET里面的 Identity 组件库,负责对用户的身份进行认证,总体来说的话,没有MVC 5 里面那么复杂,因为在MVC 5里面引入了OW ...

  2. ASP.NET Core 中的那些认证中间件及一些重要知识点

    前言 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列(一,二,三)奠定一下基础. 有关于 Authentication 的知识太广,所以本篇介绍几个在 A ...

  3. ASP.NET Core应用的错误处理[3]:ExceptionHandlerMiddleware中间件如何呈现“定制化错误页面”

    DeveloperExceptionPageMiddleware中间件利用呈现出来的错误页面实现抛出异常和当前请求的详细信息以辅助开发人员更好地进行纠错诊断工作,而ExceptionHandlerMi ...

  4. ASP.NET Core MVC/WebAPi 模型绑定探索

    前言 相信一直关注我的园友都知道,我写的博文都没有特别枯燥理论性的东西,主要是当每开启一门新的技术之旅时,刚开始就直接去看底层实现原理,第一会感觉索然无味,第二也不明白到底为何要这样做,所以只有当你用 ...

  5. ASP.NET Core应用的错误处理[2]:DeveloperExceptionPageMiddleware中间件如何呈现“开发者异常页面”

    在<ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式>中,我们通过几个简单的实例演示了如何呈现一个错误页面,这些错误页面的呈现分别由三个对应的中间件来完成,接下来我们将 ...

  6. Asp.net Core中使用Session

    前言 2017年就这么悄无声息的开始了,2017年对我来说又是特别重要的一年. 元旦放假在家写了个Asp.net Core验证码登录, 做demo的过程中遇到两个小问题,第一是在Asp.net Cor ...

  7. ASP.NET Core 中文文档 第四章 MVC(3.8)视图中的依赖注入

    原文:Dependency injection into views 作者:Steve Smith 翻译:姚阿勇(Dr.Yao) 校对:孟帅洋(书缘) ASP.NET Core 支持在视图中使用 依赖 ...

  8. .NET跨平台之旅:将示例站点升级至 ASP.NET Core 1.1

    微软今天在 Connect(); // 2016 上发布了 .NET Core 1.1 ,ASP.NET Core 1.1 以及 Entity Framework Core 1.1.紧跟这次发布,我们 ...

  9. ASP.NET Core HTTP 管道中的那些事儿

    前言 马上2016年就要过去了,时间可是真快啊. 上次写完 Identity 系列之后,反响还不错,所以本来打算写一个 ASP.NET Core 中间件系列的,但是中间遇到了很多事情.首先是 NPOI ...

随机推荐

  1. IOS开发之application/x-www-form-urlencoded ;charset=utf-8

    本来常用的是application/json的这中格式,做ios常用的网络请求框架AFNetworking,默认也是application/json,前不久就遇到这种接受格式问题,按照网上各种说法,改 ...

  2. bzoj1553: XOR网络

    Description   计算给定范围内有多少种输入可以使输出为1. 我们假设3 < n < 100, 3 < m < 3000,而且网络中的门是用1到m之间的数任意编号的. ...

  3. AngularJS---自定义指令

    AngularJS提供了一系列的内置指令,如ng开头的指令,同时AngularJS也允许用户自定义指令. 目录: 1.自定义指令 2.使用自定义指令 3.自定义指令的内嵌使用 自定义指令 Angula ...

  4. Arrays和Collection之间的转换

    1.将数组转换成固定大小的列表: public static <T> List<T> asList(T... a)参数 T... a:数组元素 返回值 List<T> ...

  5. 修改Windows Server 2008+IIS 7+ASP.NET默认连接限制,支持海量并发连接数

    WIN7中IIS7默认配置的服务器同时最多只能处理5000个请求,如果由于某些情况(程序问题等)造成同时请求超过5000时,将会导致服务器错误.为此,修改服务器的设置,从而支持10万个同时请求. 具体 ...

  6. Android笔记:invalidate()和postInvalidate() 的区别及使用

    http://blog.csdn.net/mars2639/article/details/6650876 Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在 ...

  7. 转 Dynamics CRM Alert and Notification JavaScript Methods

    http://www.powerobjects.com/2015/09/23/dynamics-crm-alert-and-notification-javascript-methods/ Befor ...

  8. 微信小程序上传文件

    wx.chooseImage({ count: 1, // 默认9 sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有 sourc ...

  9. highcharts去掉右下角highchart.com和右上角的图标(三个小横杆)

    去除右下角highchart.com credits: {                enabled:false            } 去除右上角图标 exporting: {         ...

  10. Esfog_UnityShader教程_UnityShader语法实例浅析

    距离上次首篇前言已经有一段时间了,一直比较忙,今天是周末不可以再拖了,经过我一段时间的考虑,我决定这一系列的教程会避免过于深入细节,一来可以避免一些同学被误导,二来会避免文章过于冗长难读, 三来可以让 ...