天天看点

Java中RSA非对称密钥加解密使用示例

一、简介:

  rsa加密算法是最常用的非对称加密算法,cfca在证书服务中离不了它。rsa是第一个比较完善的公开密钥算法,它既能用于加密,也能用于数字签名。这个算法经受住了多年深入的密码分析,虽然密码分析者既不能证明也不能否定rsa的安全性,但这恰恰说明该算法有一定的可信性,目前它已经成为最流行的公开密钥算法。

  二、rsa的公钥、私钥的组成,以及加密、解密的公式可见于下表

  三、使用方式:

  ① 假设a、b机器进行通信,已a机器为主;

  ② a首先需要用自己的私钥为发送请求数据签名,并将公钥一同发送给b;

  ③ b收到数据后,需要用a发送的公钥进行验证,已确保收到的数据是未经篡改的;

  ④ b验签通过后,处理逻辑,并把处理结果返回,返回数据需要用a发送的公钥进行加密(公钥加密后,只能用配对的私钥解密);

  ⑤ a收到b返回的数据,使用私钥解密,至此,一次数据交互完成。

  四、代码示例:

  1、第一步获取私钥,为签名做准备。

/**

     * 读取私钥  返回privatekey

     * @param path  包含私钥的证书路径

     * @param password  私钥证书密码

     * @return 返回私钥privatekey

     * @throws keystoreexception

     * @throws nosuchalgorithmexception

     * @throws certificateexception

     * @throws ioexception

     * @throws unrecoverablekeyexception

     */

    private static privatekey getprivatekey(string path,string password)

            throws keystoreexception, nosuchalgorithmexception, certificateexception,

            ioexception, unrecoverablekeyexception {

        keystore ks = keystore.getinstance("pkcs12");

        fileinputstream fis = new fileinputstream(path);

        char[] npassword = null;

        if ((password == null) || password.trim().equals("")) {

            npassword = null;

        } else {

            npassword = password.tochararray();

        }

        ks.load(fis, npassword);

        fis.close();

        enumeration<string> en = ks.aliases();

        string keyalias = null;

        if (en.hasmoreelements()) {

            keyalias = (string) en.nextelement();

        return (privatekey) ks.getkey(keyalias, npassword);

    }

  2、签名示例:通过第一步得到的私钥,进行签名操作,具体请看以下代码:

     * 私钥签名: 签名方法如下:base64(rsa(md5(src),privatekey)),其中src为需要签名的字符串,

privatekey是商户的cfca证书私钥。

     * @param plaintext 待签名字符串

     * @param path 签名私钥路径

     * @param password  签名私钥密码

     * @return 返回签名后的字符串

     * @throws exception

    public static string sign(string plaintext,string path,string password)

            throws exception  {

        /*

         * md5加密

         */

        messagedigest md5 = messagedigest.getinstance("md5");

        md5.update(plaintext.getbytes("utf-8"));

        byte[] digestbytes = md5.digest();

         * 用私钥进行签名 rsa

        cipher cipher = cipher.getinstance("rsa/ecb/pkcs1padding");

        //encrypt_mode表示为加密模式

        cipher.init(cipher.encrypt_mode, getprivatekey(path, password));

        //加密

        byte[] rsabytes = cipher.dofinal(digestbytes);

        //base64编码

        return base64.bytearraytobase64(rsabytes);

  3、b收到数据后,需要使用a提供的公钥信息进行验签,此处使用公钥的n、e进行验签

  首先通过公钥n、e得到公钥publickey,如下:

/** 

     * 根据公钥n、e生成公钥

     * @param modulus   公钥n串

     * @param publicexponent  公钥e串

     * @return 返回公钥publickey

    public static publickey getpublickkey(string modulus, string publicexponent)

            throws exception {

        keyspec publickeyspec = new rsapublickeyspec(

                new biginteger(modulus, 16), new biginteger(publicexponent, 16));

        keyfactory factory = keyfactory.getinstance("rsa");

        publickey publickey = factory.generatepublic(publickeyspec);

        return publickey;

  得到公钥publickey后,再去验证签名,代码如下:

     * 用公钥证书进行验签

     * @param message  签名之前的原文

     * @param ciphertext  签名

     * @param pubkeyn 公钥n串

     * @param pubkeye 公钥e串

     * @return boolean 验签成功为true,失败为false

    public static boolean verify(string message, string ciphertext,string pubkeyn,

            string pubkeye) throws exception {

        cipher c4 = cipher.getinstance("rsa/ecb/pkcs1padding");

        // 根据密钥,对cipher对象进行初始化,decrypt_mode表示解密模式

        c4.init(cipher.decrypt_mode, getpublickkey(pubkeyn,pubkeye));

        // 解密

        byte[] desdectextbytes = c4.dofinal(base64.base64tobytearray(ciphertext));

        // 得到前置对原文进行的md5

        string md5digest1 = base64.bytearraytobase64(desdectextbytes);

        md5.update(message.getbytes("utf-8"));

        // 得到商户对原文进行的md5

        string md5digest2 = base64.bytearraytobase64(digestbytes);

        // 验证签名

        if (md5digest1.equals(md5digest2)) {

            return true;

            return false;

  至此,签名验签已经完毕

  4、提供一个从.cer文件读取公钥的方法:

     * 读取公钥cer

     * @param path .cer文件的路径  如:c:/abc.cer

     * @return  base64后的公钥串

    public static string getpublickey(string path) throws ioexception,

    certificateexception{

        inputstream instream = new fileinputstream(path);

        bytearrayoutputstream out = new bytearrayoutputstream();

        int ch;

        string res = "";

        while ((ch = instream.read()) != -1) {

            out.write(ch);

        byte[] result = out.tobytearray();

        res = base64.bytearraytobase64(result);

        return res;

====================================分割线================================

最新内容请见作者的github页:http://qaseven.github.io/