開發(fā)中經(jīng)常會(huì)有字符串加解密的需求,如用戶密碼加密,可以直接MD5/SHA1加密,MD5/SHA1是不可逆的,驗(yàn)證時(shí)可以對(duì)輸入做MD5/SHA1,然后比較加密后的字符串。但是如果有查詢明文密碼的需求呢?這就不能使用單向加密的方式了,需要使用雙向可逆的加解密,一般常見(jiàn)的有AES/DES/RSA,以下代碼展示了一個(gè)加解密工具類的實(shí)現(xiàn),使用了Java庫(kù)中的加密算法實(shí)現(xiàn)。
附: 常見(jiàn)加密算法以及安全性比較 https://www.cnblogs.com/davytitan/p/3850321.html
package com.cmb.ntms.extconnect.service.utils;
import javax.crypto.*;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;
public class SecurityUtil {
//SecretKey 負(fù)責(zé)保存對(duì)稱密鑰
private SecretKey deskey;
//Cipher負(fù)責(zé)完成加密或解密工作
private Cipher cipher;
public SecurityUtil() throws NoSuchPaddingException, NoSuchAlgorithmException, UnsupportedEncodingException {
KeyGenerator keygen = KeyGenerator.getInstance("AES");
keygen.init(new SecureRandom("defaultSeed".getBytes("UTF-8")));
/*KeyGenerator keygen = KeyGenerator.getInstance("AES");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed("defaultSeed".getBytes());
keygen.init(128, random);*/
deskey = keygen.generateKey();
cipher = Cipher.getInstance("AES");
}
/**
* @param algorithm 加密算法
* @param seed 種子
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
*/
public SecurityUtil(String algorithm, String seed) throws NoSuchAlgorithmException, NoSuchPaddingException, UnsupportedEncodingException {
Security.addProvider(new com.sun.crypto.provider.SunJCE());
//KeyGenerator 提供對(duì)稱密鑰生成器的功能,支持各種算法
KeyGenerator keygen = KeyGenerator.getInstance(algorithm);
keygen.init(new SecureRandom(seed.getBytes("UTF-8")));
//生成密鑰
deskey = keygen.generateKey();
//生成Cipher對(duì)象,指定其支持的算法
cipher = Cipher.getInstance(algorithm);
}
/**
* 字符串加密
*
* @param str
* @return
* @throws InvalidKeyException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
*/
public String encode(String str) throws InvalidKeyException,
IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
cipher.init(Cipher.ENCRYPT_MODE, deskey);
byte[] src = str.getBytes("UTF-8");
byte[] result = cipher.doFinal(src);
//這里如果直接返回new String(result);再getBytes出來(lái),值是不一樣的,所以不直接將字節(jié)數(shù)組強(qiáng)轉(zhuǎn)成字符串,轉(zhuǎn)換為16進(jìn)制字符串返回
//String底層是以Char(2個(gè)字節(jié))數(shù)組記錄的,Byte會(huì)轉(zhuǎn)化成Char,因?yàn)镃har和Byte的長(zhǎng)度不同,所以在轉(zhuǎn)化的過(guò)程中會(huì)對(duì)Byte進(jìn)行整合,主要是用0填充.
return parseByte2HexStr(result);
}
/**
* 對(duì)字符串解密
*
* @param str
* @return
* @throws InvalidKeyException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
*/
public byte[] decode(String str) throws InvalidKeyException,
IllegalBlockSizeException, BadPaddingException {
cipher.init(Cipher.DECRYPT_MODE, deskey);
//先解出字節(jié)數(shù)組
byte[] strBytes = parseHexStr2Byte(str);
return cipher.doFinal(strBytes);
}
/**
* 二進(jìn)制轉(zhuǎn)16進(jìn)制字符串
*
* @param buf
* @return
*/
private String parseByte2HexStr(byte buf[]) {
StringBuilder sb = new StringBuilder();
for (byte aBuf : buf) {
String hex = Integer.toHexString(aBuf & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
/**
* 16進(jìn)制字符串轉(zhuǎn)為二進(jìn)制字節(jié)數(shù)組
*
* @param hexString
* @return
*/
private byte[] parseHexStr2Byte(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (toByte(hexChars[pos]) << 4 | toByte(hexChars[pos + 1]));
}
return d;
}
private static byte toByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
}