zoukankan      html  css  js  c++  java
  • 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负责完成加密或解密工作,基于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://pan.baidu.com/share/link?shareid=23044&uk=2986731784
        本文转自:http://www.huosen.net/archives/124.html
  • 相关阅读:
    Football Foundation (FOFO) TOJ 2556
    JAVA- String类练习
    JAVA- 清除数组重复元素
    Mysql远程登陆错误:ERROR 2003
    Linux学习之路(五)压缩命令
    Linux学习之路(四)帮助命令
    如何识别真Microsoft服务与非Microsoft服务来定位病毒自己的服务
    如何用命令行删除EasyBCD开机选择项?
    JAVA- 成员变量与局部变量的区别
    JAVA- 内部类
  • 原文地址:https://www.cnblogs.com/summers/p/4432576.html
Copyright © 2011-2022 走看看