之前用的对称加密,安全方面欠妥。后来换成了RSA非对称加密,走了很多弯路。比如:
1、利用JAVA代码生成出来的秘钥对不能正确解密和加密;
2、密文加解密长度限制等等;
网上找了好多资料后终于调通了,现总结如下:
1、运用SSL工具生成IOS和JAVA能识别的证书,不懂的可以问问度娘;
2、Windows环境搭建SSL麻烦点,但是mac自带有这个,可以让有mac的兄dei生成哈就可以了;
3、生成好之后,有两种方式加载公钥和私钥 有两种方式,一是通过读取文件,二是直接写成字符串(文件里面也是字符串)。
4、调节过程遇到的坑,我已经改好了。现弄成了一个Util,代码如下:
需要用到的JAR:maven配置
package com.common;
import java.math.BigInteger;
import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
import org.bouncycastle.util.encoders.Base64;
import net.sf.json.JSONObject;
public class RSAUtil {
private static final String RSA = "RSA";
private static final String PUBLIC_KEY = "public";
private static final String PRIVATE_KEY = "private";
/**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 117;
/**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 128;
/**
* 生成公钥和私钥
*/
public static Map
try {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(RSA);
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
Map
map.put(PUBLIC_KEY, publicKey);
map.put(PRIVATE_KEY, privateKey);
return map;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
/**
* 使用模和指数生成RSA公钥 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA/None/NoPadding】
* @param modulus 模
* @param exponent 指数
* @return
*/
public static RSAPublicKey getPublicKey(String modulus, String exponent) {
try {
BigInteger b1 = new BigInteger(modulus);
BigInteger b2 = new BigInteger(exponent);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
return null;
}
/**
* 使用模和指数生成RSA私钥 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA/None/NoPadding】
* @param modulus 模
* @param exponent 指数
* @return
*/
public static RSAPrivateKey getPrivateKey(String modulus, String exponent) {
try {
BigInteger b1 = new BigInteger(modulus);
BigInteger b2 = new BigInteger(exponent);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
return null;
}
/**
* 公钥加密
* @param data
* @param publicKey
* @return
*/
public static String encryptByPublicKey(String data, RSAPublicKey publicKey) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 模长
int key_len = publicKey.getModulus().bitLength() / 8;
// 加密数据长度 <= 模长-11
String[] datas = splitString(data, key_len-11);
String mi = "";
// 如果明文长度大于模长-11则要分组加密
for (String s : datas) {
mi += bcd2Str(cipher.doFinal(s.getBytes()));
}
return mi;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* @Title: RSAEncode
* @Description: 将字符串加密
* @param key
* @param data
* @return String
*/
public static String RSAEncode(String data, RSAPublicKey publicKey) {
byte[] b = data.getBytes();
try {
int inputLen = b.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(b, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(b, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return Base64Utils.encode(decryptedData);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 私钥解密
* @param data
* @param privateKey
* @return
*/
public static String decryptByPrivateKey(String data, RSAPrivateKey privateKey) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// 模长
int key_len = privateKey.getModulus().bitLength() / 8;
byte[] bytes = data.getBytes();
byte[] bcd = ASCII_To_BCD(bytes, bytes.length);
System.err.println(bcd.length);
// 如果密文长度大于模长则要分组解密
String ming = "";
byte[][] arrays = splitArray(bcd, key_len);
for (byte[] arr : arrays) {
ming += new String(cipher.doFinal(arr));
}
return ming;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* @Title: RSADecode
* @Description: 将字符串解密
* @param key
* @param encodedText
* @return String
*/
public static String RSADecode(String data, RSAPrivateKey privateKey) {
try {
byte[] b = Base64.decode(data);
int inputLen = b.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(b, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(b, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return new String(decryptedData);
} catch (Exception e) {
System.err.println("******分段解密失败!******");
e.printStackTrace();
}
return null;
}
/**
* 从字符串中加载公钥
*
* @param publicKeyStr
* 公钥数据字符串
* @throws Exception
* 加载公钥时产生的异常
*/
public static RSAPublicKey loadPublicKey(String publicKeyStr){
try {
byte[] buffer = Base64.decode(publicKeyStr);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
}catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static RSAPrivateKey loadPrivateKey(String privateKeyStr){
try {
byte[] buffer = Base64.decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
}catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* ASCII码转BCD码
*/
private static byte[] ASCII_To_BCD(byte[] ascii, int asc_len) {
byte[] bcd = new byte[asc_len / 2];
int j = 0;
for (int i = 0; i < (asc_len + 1) / 2; i++) {
bcd[i] = asc_to_bcd(ascii[j++]);
bcd[i] = (byte) (((j >= asc_len) ? 0x00 : asc_to_bcd(ascii[j++])) + (bcd[i] << 4));
}
return bcd;
}
private static byte asc_to_bcd(byte asc) {
byte bcd;
if ((asc >= '0') && (asc <= '9')) bcd = (byte) (asc - '0');
else if ((asc >= 'A') && (asc <= 'F')) bcd = (byte) (asc - 'A' + 10);
else if ((asc >= 'a') && (asc <= 'f')) bcd = (byte) (asc - 'a' + 10);
else bcd = (byte) (asc - 48);
return bcd;
}
/**
* BCD转字符串
*/
private static String bcd2Str(byte[] bytes) {
char temp[] = new char[bytes.length * 2], val;
for (int i = 0; i < bytes.length; i++) {
val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f);
temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
val = (char) (bytes[i] & 0x0f);
temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
}
return new String(temp);
}
/**
* 拆分字符串
*/
private static String[] splitString(String string, int len) {
int x = string.length() / len;
int y = string.length() % len;
int z = 0;
if (y != 0) {
z = 1;
}
String[] strings = new String[x + z];
String str = "";
for (int i = 0; i < x + z; i++) {
if (i == x + z - 1 && y != 0) {
str = string.substring(i * len, i * len + y);
} else {
str = string.substring(i * len, i * len + len);
}
strings[i] = str;
}
return strings;
}
/**
* 拆分数组
*/
private static byte[][] splitArray(byte[] data, int len) {
int x = data.length / len;
int y = data.length % len;
int z = 0;
if (y != 0) {
z = 1;
}
byte[][] arrays = new byte[x + z][];
byte[] arr;
for (int i = 0; i < x + z; i++) {
arr = new byte[len];
if (i == x + z - 1 && y != 0) {
System.arraycopy(data, i * len, arr, 0, y);
} else {
System.arraycopy(data, i * len, arr, 0, len);
}
arrays[i] = arr;
}
return arrays;
}
public static JSONObject getContext(String data) {
JSONObject object=new JSONObject();
//String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCv7OU1DVIFIZU4H0+X8grUCrUeqw7tqAXQtR8BWBpStNhcyupLsqEfgQn1sBOATNuSkags4Lxa7TEdQIu1Mmgsbb4ESAsRzhhj57vcBmvvl2QWq+Mi/g+PVimdC/tV9Fbu3cN/Dy+tIs3lgdhEbzkLed40cs0qR1H7k+JYV/42pQIDAQAB";
String privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAK/s5TUNUgUhlTgfT5fyCtQKtR6rDu2oBdC1HwFYGlK02FzK6kuyoR+BCfWwE4BM25KRqCzgvFrtMR1Ai7UyaCxtvgRICxHOGGPnu9wGa++XZBar4yL+D49WKZ0L+1X0Vu7dw38PL60izeWB2ERvOQt53jRyzSpHUfuT4lhX/jalAgMBAAECgYBHFQDHnso1KIySUJRoYHPfmTP1YEh33hv7aDNO57o7ELcbRyHD1Dkl8Y2Ep9A5VtShNBkviN6SHqRpnVrVq7hLD82UmerfqhGNiC6HFa+aYeiRqVL+Pq3Hs/kH6ktc4S00+oixXRi3J8Q88wNFpRnh4ObOANkxV2/FGCox/OdIAQJBANRsxszNv3fltOvnx4JhhXJHmOwuG6jbTM1t2m2d+uvfxuMBrEZQrJZB/EcO4Sn0tmcg0zisuNsYt5C82USgHUUCQQDUA2RjlAGLZafGMQ00eBWE1NasU6j1zaS9oLsBy0QEz2un3qJQHv/s9VvvJQftQco37zK/jGP1kj3nJ9+HcdnhAkAwBD6TwNZM5dGVmZjRcfXWNTTt/iYmbxvXO8OqD5HOi5DLc29bnZTFijjaXxSqhTRN72+PWguXCulDgEykZIT5AkA45cAnSS0w79MayUc18ZQ01bnW/Yy2ir3Pdjc5wAc9Ez1dC86bmfYs7ZwCjfmWnrVaVYNVDKQ230xloLnIa7GBAkAFD14+ch9ewjr90tBeUZBncds2eTF7LF5nEU7fgvcxOCdWKQ3yeZiJJyESRBnK6Oufoz2sn7CpGp9ggvFZmkS1";
String context="";
try {
context = RsaUtil.RSADecode(data, RsaUtil.loadPrivateKey(privateKey));
} catch (Exception e) {
e.printStackTrace();
context="";
object=null;
}finally{
if(!"".equals(context)){
object= JSONObject.fromObject(context);
}else{
object=null;
}
}
return object;
}
public static void main(String[] args) {
try {
String publicKey = "自己生成秘钥对里的公钥";
String privateKey = "自己生成秘钥对里的私钥";
// 明文
//String ming = "{\"code\":\"396275\",\"time\":1542180738730,\"user\":\"lzwsnlh\"}";
/*System.out.println("public key :"+publicKey);
System.out.println("private key :"+privateKey);
// 加密后的密文
String mi = RsaUtil.RSAEncode(ming, RsaUtil.loadPublicKey(publicKey));
System.out.println("加密后密文:"+mi);*/
// 解密后的明文
String ms = "iUOwkSL9L9LFs1qi1rF2MdnAfiVCv7TUGLP6ZrakJ+OwgcP9Yvo2Hfzu5nrg2plz0cM7cM/4NLwnM+EiT7z1ttxp+An2tfSbnBb8N4h762/yQ1vowCHjX0MiLmgJPnv3snO/a81ZrirBlx9sq3u0vazd0GqaLejgmNhFEB73YSSh4NsSVwRxsyjp1fj4hO5wsRQ/LOCyK6DukeQZ8uXZZcuWaT5NWZtV0vMhMTyJ76drbKWU+hHr759uOi2jL7iNjM3tlw4EVVuDf9rOUu8yBxMFWFBhleRIyIoyKCIhx8u9woJyBvSATQ6kmlhacwOdiNbiB1/b/yUGlqf5o+00xQ==";
String ming="";
ming = RsaUtil.RSADecode(ms, RsaUtil.loadPrivateKey(privateKey));
System.out.println(ming);
} catch (Exception e) {
e.printStackTrace();
}
}
}
其中:Base64Utils类如下:
package com.common;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import com.sun.org.apache.xml.internal.security.utils.Base64;
public class Base64Utils {
/** *//**
* 文件读取缓冲区大小
*/
private static final int CACHE_SIZE = 1024;
/** *//**
*
* BASE64字符串解码为二进制数据
*
* 二进制数据编码为BASE64字符串
*
* 将文件编码为BASE64字符串
*
* 大文件慎用,可能会导致内存溢出
*
* BASE64字符串转回文件
*
* 文件转换为二进制数组
*
* 二进制数据写文件
*