java/php/c#版rsa签名以及java验签实现

在开放平台领域,需要给isv提供sdk,签名是Sdk中需要提供的功能之一。由于isv使用的开发语言不是单一的,因此sdk需要提供多种语言的版本。譬如java、php、c#。另外,在电子商务尤其是支付领域,对安全性的要求比较高,所以会采用非对称密钥RSA

本文主要介绍如何基于java、php、c#在客户端使用rsa签名,然后在服务端使用Java验签。

基于openssl生成RSA公私钥对

a)从网上下载openssl工具:http://www.slproweb.com/products/Win32OpenSSL.html

b)生成私钥

进入到openssl的bin目录下,执行以下命令:

openssl genrsa -out rsa_private_key.pem 1024

会在bin目录下看到新生成的私钥文件rsa_private_key.pem,文件内容如下:

Xml代码  收藏代码

-----BEGIN RSA PRIVATE KEY-----

MIICXgIBAAKBgQDtd1lKsX6ylsAEWFi7E/ut8krJy9PQ7sGYKhIm9TvIdZiq5xzy

aw8NOLzKZ1k486MePYG4tSuoaxSbwuPLwVUzYFvnUZo7aWCIGKn16UWTM4nxc/+d

wce+bhcKrlLbTWi8l580LTE7GxclTh8z7gHq59ivhaoGbK7FNxlUfB4TSQIDAQAB

AoGBAIgTk0x1J+hI8KHMypPxoJCOPoMi1S9uEewTd7FxaB+4G5Mbuv/Dj62A7NaD

oKI9IyUqE9L3ppvtOLMFXCofkKU0p4j7MEJdZ+CjVvgextkWa80nj/UZiM1oOL6Y

HwH4ZtPtY+pFCTK1rdn3+070qBB9tnVntbN/jq0Ld7f0t7UNAkEA9ryI0kxJL9Pu

pO9NEeWuCUo4xcl9x/M9+mtkfY3VoDDDV1E/eUjmoTfANYwrjcddiQrO0MLyEdoo

tiLpN77qOwJBAPZhtv/+pqMVTrLxWnVKLZ4ZVTPPgJQQkFdhWwYlz7oKzB3VbQRt

/jLFXUyCN2eCP7rglrXnaz7AYBftF0ajHEsCQQDDNfkeQULqN0gpcDdOwKRIL1Pp

kHgWmWlg1lTETVJGEi6Kx/prL/VgeiZ1dzgCTUjAoy9r1cEFxM/PAqH3+/F/AkEA

zsTCp6Q2hLblDRewKq7OCdiIwKpr5dbgy/RQR6CD7EYTdxYeH5GPu1wXKJY/mQae

JV9GG/LS9h7MhkfbONS6cQJAdBEb5vloBDLcSQFDQO/VZ9SKFHCmHLXluhhIizYK

Gzgf3OXEGNDSAC3qy+ZTnLd3N5iYrVbK52UoiLOLhhNMqA==

-----END RSA PRIVATE KEY-----

c)生成公钥

在bin目录下,执行以下命令:

openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

会在bin目录下看到新生成的公钥文件rsa_public_key.pem,文件内容如下:

Xml代码  收藏代码

-----BEGIN PUBLIC KEY-----

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDtd1lKsX6ylsAEWFi7E/ut8krJ

y9PQ7sGYKhIm9TvIdZiq5xzyaw8NOLzKZ1k486MePYG4tSuoaxSbwuPLwVUzYFvn

UZo7aWCIGKn16UWTM4nxc/+dwce+bhcKrlLbTWi8l580LTE7GxclTh8z7gHq59iv

haoGbK7FNxlUfB4TSQIDAQAB

-----END PUBLIC KEY-----

2. 客户端签名

2.1 java版签名实现

Java代码  收藏代码

/**

* rsa签名

*

* @param content

*            待签名的字符串

* @param privateKey

*            rsa私钥字符串

* @param charset

*            字符编码

* @return 签名结果

* @throws Exception

*             签名失败则抛出异常

*/

public String rsaSign(String content, String privateKey, String charset) throws SignatureException {

try {

PrivateKey priKey = getPrivateKeyFromPKCS8("RSA", new ByteArrayInputStream(privateKey.getBytes()));

Signature signature = Signature.getInstance("SHA1WithRSA");

signature.initSign(priKey);

if (StringUtils.isEmpty(charset)) {

signature.update(content.getBytes());

} else {

signature.update(content.getBytes(charset));

}

byte[] signed = signature.sign();

return new String(Base64.encodeBase64(signed));

} catch (Exception e) {

throw new SignatureException("RSAcontent = " + content + "; charset = " + charset, e);

}

}

