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=298673178   
  6. 轉載自http://www.huosen.net/archives/124.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章