using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates; namespace API.Tools
{
/// <summary>
/// 类名:RSAFromPkcs8
/// 功能:RSA解密、签名、验签
/// 详细:该类对Java生成的密钥进行解密和签名以及验签专用类,不需要修改
/// 版本:2.0
/// 修改日期:2011-05-10
/// 说明:
/// 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
/// 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
/// </summary>
public sealed class Signatory
{
/// <summary>
/// 签名(C#解释证书导出的,会出现“数据不正确”的错误)
/// </summary>
/// <param name="privateKey">私钥</param>
/// <param name="content">需要签名的内容</param>
/// <param name="encode">编码格式</param>
/// <returns></returns>
public static string sign(string privateKey, string content, Encoding encode)
{
byte[] Data = encode.GetBytes(content);
RSACryptoServiceProvider rsa = DecodePemPrivateKey(privateKey);
MD5CryptoServiceProvider m5 = new MD5CryptoServiceProvider(); byte[] signData = rsa.SignData(Data, m5);
return Convert.ToBase64String(signData);
}
/// <summary>
/// 验证签名
/// </summary>
/// <param name="publicKey">公钥</param>
/// <param name="content">需要验证的内容</param>
/// <param name="signedString">签名结果</param>
/// <param name="encode">编码格式</param>
/// <returns></returns>
public static bool verify(string publicKey, string content, string signedString, Encoding encode)
{
bool result = false;
byte[] Data = encode.GetBytes(content);
byte[] data = Convert.FromBase64String(signedString);
RSAParameters paraPub = ConvertFromPublicKey(publicKey);
RSACryptoServiceProvider rsaPub = new RSACryptoServiceProvider();
rsaPub.ImportParameters(paraPub); MD5CryptoServiceProvider m5 = new MD5CryptoServiceProvider();
result = rsaPub.VerifyData(Data, m5, data);
return result;
} /// <summary>
/// 解析java生成的pem文件私钥
/// </summary>
/// <param name="pemstr"></param>
/// <returns></returns>
private static RSACryptoServiceProvider DecodePemPrivateKey(String pemstr)
{
byte[] pkcs8privatekey;
pkcs8privatekey = Convert.FromBase64String(pemstr);
if (pkcs8privatekey != null)
{ RSACryptoServiceProvider rsa = DecodePrivateKeyInfo(pkcs8privatekey);
return rsa;
}
else
return null;
} 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[]; 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 = ;
ushort twobytes = ; 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(); //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.Close(); } } private static bool CompareBytearrays(byte[] a, byte[] b)
{
if (a.Length != b.Length)
return false;
int i = ;
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 = ;
ushort twobytes = ;
int elems = ;
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 -----
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
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)
{
return null;
}
finally { binr.Close(); }
} private static int GetIntegerSize(BinaryReader binr)
{
byte bt = ;
byte lowbyte = 0x00;
byte highbyte = 0x00;
int count = ;
bt = binr.ReadByte();
if (bt != 0x02) //expect integer
return ;
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, );
}
else
{
count = bt; // we already have the data size
} while (binr.ReadByte() == 0x00)
{ //remove high order zeros in data
count -= ;
}
binr.BaseStream.Seek(-, SeekOrigin.Current); //last ReadByte wasn't a removed zero, so back up a byte
return count;
} private static RSAParameters ConvertFromPublicKey(string pemFileConent)
{ byte[] keyData = Convert.FromBase64String(pemFileConent);
if (keyData.Length < )
{
throw new ArgumentException("pem file content is incorrect.");
}
byte[] pemModulus = new byte[];
byte[] pemPublicExponent = new byte[];
Array.Copy(keyData, , pemModulus, , );
Array.Copy(keyData, , pemPublicExponent, , );
RSAParameters para = new RSAParameters();
para.Modulus = pemModulus;
para.Exponent = pemPublicExponent;
return para;
}
}
}

上面的类在平常使用的时候,是没有问题的,但,我们在对接第三方支付(易联支付)时,遇到一个非常刺手的,签名不通过。

  • 签名证书,是从北京数字认证拿到,里面有一个文件xxxxx-Signature.pfx 和证书密码,我们需要从该文件中,使用openssl.exe工具,导出RSA公钥和私钥
  • 导出的公钥,发给合作平台配上,私钥用于数据签名
  • 签名时,使用导出的私钥进行。

问题来了,调用上面程序的sign()方法,解释私钥时,总报“数据不正解”或者“无效的私钥”之类的。更奇怪的是,该私钥在java下使用没有问题。联系了对方,对方试了好多几证书,只有我们的这个有问题。好吧,算倒霉吧。

解决方法:

.net里可以直接使用证书进行RSA签名:

        /// <summary>
/// 签名,直接使用证书签名
/// </summary>
/// <param name="filePath"></param>
/// <param name="password"></param>
/// <param name="content"></param>
/// <param name="encode"></param>
/// <returns></returns>
public static string sign(string filePath,string password, string content, Encoding encode)
{
byte[] Data = encode.GetBytes(content); X509Certificate2 myX509 = new X509Certificate2(filePath, password, X509KeyStorageFlags.Exportable);
var rsa = (RSACryptoServiceProvider)myX509.PrivateKey;
MD5CryptoServiceProvider m5 = new MD5CryptoServiceProvider(); byte[] signData = rsa.SignData(Data, m5);
return Convert.ToBase64String(signData);
}