public PrivateKey getPrivateKeyFromPKCS8(String algorithm, InputStream ins) throws Exception {

if (ins == null || StringUtils.isEmpty(algorithm)) {

return null;

}

KeyFactory keyFactory = KeyFactory.getInstance(algorithm);

byte[] encodedKey = StreamUtil.readText(ins).getBytes();

encodedKey = Base64.decodeBase64(encodedKey);

return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));

}

注意:参数privateKey是Pem私钥文件中去除头(-----BEGIN RSA PRIVATE KEY-----)和尾(-----END RSA PRIVATE KEY-----)以及换行符后的字符串。

如果签名报以下错误:

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : algid parse error, not a sequence

则说明rsa私钥的格式不是pksc8格式,需要使用以下命令转换一下:

openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt

然后再提取去除头和尾以及换行符后字符串作为java版用的rsa私钥

2.2 php签名实现

Php代码  收藏代码

function sign($content, $rsaPrivateKeyPem) {

$priKey = file_get_contents($rsaPrivateKeyPem);

$res = openssl_get_privatekey($priKey);

openssl_sign($content, $sign, $res);

openssl_free_key($res);

$sign = base64_encode($sign);

return $sign;

}

注意:$rsaPrivateKeyPem为pem私钥文件路径

2.3 c#签名实现(引用了国外某位仁兄的方案)

C#代码  收藏代码

using System;

using System.Text;

using System.Security.Cryptography;

using System.Web;

using System.IO;

namespace Aop.Api.Util

{

/// <summary>

/// RSA签名工具类。

/// </summary>

public class RSAUtil

{

public static string RSASign(string data, string privateKeyPem)

{

RSACryptoServiceProvider rsaCsp = LoadCertificateFile(privateKeyPem);

byte[] dataBytes = Encoding.UTF8.GetBytes(data);

byte[] signatureBytes = rsaCsp.SignData(dataBytes, "SHA1");

return Convert.ToBase64String(signatureBytes);

}

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 RSACryptoServiceProvider LoadCertificateFile(string filename)

{

using (System.IO.FileStream fs = System.IO.File.OpenRead(filename))

{

byte[] data = new byte[fs.Length];

byte[] res = null;

fs.Read(data, 0, data.Length);

if (data[0] != 0x30)

{

res = GetPem("RSA PRIVATE KEY", data);

}

try

{

RSACryptoServiceProvider rsa = DecodeRSAPrivateKey(res);

return rsa;

}

catch (Exception ex)

{

}

return null;

}

}

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 ex)

{

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;

}

}

}

注:privateKeyPem为私钥文件路径

3. 服务端java验签

Java代码  收藏代码

/**

* rsa验签

*

* @param content 被签名的内容

* @param sign 签名后的结果

* @param publicKey rsa公钥

* @param charset 字符集

* @return 验签结果

* @throws SignatureException 验签失败,则抛异常

*/

boolean doCheck(String content, String sign, String publicKey, String charset) throws SignatureException {

try {

PublicKey pubKey = getPublicKeyFromX509("RSA", new ByteArrayInputStream(publicKey.getBytes()));

Signature signature = Signature.getInstance("SHA1WithRSA");

signature.initVerify(pubKey);

signature.update(getContentBytes(content, charset));

return signature.verify(Base64.decodeBase64(sign.getBytes()));

} catch (Exception e) {

throw new SignatureException("RSA验证签名[content = " + content + "; charset = " + charset

+ "; signature = " + sign + "]发生异常!", e);

}

}

private PublicKey getPublicKeyFromX509(String algorithm, InputStream ins) throws NoSuchAlgorithmException {

try {

KeyFactory keyFactory = KeyFactory.getInstance(algorithm);

StringWriter writer = new StringWriter();

StreamUtil.io(new InputStreamReader(ins), writer);

byte[] encodedKey = writer.toString().getBytes();

// 先base64解码

encodedKey = Base64.decodeBase64(encodedKey);

return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));

} catch (IOException ex) {

// 不可能发生

} catch (InvalidKeySpecException ex) {

// 不可能发生

}

return null;

}

private byte[] getContentBytes(String content, String charset) throws UnsupportedEncodingException {

if (StringUtil.isEmpty(charset)) {

return content.getBytes();

}

return content.getBytes(charset);

}

注意:参数publicKey是Pem公钥文件中去除头(-----BEGIN RSA PRIVATE KEY-----)和尾(-----END RSA PRIVATE KEY-----)以及换行符后的字符串。

时间: 2024-10-16 18:44:51

