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

来源:互联网 发布:大话2法力灵动数据 编辑:程序博客网 时间:2024/04/30 04:55

一、简介:
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负责完成加密或解密工作,基于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     * @throws Exception     */    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     * @throws Exception     */    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);        MessageDigest md5 = MessageDigest.getInstance("MD5");        md5.update(message.getBytes("utf-8"));        byte[] digestBytes = md5.digest();        // 得到商户对原文进行的MD5        String md5Digest2 = Base64.byteArrayToBase64(digestBytes);        // 验证签名        if (md5Digest1.equals(md5Digest2)) {            return true;        } else {            return false;        }    }

    至此,签名验签已经完毕


  4. 提供一个从.cer文件读取公钥的方法:
    /**     * 读取公钥cer     * @param path .cer文件的路径  如:c:/abc.cer     * @return  base64后的公钥串     * @throws IOException     * @throws CertificateException     */    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;    }


  5. 附上所有代码: 点击下载
本文转自:霍森博客:http://www.huosen.net/archives/124.html
原创粉丝点击