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. 原生js(二)

    js的同步.异步和延迟 1.默认情况下,js是同步和阻塞DOM解析的.在解析DOM的过程中,当遇到script时,会暂停DOM解析,开始请求script并执行js,执行完成之后再接着解析DOM树. 2 ...

  2. java(4) 异常

    1.Throwable 继承体系 * Eorro * Exception --RuntimeException 该类及其子类用于表示运行时异常,Exception类下所有其他子类都用于表示编译时异常. ...

  3. LeetCode 22 Generate Parentheses(找到所有匹配的括号组合)

    题目链接 : https://leetcode.com/problems/generate-parentheses/?tab=Description   给一个整数n,找到所有合法的 () pairs ...

  4. 3-1 vue-resource基础介绍

    1.静态引用 <script src="https://cdn.bootcss.com/vue-resource/1.3.4/vue-resource.js">< ...

  5. linux安装环境

    我用的是Linux ubuntu 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:16:20 UTC 2015 x86_64 x86_64 ...

  6. HDFS文件系统的JAVA-API操作(一)

    使用java.net.URL访问HDFS文件系统 HDFS的API使用说明: 1.如果要访问HDFS,HDFS客户端必须有一份HDFS的配置文件 也就是hdfs-site.xml,从而读取Nameno ...

  7. 查询ip

    ifconfig | grep "inet " | grep -v 127.0.0.1

  8. PHP快速入门

    1.表单 <form action="processorder.php" method="post"> 表单的第一行,action的意思是说,提交表 ...

  9. TensorFlow 实现分类操作的函数学习

    函数:tf.nn.sigmoid_cross_entropy_with_logits(logits, targets, name=None) 说明:此函数是计算logits经过sigmod函数后的交叉 ...

  10. SS iproute2,nslookup,dig

    从某种意义上说,iproute工具集几乎可以替代掉net-tools工具集,具体的替代方案是这样的:用途  net-tool(被淘汰)   iproute2地址和链路配置   ifconfig  ip ...