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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM