欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

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

程序员文章站 2022-05-06 09:09:48
...
java/php/c#版rsa签名以及java验签实现

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

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

?

  1. 基于openssl生成RSA公私钥对
a)从网上下载openssl工具,最好是windows下免编译的版本,譬如:http://www.deanlee.cn/programming/openssl-for-windows/

? b)生成私钥

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

openssl genrsa -out rsa_private_key.pem 1024

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

-----BEGIN RSA PRIVATE KEY-----MIICXgIBAAKBgQDtd1lKsX6ylsAEWFi7E/ut8krJy9PQ7sGYKhIm9TvIdZiq5xzyaw8NOLzKZ1k486MePYG4tSuoaxSbwuPLwVUzYFvnUZo7aWCIGKn16UWTM4nxc/+dwce+bhcKrlLbTWi8l580LTE7GxclTh8z7gHq59ivhaoGbK7FNxlUfB4TSQIDAQABAoGBAIgTk0x1J+hI8KHMypPxoJCOPoMi1S9uEewTd7FxaB+4G5Mbuv/Dj62A7NaDoKI9IyUqE9L3ppvtOLMFXCofkKU0p4j7MEJdZ+CjVvgextkWa80nj/UZiM1oOL6YHwH4ZtPtY+pFCTK1rdn3+070qBB9tnVntbN/jq0Ld7f0t7UNAkEA9ryI0kxJL9PupO9NEeWuCUo4xcl9x/M9+mtkfY3VoDDDV1E/eUjmoTfANYwrjcddiQrO0MLyEdootiLpN77qOwJBAPZhtv/+pqMVTrLxWnVKLZ4ZVTPPgJQQkFdhWwYlz7oKzB3VbQRt/jLFXUyCN2eCP7rglrXnaz7AYBftF0ajHEsCQQDDNfkeQULqN0gpcDdOwKRIL1PpkHgWmWlg1lTETVJGEi6Kx/prL/VgeiZ1dzgCTUjAoy9r1cEFxM/PAqH3+/F/AkEAzsTCp6Q2hLblDRewKq7OCdiIwKpr5dbgy/RQR6CD7EYTdxYeH5GPu1wXKJY/mQaeJV9GG/LS9h7MhkfbONS6cQJAdBEb5vloBDLcSQFDQO/VZ9SKFHCmHLXluhhIizYKGzgf3OXEGNDSAC3qy+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/ut8krJy9PQ7sGYKhIm9TvIdZiq5xzyaw8NOLzKZ1k486MePYG4tSuoaxSbwuPLwVUzYFvnUZo7aWCIGKn16UWTM4nxc/+dwce+bhcKrlLbTWi8l580LTE7GxclTh8z7gHq59ivhaoGbK7FNxlUfB4TSQIDAQAB-----END PUBLIC KEY-----

?

?2.?客户端签名

? 2.1?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-----)以及换行符后的字符串。

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

using System;using System.Text;using System.Security.Cryptography;using System.Web;using System.IO;namespace Aop.Api.Util{    ///     /// RSA签名工具类。    ///     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;        }    }}

?

? 3. 服务端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);    }

?

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

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。

相关文章

相关视频


网友评论

文明上网理性发言,请遵守 新闻评论服务协议

我要评论
  • java/php/c#版rsa签字以及java验签实现
  • 专题推荐

    作者信息
    java/php/c#版rsa签字以及java验签实现

    认证0级讲师

    推荐视频教程
  • java/php/c#版rsa签字以及java验签实现javascript初级视频教程
  • java/php/c#版rsa签字以及java验签实现jquery 基础视频教程
  • 视频教程分类