使用场景中需要对字符串加密、解密,且加解密可以指定密钥时,可以使用javax.crypto.Cipher类作为加解密工具,java.security.Key作为密钥。
方法一:
- 加密时先将字符串转换成byte数组,用Cipher.doFinal加密后获取加密byte数组,并转换成16进制字符串作为加密结果
- 解密时将需要解密的16进制字符串转换成加密后的byte数组,再用Cipher.doFinal解密,用解密后的byte数组创建String对象获得解密后字符串。
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
public class EncryptUtils {
private static String defaultKey = "youngsun";
//加密工具
private Cipher encryptCipher;
//解密工具
private Cipher decryptCipher;
/**
* 指定密钥构造方法
* @param keyStr 传入的密钥
* @throws Exception
*/
public EncryptUtils(String keyStr) throws Exception {
Key key = getKey(keyStr.getBytes());
encryptCipher = Cipher.getInstance("DES");
encryptCipher.init(Cipher.ENCRYPT_MODE, key);
decryptCipher = Cipher.getInstance("DES");
decryptCipher.init(Cipher.DECRYPT_MODE, key);
}
/** 默认密钥构造方法 */
public EncryptUtils() throws Exception {
this(defaultKey);
}
/**
* byte数组转化成16进制字符串(与hexStr2ByteArr互为转换)
* @param byteArr
* @return hexStr
*/
public static String byteArr2HexStr(byte[] byteArr) throws Exception {
int arrLen = byteArr.length;
//byte转16进制需要预留两位,不到两位的用0补充
StringBuffer sb = new StringBuffer(arrLen*2);
for (int i = 0; i < arrLen; i++) {
int b = byteArr[i];
while (b < 0) {
b = b + 256;
}
if(b < 16){
sb.append("0");
}
String s = Integer.toString(b, 16);
sb.append(s);
}
return sb.toString();
}
/**
* 16进制字符串转换成byte数组(与byteArr2HexStr互为转换)
* @param hexStr
* @return byte[]
*/
public static byte[] hexStr2ByteArr(String hexStr){
int strLen = hexStr.length();
byte[] bytes = new byte[strLen / 2];
for (int i = 0; i < strLen; i = i + 2) {
String byteStr = hexStr.substring(i, i + 2);
bytes[i/2] = (byte)Integer.parseInt(byteStr, 16);
}
return bytes;
}
/**
* byte数组加密
* @param bytes 待加密byte数组
* @return encryptBytes 加密后数组
* @throws Exception
*/
public byte[] encryptBytes(byte[] bytes) throws Exception{
byte[] encryptBytes = encryptCipher.doFinal(bytes);
return encryptBytes;
}
/**
* 字符串加密
* @param str 待加密字符串
* @return
* @throws Exception
*/
public String encryptStr(String str) throws Exception{
byte[] bytes = str.getBytes();
byte[] encryptBytes = encryptCipher.doFinal(bytes);
String encryptStr = byteArr2HexStr(encryptBytes);
return encryptStr;
}
public byte[] decryptBytes(byte[] bytes) throws Exception{
return decryptCipher.doFinal(bytes);
}
public String decryptString(String str) throws Exception{
byte[] bytes = decryptBytes(hexStr2ByteArr(str));
return new String(bytes);
}
/**
* 创建密钥需要数组长度为8位,不足8位的用0替代,超出8位取前八位
* @param keyBytes 密钥字符串转数组,获取Key
* @return Key
*/
private Key getKey(byte[] keyBytes){
byte[] entBytes = new byte[8];
for (int i = 0; i < keyBytes.length && i < entBytes.length; i++) {
entBytes[i] = keyBytes[i];//keyBytes不足8位时,余下
}
Key key = new SecretKeySpec(entBytes, "DES");
return key;
}
}
方法二:
基于方法一,将上面代码中的byte数组与16进制字符串互转部分改为由com.thoughtworks.xstream.core.util.Base64Encoder类加密解密处理。
因为如果加密后的byte数组,直接用于创建String对象作为加密字符串的转换不可逆(再将字符串转换成byte数组后的结果与加密结果byte数组不一致)。
@Test
public void testEncryptUtils(){
String testStr = "123456";
String keyStr = "youngsun";
try {
Key key = new SecretKeySpec(keyStr.getBytes(), "DES");
Cipher encryptCipher = Cipher.getInstance("DES");
encryptCipher.init(Cipher.ENCRYPT_MODE, key);
Cipher decryptCipher = Cipher.getInstance("DES");
decryptCipher.init(Cipher.DECRYPT_MODE, key);
System.out.println("加密前:" + testStr);
byte[] bytes = encryptCipher.doFinal(testStr.getBytes());
System.out.println("加密后数组bytes:" + Arrays.toString(bytes));
String byteStr = new String(bytes);
System.out.println("bytes转换成字符串 byteStr:" + byteStr);
System.out.println("byteStr转换byte数组" + Arrays.toString(byteStr.getBytes()));
Base64Encoder base64Encoder = new Base64Encoder();
String s = base64Encoder.encode(bytes);
System.out.println("加密后:" + s);
byte[] bytes2 = base64Encoder.decode(s);
byte[] bytes1 = decryptCipher.doFinal(bytes2);
System.out.println("解密后:" + new String(bytes1) );
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}catch (InvalidKeyException e) {
e.printStackTrace();
}catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
}
运行结果:
加密前:123456
加密后数组bytes:[58, -67, 118, 96, 3, -74, -109, 5]
bytes转换成字符串 byteStr::�v`��
byteStr转换byte数组[58, -17, -65, -67, 118, 96, 3, -17, -65, -67, -17, -65, -67, 5]
加密后:Or12YAO2kwU=
解密后:123456