java/php/c#版rsa签名以及java验签实现的相关文章

java/php/c#版rsa签名以及验签实现

本文为转载,请转载请注明地址: 原文地址为        http://xw-z1985.iteye.com/blog/1837376 在开放平台领域,需要给isv提供sdk,签名是Sdk中需要提供的功能之一.由于isv使用的开发语言不是单一的,因此sdk需要提供多种语言的版 本.譬如java.php.c#.另外,在电子商务尤其是支付领域,对安全性的要求比较高,所以会采用非对称密钥RSA 本文主要介绍如何基于java.php.c#在客户端使用rsa签名,然后在服务端使用Java验签. 基于ope

openssl+前端jsrsa签名+后端nodejs验签

内容如标题所示,总体分为三个部分: 一.win10下安装openssl,然后通过openssl工具生成RSA的公钥和私钥 (1)win10下安装openssl需要的工具有:VS2013,Perl,nasm,openssl源码 其中,VS2013的安装.注册和激活请自行百度,ActivePerl.nasm和openssl源码也请自行下载安装,ActivePerl好说(执行perl example.pl,若提示:Hello from ActivePerl! 则说明Perl安装成功),nasm我选的是

Java实现RSA密钥对并在加解密、加签验签中应用的实例

一.项目结构 二.代码具体实现 1.密钥对生成的两种方式:一种生成公钥私文件,一种生成公钥私串 KeyPairGenUtil.java package com.wangjinxiang.genkey.util; import java.io.FileOutputStream; import java.io.ObjectOutputStream; import java.security.Key; import java.security.KeyPair; import java.security

c# 对XML进行数字签名并且让java验签成功

实现: 1.c#将xml报文做数字签名发送到java服务,java服务成功验签. 2.c#服务对收到java服务推送的xml报文成功验签. 前提: 1.java服务要求 资料: 1.msdn:xml签名:https://docs.microsoft.com/zh-cn/dotnet/standard/security/how-to-sign-xml-documents-with-digital-signatures 2.msdn:xml验签:https://docs.microsoft.com/

RSA后台签名前台验签的应用(前台采用jsrsasign库)

写在前面 安全测试需要, 为防止后台响应数据返给前台过程中被篡改前台再拿被篡改后的数据进行接下来的操作影响正常业务, 决定采用RSA对响应数据进行签名和验签, 于是有了这篇<RSA后台签名前台验签的应用>. 我这里所谓的返给前台的数据只是想加密用户验证通过与否的字段success是true还是false, 前台拿这个success作为判断依据进行下一步的操作, 是进一步向后台发起请求还是直接弹出错误消息.照测试结果看这是个逻辑漏洞, 即使后台返回的是false, 在返回前台的过程中响应包被劫获

PHP RSA签名(公钥、私钥)

1.公钥.私钥格式化(加上前后戳.每64位进行换行) /**********************************私钥格式化*************************************/ 1 function formatPriKey($priKey) { 2 $fKey = "-----BEGIN PRIVATE KEY-----\n"; 3 $len = strlen($priKey); 4 for($i = 0; $i < $len; ) { 5 $

RSA加密解密及RSA加签验签

RSA安全性应用场景说明 在刚接触RSA的时候,会混淆RSA加密解密和RSA加签验签的概念.简单来说加密解密是公钥加密私钥解密,持有公钥(多人持有)可以对数据加密,但是只有持有私钥(一人持有)才可以解密并查看数据:加签验签是私钥加签公钥验签,持有私钥(一人持有)可以加签,持有公钥(多人持有)可以验签. 在金融行业在设计到数据交互传输的时候,需要考虑数据的安全性问题.下文通过介绍RSA的加密和加签两个特性,说明RSA加密技术在保障数据传输过程中的安全性以及实现数据的防篡改和防否机制的应用场景及代码

RSA加密、解密、加签、验签以及生成公私钥

RSA加解密.加验签.生成公私钥代码如下: package util; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.security.KeyFactory; import java.secu

一篇搞定RSA加密与SHA签名|与Java完全同步

看到这篇文章的同学可幸福了,当时在做RSA加密与签名的时候网上的资料简直不要太老,做完后实在是忍受不下去了,这篇文章我会详细讲解iOS如何实现RSA加密与签名,并且与Java完全同步,这是我的第二篇博客,若有什么不足之处还请大家指教. 基础知识 什么是RSA? 答:RSA是一种非对称加密算法,常用来对传输数据进行加密,配合上数字摘要算法,也可以进行文字签名. RSA加密中padding? 答:padding即填充方式,由于RSA加密算法中要加密的明文是要比模数小的,padding就是通过一些填充