標籤:
一、簡介: RSA密碼編譯演算法是最常用的非對稱式加密演算法,CFCA在認證服務中離不了它。RSA是第一個比較完善的公開密鑰演算法,它既能用於加密,也能用於數位簽章。這個演算法經受住了多年深入的密碼分析,雖然密碼分析者既不能證明也不能否定RSA的安全性,但這恰恰說明該演算法有一定的可信性,目前它已經成為最流行的公開密鑰演算法。
二、RSA的公開金鑰、私密金鑰的組成,以及加密、解密的公式可見於下表
三、使用方式:
① 假設A、B機器進行通訊,已A機器為主;
② A首先需要用自己的私密金鑰為發送請求資料簽名,並將公開金鑰一同發送給B;
③ B收到資料後,需要用A發送的公開金鑰進行驗證,已確保收到的資料是未經篡改的;
④ B驗簽通過後,處理邏輯,並把處理結果返回,返回資料需要用A發送的公開金鑰進行加密(公開金鑰加密後,只能用配對的私密金鑰解密);
⑤ A收到B返回的資料,使用私密金鑰解密,至此,一次資料互動完成。
四、程式碼範例:
- 第一步擷取私密金鑰,為簽名做準備。
/** * 讀取私密金鑰 返回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); }
- 簽名樣本 通過第一步得到的私密金鑰,進行簽名操作,具體請看以下代碼:
/** * 私密金鑰簽名: 簽名方法如下: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);
- 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; } } 至此,簽名驗簽已經完畢
- 提供一個從.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; }
- 附上所有代碼: http://pan.baidu.com/share/link?shareid=23044&uk=2986731784
本文轉自:http://www.huosen.net/archives/124.html
Java中RSA非對稱金鑰加解密使用樣本