java 私钥签名_java/php/c#版rsa签名以及java验签实现--转

本文详细介绍了如何使用Java生成RSA密钥对,包括私钥和公钥,并提供了Java、PHP和C#的签名实现。同时,文章还展示了Java如何进行RSA签名验证,强调了在处理私钥和公钥字符串时的注意事项。

b)生成私钥

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

openssl genrsa -out rsa_private_key.pem 1024

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

-----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,文件内容如下:

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

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDtd1lKsX6ylsAEWFi7E/ut8krJ

y9PQ7sGYKhIm9TvIdZiq5xzyaw8NOLzKZ1k486MePYG4tSuoaxSbwuPLwVUzYFvn

UZo7aWCIGKn16UWTM4nxc/+dwce+bhcKrlLbTWi8l580LTE7GxclTh8z7gHq59iv

haoGbK7FNxlUfB4TSQIDAQAB

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

2. 客户端签名

2.1 java版签名实现

/*** rsa签名

*

*@paramcontent

* 待签名的字符串

*@paramprivateKey

* rsa私钥字符串

*@paramcharset

* 字符编码

*@return签名结果

*@throwsException

* 签名失败则抛出异常*/

public String rsaSign(String content, String privateKey, String charset) throwsSignatureException {try{

PrivateKey priKey= getPrivateKeyFromPKCS8("RSA", newByteArrayInputStream(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 newString(Base64.encodeBase64(signed));

}catch(Exception e) {throw new SignatureException("RSAcontent = " + content + "; charset = " +charset, e);

}

}public PrivateKey getPrivateKeyFromPKCS8(String algorithm, InputStream ins) throwsException {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(newPKCS8EncodedKeySpec(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签名实现

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#签名实现(引用了国外某位仁兄的方案)

usingSystem;usingSystem.Text;usingSystem.Security.Cryptography;usingSystem.Web;usingSystem.IO;namespaceAop.Api.Util

{///

///RSA签名工具类。///

public classRSAUtil

{public static string RSASign(string data, stringprivateKeyPem)

{

RSACryptoServiceProvider rsaCsp=LoadCertificateFile(privateKeyPem);byte[] dataBytes =Encoding.UTF8.GetBytes(data);byte[] signatureBytes = rsaCsp.SignData(dataBytes, "SHA1");returnConvert.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));returnConvert.FromBase64String(base64);

}private static RSACryptoServiceProvider LoadCertificateFile(stringfilename)

{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);returnrsa;

}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 = newMemoryStream(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 = newCspParameters();

CspParameters.Flags=CspProviderFlags.UseMachineKeyStore;

RSACryptoServiceProvider RSA= new RSACryptoServiceProvider(1024, CspParameters);

RSAParameters RSAparams= newRSAParameters();

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);returnRSA;

}catch(Exception ex)

{return null;

}finally{

binr.Close();

}

}private static intGetIntegerSize(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

returncount;

}

}

}

注:privateKeyPem为私钥文件路径

3. 服务端java验签

/*** rsa验签

*

*@paramcontent 被签名的内容

*@paramsign 签名后的结果

*@parampublicKey rsa公钥

*@paramcharset 字符集

*@return验签结果

*@throwsSignatureException 验签失败,则抛异常*/

boolean doCheck(String content, String sign, String publicKey, String charset) throwsSignatureException {try{

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

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

signature.initVerify(pubKey);

signature.update(getContentBytes(content, charset));returnsignature.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) throwsNoSuchAlgorithmException {try{

KeyFactory keyFactory=KeyFactory.getInstance(algorithm);

StringWriter writer= newStringWriter();

StreamUtil.io(newInputStreamReader(ins), writer);byte[] encodedKey =writer.toString().getBytes();//先base64解码

encodedKey =Base64.decodeBase64(encodedKey);return keyFactory.generatePublic(newX509EncodedKeySpec(encodedKey));

}catch(IOException ex) {//不可能发生

} catch(InvalidKeySpecException ex) {//不可能发生

}return null;

}private byte[] getContentBytes(String content, String charset) throwsUnsupportedEncodingException {if(StringUtil.isEmpty(charset)) {returncontent.getBytes();

}returncontent.getBytes(charset);

}

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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值