在上一篇文章中,我们已经将密钥的生成方法和流程,归纳总结。而本篇主要是讲如何利用密钥进行加解密。
首先,在上一篇文章中的我们生成了很多密钥,证书等等。
在上述生成的文件中,接收服务端加密报文: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类