qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          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;
              }

          posted on 2012-09-10 09:47 順其自然EVO 閱讀(1523) 評論(2)  編輯  收藏

          評論

          # re: Java中RSA非對稱密鑰加解密使用示例 2012-10-17 12:25 bigfishyuwan

          good,簡單明了  回復  更多評論   

          # re: Java中RSA非對稱密鑰加解密使用示例 2012-12-20 13:44 horr

          看著文章這么熟悉呢  回復  更多評論   


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          <2012年9月>
          2627282930311
          2345678
          9101112131415
          16171819202122
          23242526272829
          30123456

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 衢州市| 徐水县| 桂东县| 巫溪县| 大冶市| 牙克石市| 万年县| 盈江县| 郧西县| 大埔区| 江西省| 平武县| 澄江县| 洛南县| 北安市| 营口市| 红桥区| 南投市| 洮南市| 布尔津县| 碌曲县| 孝昌县| 治多县| 乌兰浩特市| 武陟县| 平陆县| 祁连县| 江达县| 信阳市| 千阳县| 黄大仙区| 宁阳县| 体育| 鄄城县| 宕昌县| 饶阳县| 平度市| 田东县| 中西区| 临夏市| 特克斯县|