SHA1WithRSA签名 规范化标准签名
#region CerRsaSignature 根据私钥签名
/// <summary>
/// 根据私钥串签名
/// </summary>
/// <param name="plainText">待签名的明文</param>
/// <param name="prikeyPath">私钥证书路径</param>
/// <param name="prikeyPassword">私钥证书密码</param>
/// <param name="urid">签名uri</param>
/// <returns></returns>
public static ReturnValue CerRsaSignature(string prikeyPath, string prikeyPassword, string plainText,string urid)
{
ReturnValue retValue = new ReturnValue();
try
{
X509Certificate2 x509_Cer1 = new X509Certificate2(prikeyPath, prikeyPassword, X509KeyStorageFlags.Exportable);
string key = x509_Cer1.PrivateKey.ToXmlString(true);
ReturnValue signValue = CreateSign(plainText, urid, key);
//签名失败
if (signValue.HasError)
{
retValue.HasError = true;
retValue.Message = "签名失败";
return retValue;
}
retValue.HasError = signValue.HasError;
retValue.Message = signValue.Message;
return retValue;
}
catch (Exception ex)
{
retValue.HasError = true;
retValue.Message = "签名异常" + ex.Message;
log.WarnFormat("创建签名失败,签名数据:{0},错误原因:{1}", plainText, ex);
return retValue;
}
}
/// <summary>
/// 根据私钥证书XML串创建签名
/// </summary>
/// <param name="privateKey">私钥证书XML串</param>
/// <param name="plainText">待签名的明文</param>
/// <param name="urid">签名uri</param>
/// <returns></returns>
public static ReturnValue CerRsaSignature(string privateKey, string plainText, string urid)
{
ReturnValue retValue = new ReturnValue();
try
{
ReturnValue signValue = CreateSign(plainText, urid, privateKey);
//签名失败
if (signValue.HasError)
{
retValue.HasError = true;
retValue.Message = "签名失败";
return retValue;
}
retValue.HasError = signValue.HasError;
retValue.Message = signValue.Message;
return retValue;
}
catch (Exception ex)
{
retValue.HasError = true;
retValue.Message = "签名异常" + ex.Message;
log.WarnFormat("创建签名失败,签名数据:{0},错误原因:{1}", plainText, ex);
return retValue;
}
}
/// <summary>
/// 创建签名
/// </summary>
/// <param name="plainText"></param>
/// <param name="urid"></param>
/// <param name="key"></param>
/// <returns></returns>
private static ReturnValue CreateSign(string plainText, string urid, string key)
{
XmlDocument doc = new XmlDocument();
////创建CspParameters 对象并将私钥放入密钥容器中
//CspParameters cspParams = new CspParameters();
//cspParams.KeyContainerName = key;
// 创建一个新的RSA签名密钥并将其保存在容器。
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider();
rsaKey.FromXmlString(key);
// 创建一个新的XML文档。
XmlDocument xmlDoc = new XmlDocument();
//将plainText加载到XmlDocument对象中。
xmlDoc.PreserveWhitespace = true;
xmlDoc.LoadXml(plainText);
// XML文档签名。
ReturnValue signValue = SignXml(xmlDoc, rsaKey, urid);
return signValue;
}
/// <summary>
/// 计算签名
/// </summary>
/// <param name="xmlDoc"></param>
/// <param name="Key"></param>
/// <param name="urid"></param>
/// <returns></returns>
private static ReturnValue SignXml(XmlDocument xmlDoc, RSA Key,string urid)
{
ReturnValue retValue = new ReturnValue();
//检查参数。
if (xmlDoc == null)
{
retValue.HasError = true;
retValue.Message = "签名XML为空";
return retValue;
}
if (Key == null)
{
retValue.HasError = true;
retValue.Message = "签名Key为空";
return retValue;
}
try
{
// 创建一个signedxml对象
SignedXml signedXml = new SignedXml(xmlDoc);
//添加添加到SignedXml的密钥
signedXml.SigningKey = Key;
////指定标准化:http://www.w3.org/TR/2001/REC-xml-c14n-20010315
//signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigC14NTransformUrl;
////指定签名方法:rsa-sha1
//signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
string uri = "#" + urid;
// 创建一个引用来签名
Reference reference = new Reference();
reference.Uri = uri;
//指定Signature标签与原xml报文的组装方式:enveloped
XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
reference.AddTransform(env);
// 添加到SignedXml对象添加参考。
signedXml.AddReference(reference);
// 计算签名
signedXml.ComputeSignature();
// 得到签名的XML表示形式
XmlElement xmlDigitalSignature = signedXml.GetXml();
//xmlDigitalSignature.Prefix = "ds";
//SetPrefix("ds", xmlDigitalSignature);
//添加元素的XML文档。
xmlDoc.DocumentElement.LastChild.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
//把签名加入到文档中
//xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
//获取SignatureValue标签的值,然后每76个字节增加一个换行
string signatureValue = xmlDoc.GetElementsByTagName("SignatureValue").Item(0).InnerText;
//设置xml文档中的SignatureValue标签的值
xmlDoc.GetElementsByTagName("SignatureValue").Item(0).InnerText = splitPer76AddLineBreak(signatureValue);
retValue.HasError = false;
retValue.Message = xmlDoc.OuterXml;
return retValue;
}
catch (Exception ex)
{
log.WarnFormat("创建签名失败,签名原文:{0},签名私钥:{1},错误原因:{2}", xmlDoc.InnerXml, Key.ToXmlString(true), ex.Message);
retValue.HasError = true;
retValue.Message = "创建签名异常";
return retValue;
}
}
#endregion
/// <summary>
/// 私有方法
/// </summary>
/// <param name="prefix"></param>
/// <param name="node"></param>
private static void SetPrefix(String prefix, XmlNode node)
{
foreach (XmlNode n in node.ChildNodes)
{
SetPrefix(prefix, n);
n.Prefix = prefix;
}
}
/// <summary>
/// 对数据每76个字节增加一个换行符
/// </summary>
/// <param name="message">待添加换行符的数据</param>
/// <returns>添加换行符后的数据</returns>
private static string splitPer76AddLineBreak(string message)
{
//存储带有换行符的结果
StringBuilder sb = new StringBuilder();
//循环次数
int count = 0;
if (message.Length % 76 == 0)
{
count = message.Length / 76;
}
else
{
count = message.Length / 76 + 1;
}
//截取字符串之后,还剩下没有截取的长度
int length = message.Length;
for (int i = 0; i < count; i++)
{
//待截取的长度大于76时,增加换行符
if (length > 76)
{
sb.AppendLine(message.Substring(i * 76, 76));
}
else
{//不大于76,说明是最后一段
sb.Append(message.Substring(i * 76));
break;
}
length = message.Length - ((i + 1) * 76);
}
return sb.ToString();
}
#region 验签方法
/// <summary>
/// 根据公钥对返回数据进行验签
/// </summary>
/// <param name="pubKeyPath">公钥路径</param>
/// <param name="data">需要验签的数据</param>
/// <returns></returns>
public static ReturnValue VerifyXmlDoc(string pubKeyPath, string data)
{
ReturnValue retValue = new ReturnValue();
//创建XML对象
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = true;
try
{
//将数据加载到XML对象中
xmlDoc.LoadXml(data);
//读取公钥串
X509Certificate2 x509_Cer2 = new X509Certificate2(pubKeyPath);
string publicKey = x509_Cer2.PublicKey.Key.ToXmlString(false);
bool verify = VerifyXML(xmlDoc, publicKey);
if (verify)
{
retValue.HasError = false;
retValue.Message = "验签成功";
}
else
{
retValue.HasError = true;
retValue.Message = "验签失败";
}
return retValue;
}
catch (Exception ex)
{
log.WarnFormat("验签异常:{0},银行返回数据:{1}", ex.Message, data);
retValue.HasError = true;
retValue.Message = "验签异常:" + ex.Message;
return retValue;
}
}
/// <summary>
/// 根据公钥证书XML串验证签名
/// </summary>
/// <param name="publicKey"></param>
/// <param name="xmlDoc"></param>
/// <returns></returns>
public static ReturnValue VerifyXmlDoc(string publicKey, XmlDocument xmlDoc)
{
ReturnValue retValue = new ReturnValue();
try
{
bool verify = VerifyXML(xmlDoc, publicKey);
if (verify)
{
retValue.HasError = false;
retValue.Message = "验签成功";
}
else
{
retValue.HasError = true;
retValue.Message = "验签失败";
}
return retValue;
}
catch (Exception ex)
{
log.WarnFormat("验签异常:{0},银行返回数据:{1}", ex.Message, xmlDoc);
retValue.HasError = true;
retValue.Message = "验签异常:" + ex.Message;
return retValue;
}
}
/// <summary>
/// 验证XmlDocument
/// </summary>
/// <param name="xmlDoc"></param>
/// <param name="pubilcKey"></param>
/// <returns></returns>
private static bool VerifyXML(XmlDocument xmlDoc, string pubilcKey)
{
//创建加密服务提供者对象
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
//由通过 XML 字符串重新构造加密服务提供者对象
csp.FromXmlString(pubilcKey);
//创建XML签名对象
SignedXml sxml = new SignedXml(xmlDoc);
//得到签名元素的节点
XmlNode dsig = xmlDoc.GetElementsByTagName("Signature",
SignedXml.XmlDsigNamespaceUrl)[0];
sxml.LoadXml((XmlElement)dsig);
//验证签名是否正确,并且返回结果
bool verify = sxml.CheckSignature(csp);
return verify;
}
#endregion