问题解决!

.NET RSA解密、签名、验签的更多相关文章

  1. RSACryptoServiceProvider加密解密签名验签和DESCryptoServiceProvider加解密

    原文:RSACryptoServiceProvider加密解密签名验签和DESCryptoServiceProvider加解密 C#在using System.Security.Cryptograph ...

  2. js rsa sign使用笔记(加密,解密,签名,验签)

    你将会收获: js如何加密, 解密 js如何签名, 验签 js和Java交互如何相互解密, 验签(重点) 通过谷歌, 发现jsrsasign库使用者较多. 查看api发现这个库功能很健全. 本文使用方 ...

  3. C# RSACryptoServiceProvider加密解密签名验签和DESCryptoServic

    C#在using System.Security.Cryptography下有 DESCryptoServiceProvider RSACryptoServiceProvider DESCryptoS ...

  4. Java RSA 加密 解密 签名 验签

    原文:http://gaofulai1988.iteye.com/blog/2262802 import java.io.FileInputStream; import java.io.FileOut ...

  5. RSA密钥生成、加密解密、签名验签

    RSA 非对称加密公钥加密,私钥解密 私钥签名,公钥验签 下面是生成随机密钥对: //随机生成密钥对 KeyPairGenerator keyPairGen = null; try { keyPair ...

  6. [Python3] RSA的加解密和签名/验签实现 -- 使用pycrytodome

    Crypto 包介绍: pycrypto,pycrytodome 和 crypto 是一个东西,crypto 在 python 上面的名字是 pycrypto 它是一个第三方库,但是已经停止更新,所以 ...

  7. 利用SHA-1算法和RSA秘钥进行签名验签(带注释)

    背景介绍 1.SHA 安全散列算法SHA (Secure Hash Algorithm)是美国国家标准和技术局发布的国家标准FIPS PUB 180-1,一般称为SHA-1.其对长度不超过264二进制 ...

  8. 支付接口中常用的加密解密以及验签rsa,md5,sha

    一.常用加密类型分类 1.对称加密:采用单钥对信息进行加密和解密,即同一个秘钥既可以对信息进行加密,也可以进行解密.此类型称之为对称加密.特点速度快,常用于对大量数据信息或文件加密时使用.常用例子:D ...

  9. 数据安全管理:RSA加密算法,签名验签流程详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.RSA算法简介 1.加密解密 RSA加密是一种非对称加密,在公开密钥加密和电子商业中RSA被广泛使用.可以在不直接传递密钥的情况下,完成加 ...

  10. RSA签名验签

    import android.util.Base64; import java.security.KeyFactory; import java.security.PrivateKey; import ...

随机推荐

  1. PCL—低层次视觉—关键点检测(Harris)

    除去NARF这种和特征检测联系比较紧密的方法外,一般来说特征检测都会对曲率变化比较剧烈的点更敏感.Harris算法是图像检测识别算法中非常重要的一个算法,其对物体姿态变化鲁棒性好,对旋转不敏感,可以很 ...

  2. Learning Git by Animations

    https://hujiaweibujidao.github.io/blog/2016/05/20/learning-git-by-animations/ http://learngitbranchi ...

  3. OGG遇到相关问题汇总

    OGG初始化加载数据时遇到的问题 1.target端拒绝source端访问 2016-12-13 14:31:03 INFO OGG-00963 Oracle GoldenGate Manager f ...

  4. OpenMax概述

    一.OpenMax简介 OpenMAX是一个多媒体应用程序的标准.由NVIDIA公司和Khronos™在2006年推出. 它是无授权费的.跨平台的C语言程序接口序列,这些接口对音频.视频.静态图片的常 ...

  5. docker参数--restart=always的作用

    创建容器时没有添加参数  --restart=always ,导致的后果是:当 Docker 重启时,容器未能自动启动. 现在要添加该参数怎么办呢,方法有二: 1.Docker 命令修改 docker ...

  6. 把握这两点,抢占下一个电商风口|2016最新中国电商App排名&研究报告

    序言 电商,是随着中国互联网经济的持续发展所成长起来的.淘宝.京东这些电商从交易额和影响力上看都位列中国最为成功.最具话题性的互联网企业之中.尽管近几年中国经济有所放缓,但中国消费市场的增长速度仍有望 ...

  7. VS2013打开2008的项目

    找到 .csproj 后缀的文件.然后右键选择文本打开. 找到下面一段话: <ProjectTypeGuids>-00065b846f21};{fae04ec0-301f-11d3-bf4 ...

  8. thinkphp---部署在IIS8.0服务器上

    最近做了一个项目,使用的是我自己基于thinkphp开发的一套CMS,由于我本地使用的都是apche的环境,即使是线上环境用的也是宝塔面板,但是现在要将thinkphp的系统部署在IIS8.0的环境下 ...

  9. HDU-1394 Minimum Inversion Number(线段树求逆序数)

    Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Ot ...

  10. MapReduce的分区

    第一部分 分区简述(比如国家由省市来划分) 分区:map的输出经过partitioner分区进行下一步的reducer.一个分区对应一个reducer,就会使得reducer并行化处理任务.默认为1 ...