本人被要求实现.net的签名验签,还是个.net菜鸡,来分享下采坑过程
依然,签名验签使用的证书格式依然是pem,有关使用openssl将.p12和der转pem的命令请转到php实现签名验签
.net不像php只要将pem文件读出来就可以签名验签,需要解析pem文件的主体内容,获取参数装载特定类,具体看一下代码:
//有些函数我也不知道是干嘛的,反正.net的实现要这样,采百家之长,签的了名,验的了签就对了
//自己去单元测试下
//pem文件是我使用的是绝对路径
public class Signature
{
//签名,返回256位字节数组
public static byte[] Sign(string content,string path,string code)
{
RSACryptoServiceProvider rsaCsp = RSAProviderPrivate(path);
byte[] dataBytes = Encoding.UTF8.GetBytes(content);
byte[] signatureBytes = rsaCsp.SignData(dataBytes, code);
return signatureBytes;
}
//验签
public static Boolean Verify(string content, byte\[\] signContent, string path, string code)
{
byte\[\] dataBytes = Encoding.UTF8.GetBytes(content);
byte\[\] publicPemBytes = LoadCertificateFile(path, "PUBLIC KEY");
RSACryptoServiceProvider rsaPub = CreateRsaProviderFromPublicKey(publicPemBytes);
Boolean flag= rsaPub.VerifyData(dataBytes,code, signContent);
return flag;
}
//加载公私钥证书文件
private static byte\[\] LoadCertificateFile(String filePath,string type)
{
using (System.IO.FileStream fs = System.IO.File.OpenRead(filePath))
{
byte\[\] data = new byte\[fs.Length\];
byte\[\] res = null;
fs.Read(data, 0, data.Length);
if (data\[0\] != 0x30)
{
res = GetPem(type, data);
}
return res;
}
}
private static RSACryptoServiceProvider RSAProviderPrivate(String filePath)
{
byte\[\] res = LoadCertificateFile(filePath, "RSA PRIVATE KEY");
try
{
RSACryptoServiceProvider rsa = DecodeRSAPrivateKey(res);
return rsa;
}
catch (Exception e)
{
Console.WriteLine(e);
}
return null;
}
//获取pem文件的主体内容,并转换成字节数组
private static byte\[\] GetPem(String type, byte\[\] data)
{
string pem = Encoding.UTF8.GetString(data);
string header = String.Format("-----BEGIN {0}-----\\\\n", type);
string footer = String.Format("-----END {0}-----", type);
int start = pem.IndexOf(header) + header.Length;
int end = pem.IndexOf(footer, start);
string base64 = pem.Substring(start, (end - start));
return Convert.FromBase64String(base64);
}
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 (Exception e)
{
Console.WriteLine(e);
return null;
}
finally
{
binr.Close();
}
}
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;
}
private static RSAParameters ConvertFromPublicKey(byte\[\] publicPemBytes)
{
byte\[\] keyData = publicPemBytes;
if (keyData.Length < 162)
{
throw new ArgumentException("pem file content is incorrect.");
}
byte\[\] pemModulus = new byte\[128\];
byte\[\] pemPublicExponent = new byte\[3\];
Array.Copy(keyData, 29, pemModulus, 0, 128);
Array.Copy(keyData, 159, pemPublicExponent, 0, 3);
RSAParameters para = new RSAParameters();
para.Modulus = pemModulus;
para.Exponent = pemPublicExponent;
return para;
}
public static RSACryptoServiceProvider CreateRsaProviderFromPublicKey(byte\[\] publicKeyBytes)
{
byte\[\] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
byte\[\] x509key;
byte\[\] seq = new byte\[15\];
int x509size;
x509key = publicKeyBytes;
x509size = x509key.Length;
using (MemoryStream mem = new MemoryStream(x509key))
{
using (BinaryReader binr = new BinaryReader(mem))
{
byte bt = 0;
ushort twobytes = 0;
twobytes = binr.ReadUInt16();
if (twobytes == 0x8130)
binr.ReadByte();
else if (twobytes == 0x8230)
binr.ReadInt16();
else
return null;
seq = binr.ReadBytes(15);
if (!CompareBytearrays(seq, SeqOID))
return null;
twobytes = binr.ReadUInt16();
if (twobytes == 0x8103)
binr.ReadByte();
else if (twobytes == 0x8203)
binr.ReadInt16();
else
return null;
bt = binr.ReadByte();
if (bt != 0x00)
return null;
twobytes = binr.ReadUInt16();
if (twobytes == 0x8130)
binr.ReadByte();
else if (twobytes == 0x8230)
binr.ReadInt16();
else
return null;
twobytes = binr.ReadUInt16();
byte lowbyte = 0x00;
byte highbyte = 0x00;
if (twobytes == 0x8102)
lowbyte = binr.ReadByte();
else if (twobytes == 0x8202)
{
highbyte = binr.ReadByte();
lowbyte = binr.ReadByte();
}
else
return null;
byte\[\] modint = { lowbyte, highbyte, 0x00, 0x00 };
int modsize = BitConverter.ToInt32(modint, 0);
int firstbyte = binr.PeekChar();
if (firstbyte == 0x00)
{
binr.ReadByte();
modsize -= 1;
}
byte\[\] modulus = binr.ReadBytes(modsize);
if (binr.ReadByte() != 0x02)
return null;
int expbytes = (int)binr.ReadByte();
byte\[\] exponent = binr.ReadBytes(expbytes);
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
RSAParameters RSAKeyInfo = new RSAParameters();
RSAKeyInfo.Modulus = modulus;
RSAKeyInfo.Exponent = exponent;
RSA.ImportParameters(RSAKeyInfo);
return RSA;
}
}
}
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章