背景
最近在项目中需要使用到AES、RSA、MD5、SHA的加解密,整理了工具类,放出来记录一下,完整的源码已经放到github上。
加解密
AES
/**
* AES 工具类
*/
public class AESUtil {
private final static String SHA1PRNG = "SHA1PRNG";
@IntDef({
Cipher.ENCRYPT_MODE, Cipher.DECRYPT_MODE})
@interface AESType {
}
/**
* Aes加密/解密
*
* @param content 字符串
* @param password 密钥
* @param type 加密:{@link Cipher#ENCRYPT_MODE},解密:{@link Cipher#DECRYPT_MODE}
* @return 加密/解密结果字符串
*/
public static String aes(String content, String password, @AESType int type) {
try {
KeyGenerator generator = KeyGenerator.getInstance("AES");
SecureRandom secureRandom;
if (android.os.Build.VERSION.SDK_INT >= 24) {
secureRandom = SecureRandom.getInstance(SHA1PRNG, new CryptoProvider());
} else if (android.os.Build.VERSION.SDK_INT >= 17) {
secureRandom = SecureRandom.getInstance(SHA1PRNG, "Crypto");
} else {
secureRandom = SecureRandom.getInstance(SHA1PRNG);
}
secureRandom.setSeed(password.getBytes());
generator.init(128, secureRandom);
SecretKey secretKey = generator.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
@SuppressLint("GetInstance") Cipher cipher = Cipher.getInstance("AES");
cipher.init(type, key);
if (type == Cipher.ENCRYPT_MODE) {
byte[] byteContent = content.getBytes("utf-8");
return parseByte2HexStr(cipher.doFinal(byteContent));
} else {
byte[] byteContent = parseHexStr2Byte(content);
return new String(cipher.doFinal(byteContent));
}
} catch (NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException |
UnsupportedEncodingException | InvalidKeyException | NoSuchPaddingException |
NoSuchProviderException e) {
e.printStackTrace();
}
return null;
}
}
RSA
/**
* RSA 工具类
*/
public class RSAUtil {
/**
* 随机获取密钥(公钥和私钥), 客户端公钥加密,服务器私钥解密
*
* @return 结果密钥对
* @throws Exception 异常
*/
public static Map<String, Object> getKeyPair() throws Exception {
KeyPairGenerator keyPairGen = getKeyPairGenerator();
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
Map<String, Object> keyMap = new HashMap<>(2);
keyMap.put("RSAPublicKey", publicKey);
keyMap.put("RSAPrivateKey", privateKey);
return keyMap;
}
/**
* 获取公钥/私钥
*
* @param keyMap 密钥对
* @param isPublicKey true:获取公钥,false:获取私钥
* @return 获取密钥字符串
*/
public static String getKey(Map<String, Object> keyMap, boolean isPublicKey) {
Key key = (Key) keyMap.get(isPublicKey ? "RSAPublicKey" : "RSAPrivateKey");
return new String(Base64.encode(key.getEncoded(), Base64.DEFAULT));
}
/**
* 获取数字签名
*
* @param data 二进制位
* @param privateKey 私钥(BASE64编码)
* @return 数字签名结果字符串
* @throws Exception 异常
*/
public static String sign(byte[] data, String privateKey) throws Exception {
byte[] keyBytes = Base64.decode(privateKey.getBytes(), Base64.DEFAULT);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = getKeyFactory();
PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Signature signature = Signature.getInstance("MD5withRSA");
signature.initSign(privateK);
signature.update(data);
return new String(Base64.encode(signature.sign(), Base64.DEFAULT));
}
/**
* 数字签名校验
*
* @param data 二进位组
* @param publicKey 公钥(BASE64编码)
* @param sign 数字签名字符串
* @return true:校验成功,false:校验失败
* @throws Exception 异常
*/
public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
byte[] keyBytes = Base64.decode(publicKey.getBytes(), Base64.DEFAULT);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = getKeyFactory();
PublicKey publicK = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance("MD5withRSA");
signature.initVerify(publicK);
signature.update(data);
return signature.verify(Base64.decode(sign.getBytes(), Base64.DEFAULT));
}
/**
* 获取 KeyFactory
*
* @throws NoSuchAlgorithmException 异常
*/
private static KeyFactory getKeyFactory() throws NoSuchAlgorithmException,
NoSuchProviderException {
KeyFactory keyFactory;
if (Build.VERSION.SDK_INT >= 16) {
keyFactory = KeyFactory.getInstance("RSA", "BC");
} else {
keyFactory = KeyFactory.getInstance("RSA");
}
return keyFactory;
}
/**
* 获取 KeyFactory
*
* @throws NoSuchAlgorithmException 异常
*/
private static KeyPairGenerator getKeyPairGenerator() throws NoSuchProviderException,
NoSuchAlgorithmException {
KeyPairGenerator keyPairGen;
if (Build.VERSION.SDK_INT >= 16) {
keyPairGen = KeyPairGenerator.getInstance("RSA", "BC");
} else {
keyPairGen = KeyPairGenerator.getInstance("RSA");
}
return keyPairGen;
}
/**
* Rsa公钥加密类型
*/
public static final int RSA_PUBLIC_ENCRYPT = 0;
/**
* Rsa公钥解密类型
*/
public static final int RSA_PUBLIC_DECRYPT = 1;
/**
* Rsa私钥加密类型
*/
public static final int RSA_PRIVATE_ENCRYPT = 2;
/**
* Rsa私钥解密类型
*/
public static final int RSA_PRIVATE_DECRYPT = 3;
@IntDef({
RSA_PUBLIC_ENCRYPT, RSA_PUBLIC_DECRYPT, RSA_PRIVATE_ENCRYPT, RSA_PRIVATE_DECRYPT})
@interface RSAType {
}
/**
* Rsa加密/解密(一般情况下,公钥加密私钥解密)
*
* @param data 源数据
* @param string 密钥(BASE64编码)
* @param type 操作类型:{@link #RSA_PUBLIC_ENCRYPT},{@link #RSA_PUBLIC_DECRYPT
* },{@link #RSA_PRIVATE_ENCRYPT},{@link #RSA_PRIVATE_DECRYPT}
* @return 加密/解密结果字符串
* @throws Exception 异常
*/
public static byte[] rsa(byte[] data, String string, @RSAType int type) throws Exception {
byte[] keyBytes = Base64.decode(string, Base64.DEFAULT);
Key key;
KeyFactory keyFactory = getKeyFactory();
if (type == RSA_PUBLIC_ENCRYPT || type == RSA_PUBLIC_DECRYPT) {
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
key = keyFactory.generatePublic(x509KeySpec);
} else {
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
key = keyFactory.generatePrivate(pkcs8KeySpec);
}
// 对数据加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段加密
if (type == RSA_PUBLIC_ENCRYPT || type == RSA_PRIVATE_ENCRYPT) {
cipher.init(Cipher.ENCRYPT_MODE, key);
while (inputLen - offSet > 0) {
if (inputLen - offSet > 117) {
cache = cipher.doFinal(data, offSet, 117);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
out.flush();
i++;
offSet = i * 117;
}
} else {
cipher.init(Cipher.DECRYPT_MODE, key);
while (inputLen - offSet > 0) {
if (inputLen - offSet > 128) {
cache = cipher.doFinal(data, offSet, 128);
// 当最前面的数据是0,解密工具会错误的认为这是padding,因此导致长度不正确
if (cache.length < 117) {
byte[] temp = new byte[117];
System.arraycopy(cache, 0, temp, 117 - cache.length, cache.length);
cache = temp;
}
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
out.flush();
i++;
offSet = i * 128;
}
}
byte[] result = out.toByteArray();
out.close();
return result;
}
}
MD5
/**
* MD5 工具类
*/
public class MD5Util {
/**
* MD5加密
*
* @param string 加密字符串
* @return 加密结果字符串
* @see #md5(String, String)
*/
public static String md5(@NonNull String string) {
return TextUtils.isEmpty(string) ? "" : md5(string, "");
}
/**
* MD5加密(加盐)
*
* @param string 加密字符串
* @param slat 加密盐值key
* @return 加密结果字符串
*/
public static String md5(@NonNull String string, String slat) {
if (TextUtils.isEmpty(string)) return "";
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] bytes = md5.digest((string + slat).getBytes());
String result = "";
for (byte b : bytes) {
String temp = Integer.toHexString(b & 0xff);
if (temp.length() == 1) {
temp = "0" + temp;
}
result += temp;
}
return result;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
/**
* MD5加密(多次)
*
* @param string 加密字符串
* @param times 重复加密次数
* @return 加密结果字符串
*/
public static String md5(@NonNull String string, int times) {
if (TextUtils.isEmpty(string)) return "";
String md5 = string;
for (int i = 0; i < times; i++) md5 = md5(md5);
return md5;
}
/**
* MD5加密(文件)
* 可用于文件校验。
*
* @param file 加密文件
* @return md5 数值
*/
public static String md5(