在上一篇文章中,我們已經將密鑰的生成方法和流程,歸納總結。而本篇主要是講如何利用密鑰進行加解密。
首先,在上一篇文章中的我們生成了很多密鑰,證書等等。
在上述生成的文件中,接收服務端加密報文:pkcs8_private_key.pem給安卓使用解密,private_key.p12 給IOS使用解密(IOS加密是public_key.der文件),rsa_public_key.pem是JAVA服務器端使用的加密密鑰(雙向通信需要用兩套不一樣的密鑰)。發送加密報文:rsa_public_key.pem給安卓使用加密,public_key.der給IOS使用加密,pkcs8_private_key.pem在服務器端進行解密密鑰。
其次,打開密鑰文件后,一般長這個樣子。
於是為了將其利用起來,寫了如下代碼:
1 public static String readWantedText(String url) { 2 try { 3 FileReader fr = new FileReader(url); 4 BufferedReader br = new BufferedReader(fr); 5 StringBuffer sb = new StringBuffer(); 6 7 String temp = "";// 用於臨時保存每次讀取的內容 8 temp = br.readLine(); 9 while ((temp = br.readLine()) != null) { 10 if (temp.charAt(0) == '-') { 11 continue; 12 } 13 sb.append(temp); 14 } 15 16 return sb.toString(); 17 18 } catch (Exception e) { 19 e.printStackTrace(); 20 return null; 21 } 22 }
獲得以上密鑰字符串之后,再將其轉化為可用的密鑰,轉化私鑰代碼如下
1 public static PrivateKey getPrivateKey(String key) throws Exception { 2 3 byte[] keyBytes = key.getBytes(); 4 keyBytes = Base64.decodeBase64(keyBytes); 5 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); 6 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 7 PrivateKey privateKey = keyFactory.generatePrivate(keySpec); 8 return privateKey; 9 }
轉化公鑰代碼如下:
1 public static PublicKey getPublicKey(String key) throws Exception { 2 3 byte[] keyBytes = key.getBytes(); 4 keyBytes = Base64.decodeBase64(keyBytes); 5 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); 6 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 7 PublicKey publicKey = keyFactory.generatePublic(keySpec); 8 return publicKey; 9 }
然后,得到了密鑰之后我們進行加解密操作,其中一個重要的點就是117 可以參考此篇博文:http://www.metsky.com/archives/657.html,詳細了解。這里關注點是,加密117字節加密 一下,解密用128解密。
加密函數如下:
1 public static final String KEY_ALGORITHM = "RSA"; 2 private static final int MAX_ENCRYPT_BLOCK = 117; 3 private static final int MAX_DECRYPT_BLOCK = 128; 4 5 public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception { 6 byte[] keyBytes = Base64Utils.decode(publicKey); 7 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); 8 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 9 Key publicK = keyFactory.generatePublic(x509KeySpec); 10 // 對數據加密 11 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 12 cipher.init(Cipher.ENCRYPT_MODE, publicK); 13 int inputLen = data.length; 14 ByteArrayOutputStream out = new ByteArrayOutputStream(); 15 int offSet = 0; 16 byte[] cache; 17 int i = 0; 18 // 對數據分段加密 19 while (inputLen - offSet > 0) { 20 if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { 21 cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); 22 } else { 23 cache = cipher.doFinal(data, offSet, inputLen - offSet); 24 } 25 out.write(cache, 0, cache.length); 26 i++; 27 offSet = i * MAX_ENCRYPT_BLOCK; 28 } 29 byte[] encryptedData = out.toByteArray(); 30 out.close(); 31 return encryptedData; 32 }
解密函數如下:
public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception { byte[] keyBytes = Base64Utils.decode(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, privateK); int inputLen = encryptedData.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 對數據分段解密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_DECRYPT_BLOCK; } byte[] decryptedData = out.toByteArray(); out.close(); return decryptedData; }
上兩段代碼中,涉及到的轉碼代碼為:
1 public static byte[] decode(String base64) throws Exception { 2 return Base64.decode(base64.getBytes()); 3 } 4 14 public static String encode(byte[] bytes) throws Exception { 15 return new String(Base64.encode(bytes)); 16 }
由此 我們就完成了對密鑰的使用,現在我們通過一個簡單的測試代碼來檢驗我們這幾篇文檔的成果。
1 public static void main(String[] args) { 2 3 4 String publicFilePath = "E:\\test_public_key.pem"; 5 String publickey = RSAForCommunication.readWantedText1(publicFilePath); 6 String word = "這是用來測試,加密效果的一句話,可以試試 有多長。但是目前的情況來看,是可以長場產出噶哈哈哈哈哈哈哈哈啊哈哈哈哈哈啊哈哈哈哈啊啊啊哈哈哈"; 7 String encode =""; 8 try { 9 byte[] a = RSAForCommunication.encryptByPublicKey(word.getBytes(), publickey); 10 encode = Base64Utils.encode(a); 11 } catch (Exception e) { 12 13 } 14 15 System.out.println("-------加密之后的密文:"); 16 System.out.println(encode); 17 18 19 String filePath = "E:\\test_private_key.pem"; 20 String key = RSAForCommunication.readWantedText1(filePath); 21 byte[] a; 22 try { 23 a = Base64Utils.decode(encode); 24 byte[] b = decryptByPrivateKey(a, key); 25 String deCodeStr = new String(b, "utf-8"); 26 System.out.println("--------密文解密為:"); 27 System.out.println(deCodeStr); 28 } catch (Exception ex) { 29 System.out.println("1"); 30 } 31 32 }
結果展示
最后,這里的密文在傳輸過程中會出現空格或者被轉義的情況,請注意!這是因為安卓或者IOS使用了通信框架或者其他原因導致。會使得通信失敗
如果你有更好的加解密辦法請聯系我。
——————————————————————————————————————————
補充
關於Base64的包 不建議使用 sun.misc.BASE64Encoder這個包,具體的原因是由於SUN公司賣給oracle之前,自己定義的一些類。並不在公布的API中,以后隨時可能被刪除掉,所以不建議使用。
建議使用 ,如:org.apache.commons.codec.binary.Base64類