java/php/c#版rsa簽字以及java驗簽實現

來源:互聯網
上載者:User
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);    }

?

  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.