很簡單的一個需求,ipad端給密碼RSA加密,傳到java后臺,解密。RSA加密算法是基于一個密鑰對的,分為公鑰和私鑰,一般情況公鑰加密,私鑰解密,但也可私鑰加密,公鑰解密。還可以驗簽,就是先用私鑰對數據進行加密,然后對加密后的數據進行簽名,得到一個簽名值。然后再用公鑰先驗簽,證明是對應私鑰加密過的數據才解密。主要是為了防止來源不確定的數據。 根據上面的介紹,大家也都知道,RSA算法的關鍵就是密鑰對,我和IOS的同事各自找了RSA的算法實現代碼,都能正常根據密鑰對加解密。問題是我們各自使用對方的密鑰對就不能加解密成功。IOS同事也是一個新手。連RSA算法是個什么概念都沒搞清楚,我也懂點IOS。所以就陪著他一起看代碼,找資料??吹降资裁丛蛞鸬拿荑€對不能共用。后來找到下面這篇文章: Java中使用OpenSSL生成的RSA公私鑰進行數據加解密
原來在用mac 系統中自帶的openssl生成的密鑰對文件是X509編碼格式的。而我們JAVA所需的私鑰文件是PKCS#8編碼格式的。。所以要將在mac 系統中生成的私鑰文件轉下碼就行了。轉碼方式參考上面鏈接。附下java代碼:
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.security.InvalidKeyException;import java.security.KeyFactory;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.NoSuchAlgorithmException;import java.security.SecureRandom;import java.security.interfaces.RSAPrivateKey;import java.security.interfaces.RSAPublicKey;import java.security.spec.InvalidKeySpecException;import java.security.spec.PKCS8EncodedKeySpec;import java.security.spec.X509EncodedKeySpec;import javax.crypto.BadPaddingException;import javax.crypto.Cipher;import javax.crypto.IllegalBlockSizeException;import javax.crypto.NoSuchPaddingException;import sun.misc.BASE64Decoder;import sun.misc.BASE64Encoder;public class RSAEncrypt { private static final String DEFAULT_PUBLIC_KEY= "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChDzcjw/rWgFwnxunbKp7/4e8w" + "/r" + "/UmXx2jk6qEEn69t6N2R1i/LmcyDT1xr/T2AHGOiXNQ5V8W4iCaaeNawi7aJaRht" + "/r" + "Vx1uOH/2U378fscEESEG8XDqll0GCfB1/TjKI2aitVSzXOtRs8kYgGU78f7VmDNg" + "/r" + "XIlk3gdhnzh+uoEQywIDAQAB" + "/r"; private static final String DEFAULT_PRIVATE_KEY= "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKEPNyPD+taAXCfG" + "/r" + "6dsqnv/h7zD9SZfHaOTqoQSfr23o3ZHWL8uZzINPXGv9PYAcY6Jc1DlXxbiIJpp4" + "/r" + "1rCLtolpGG1XHW44f/ZTfvx+xwQRIQbxcOqWXQYJ8HX9OMojZqK1VLNc61GzyRiA" + "/r" + "ZTvx/tWYM2BciWTeB2GfOH66gRDLAgMBAAECgYBp4qTvoJKynuT3SbDJY/XwaEtm" + "/r" + "u768SF9P0GlXrtwYuDWjAVue0VhBI9WxMWZTaVafkcP8hxX4QZqPh84td0zjcq3j" + "/r" + "DLOegAFJkIorGzq5FyK7ydBoU1TLjFV459c8dTZMTu+LgsOTD11/V/Jr4NJxIudo" + "/r" + "MBQ3c4cHmOoYv4uzkQJBANR+7Fc3e6oZgqTOesqPSPqljbsdF9E4x4eDFuOecCkJ" + "/r" + "DvVLOOoAzvtHfAiUp+H3fk4hXRpALiNBEHiIdhIuX2UCQQDCCHiPHFd4gC58yyCM" + "/r" + "6Leqkmoa+6YpfRb3oxykLBXcWx7DtbX+ayKy5OQmnkEG+MW8XB8wAdiUl0/tb6cQ" + "/r" + "FaRvAkBhvP94Hk0DMDinFVHlWYJ3xy4pongSA8vCyMj+aSGtvjzjFnZXK4gIjBjA" + "/r" + "2Z9ekDfIOBBawqp2DLdGuX2VXz8BAkByMuIh+KBSv76cnEDwLhfLQJlKgEnvqTvX" + "/r" + "TB0TUw8avlaBAXW34/5sI+NUB1hmbgyTK/T/IFcEPXpBWLGO+e3pAkAGWLpnH0Zh" + "/r" + "Fae7oAqkMAd3xCNY6ec180tAe57hZ6kS+SYLKwb4gGzYaCxc22vMtYksXHtUeamo" + "/r" + "1NMLzI2ZfUoX" + "/r"; /** * 私鑰 */ private RSAPrivateKey privateKey; /** * 公鑰 */ private RSAPublicKey publicKey; /** * 字節數據轉字符串專用集合 */ private static final char[] HEX_CHAR= {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; /** * 獲取私鑰 * @return 當前的私鑰對象 */ public RSAPrivateKey getPrivateKey() { return privateKey; } /** * 獲取公鑰 * @return 當前的公鑰對象 */ public RSAPublicKey getPublicKey() { return publicKey; } /** * 隨機生成密鑰對 */ public void genKeyPair(){ KeyPairGenerator keyPairGen= null; try { keyPairGen= KeyPairGenerator.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } keyPairGen.initialize(1024, new SecureRandom()); KeyPair keyPair= keyPairGen.generateKeyPair(); this.privateKey= (RSAPrivateKey) keyPair.getPrivate(); this.publicKey= (RSAPublicKey) keyPair.getPublic(); } /** * 從文件中輸入流中加載公鑰 * @param in 公鑰輸入流 * @throws Exception 加載公鑰時產生的異常 */ public void loadPublicKey(InputStream in) throws Exception{ try { BufferedReader br= new BufferedReader(new InputStreamReader(in)); String readLine= null; StringBuilder sb= new StringBuilder(); while((readLine= br.readLine())!=null){ if(readLine.charAt(0)=='-'){ continue; }else{ sb.append(readLine); sb.append('/r'); } } loadPublicKey(sb.toString()); } catch (IOException e) { throw new Exception("公鑰數據流讀取錯誤"); } catch (NullPointerException e) { throw new Exception("公鑰輸入流為空"); } } /** * 從字符串中加載公鑰 * @param publicKeyStr 公鑰數據字符串 * @throws Exception 加載公鑰時產生的異常 */ public void loadPublicKey(String publicKeyStr) throws Exception{ try { BASE64Decoder base64Decoder= new BASE64Decoder(); byte[] buffer= base64Decoder.decodeBuffer(publicKeyStr); KeyFactory keyFactory= KeyFactory.getInstance("RSA"); X509EncodedKeySpec keySpec= new X509EncodedKeySpec(buffer); this.publicKey= (RSAPublicKey) keyFactory.generatePublic(keySpec); } catch (NoSuchAlgorithmException e) { throw new Exception("無此算法"); } catch (InvalidKeySpecException e) { throw new Exception("公鑰非法"); } catch (IOException e) { throw new Exception("公鑰數據內容讀取錯誤"); } catch (NullPointerException e) { throw new Exception("公鑰數據為空"); } } /** * 從文件中加載私鑰 * @param keyFileName 私鑰文件名 * @return 是否成功 * @throws Exception */ public void loadPrivateKey(InputStream in) throws Exception{ try { BufferedReader br= new BufferedReader(new InputStreamReader(in)); String readLine= null; StringBuilder sb= new StringBuilder(); while((readLine= br.readLine())!=null){ if(readLine.charAt(0)=='-'){ continue; }else{ sb.append(readLine); sb.append('/r'); } } loadPrivateKey(sb.toString()); } catch (IOException e) { throw new Exception("私鑰數據讀取錯誤"); } catch (NullPointerException e) { throw new Exception("私鑰輸入流為空"); } } public void loadPrivateKey(String privateKeyStr) throws Exception{ try { BASE64Decoder base64Decoder= new BASE64Decoder(); byte[] buffer= base64Decoder.decodeBuffer(privateKeyStr); PKCS8EncodedKeySpec keySpec= new PKCS8EncodedKeySpec(buffer); KeyFactory keyFactory= KeyFactory.getInstance("RSA"); this.privateKey= (RSAPrivateKey) keyFactory.generatePrivate(keySpec); } catch (NoSuchAlgorithmException e) { throw new Exception("無此算法"); } catch (InvalidKeySpecException e) { e.printStackTrace(); throw new Exception("私鑰非法"); } catch (IOException e) { throw new Exception("私鑰數據內容讀取錯誤"); } catch (NullPointerException e) { throw new Exception("私鑰數據為空"); } } /** * 加密過程 * @param publicKey 公鑰 * @param plainTextData 明文數據 * @return * @throws Exception 加密過程中的異常信息 */ public byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData) throws Exception{ if(publicKey== null){ throw new Exception("加密公鑰為空, 請設置"); } Cipher cipher= null; try { cipher= Cipher.getInstance("RSA");//, new BouncyCastleProvider()); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] output= cipher.doFinal(plainTextData); return output; } catch (NoSuchAlgorithmException e) { throw new Exception("無此加密算法"); } catch (NoSuchPaddingException e) { e.printStackTrace(); return null; }catch (InvalidKeyException e) { throw new Exception("加密公鑰非法,請檢查"); } catch (IllegalBlockSizeException e) { throw new Exception("明文長度非法"); } catch (BadPaddingException e) { throw new Exception("明文數據已損壞"); } } /** * 解密過程 * @param privateKey 私鑰 * @param cipherData 密文數據 * @return 明文 * @throws Exception 解密過程中的異常信息 */ public byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData) throws Exception{ if (privateKey== null){ throw new Exception("解密私鑰為空, 請設置"); } Cipher cipher= null; try { cipher= Cipher.getInstance("RSA");//, new BouncyCastleProvider()); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] output= cipher.doFinal(cipherData); return output; } catch (NoSuchAlgorithmException e) { throw new Exception("無此解密算法"); } catch (NoSuchPaddingException e) { e.printStackTrace(); return null; }catch (InvalidKeyException e) { throw new Exception("解密私鑰非法,請檢查"); } catch (IllegalBlockSizeException e) { throw new Exception("密文長度非法"); } catch (BadPaddingException e) { throw new Exception("密文數據已損壞"); } } /** * 字節數據轉十六進制字符串 * @param data 輸入數據 * @return 十六進制內容 */ public static String byteArrayToString(byte[] data){ StringBuilder stringBuilder= new StringBuilder(); for (int i=0; i<data.length; i++){ //取出字節的高四位 作為索引得到相應的十六進制標識符 注意無符號右移 stringBuilder.append(HEX_CHAR[(data[i] & 0xf0)>>> 4]); //取出字節的低四位 作為索引得到相應的十六進制標識符 stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]); if (i<data.length-1){ stringBuilder.append(' '); } } return stringBuilder.toString(); } public static void main(String[] args){ RSAEncrypt rsaEncrypt= new RSAEncrypt(); //rsaEncrypt.genKeyPair(); //加載公鑰 try { rsaEncrypt.loadPublicKey(RSAEncrypt.DEFAULT_PUBLIC_KEY); System.out.println("加載公鑰成功"); } catch (Exception e) { System.err.println(e.getMessage()); System.err.println("加載公鑰失敗"); } //加載私鑰 try { rsaEncrypt.loadPrivateKey(RSAEncrypt.DEFAULT_PRIVATE_KEY); System.out.println("加載私鑰成功"); } catch (Exception e) { System.err.println(e.getMessage()); System.err.println("加載私鑰失敗"); } //測試字符串 String encryptStr= "abc"; System.out.println("私鑰長度:"+rsaEncrypt.getPrivateKey().toString().length()); System.out.println("公鑰長度:"+rsaEncrypt.getPublicKey().toString().length()); try { //加密 byte[] cipher = rsaEncrypt.encrypt(rsaEncrypt.getPublicKey(), encryptStr.getBytes()); //解密 byte[] plainText = rsaEncrypt.decrypt(rsaEncrypt.getPrivateKey(), cipher); System.out.println("密文長度:"+ cipher.length); System.out.println(RSAEncrypt.byteArrayToString(cipher)); System.out.println("明文長度:"+ plainText.length); System.out.println(RSAEncrypt.byteArrayToString(plainText)); System.out.println(new String(plainText)); } catch (Exception e) { System.err.println(e.getMessage()); } }}提供兩種方式加載密鑰對,可通過字符串或者文件流,文件是指生成的.pem文件才可以哦。 另外附一份IOS中加密方法,不過這里要求的文件是der。 http://blog.yorkgu.me/2011/10/27/rsa-in-ios-using-publick-key-generated-by-openssl/ IOS中加密后返回的NSdata對象,可以對NSdata對象進行base64編碼轉換成字符串,然后java用BASE64Decoder解碼之后,就轉換成了byte[],可直接用上面方法解密。。。
新聞熱點
疑難解答