Java中RSA非對稱密鑰加解密使用示例

1、簡介: RSA加密算法是最經常使用的非對稱加密算法,CFCA在證書服務中離不了它。RSA是第一個比較完善的公開密鑰算法,它既能用於加密,也能用於數字簽名。這個算法經受住了多年深刻的密碼分析,雖然密碼分析者既不能證實也不可否定RSA的安全性,但這偏偏說明該算法有必定的可信性,目前它已經成爲最流行的公開密鑰算法。javascript

2、RSA的公鑰、私鑰的組成,以及加密、解密的公式可見於下表html

3、使用方式:java

①  假設A、B機器進行通訊,已A機器爲主;算法

②  A首先須要用本身的私鑰爲發送請求數據簽名,並將公鑰一同發送給B;安全

③  B收到數據後,須要用A發送的公鑰進行驗證,已確保收到的數據是未經篡改的;this

④  B驗籤經過後,處理邏輯,並把處理結果返回,返回數據須要用A發送的公鑰進行加密(公鑰加密後,只能用配對的私鑰解密);編碼

⑤  A收到B返回的數據,使用私鑰解密,至此,一次數據交互完成。加密

4、代碼示例:spa

    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後,再去驗證簽名,代碼以下:.net

      複製代碼
      /** * 用公鑰證書進行驗籤 * @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
相關文章
相關標籤/搜索