开发中经常会有字符串加解密的需求,如用户密码加密,可以直接MD5/SHA1加密,MD5/SHA1是不可逆的,验证时可以对输入做MD5/SHA1,然后比较加密后的字符串。但是如果有查询明文密码的需求呢?这就不能使用单向加密的方式了,需要使用双向可逆的加解密,一般常见的有AES/DES/RSA,以下代码展示了一个加解密工具类的实现,使用了Java库中的加密算法实现。
附: 常见加密算法以及安全性比较 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 负责保存对称密钥
private SecretKey deskey;
//Cipher负责完成加密或解密工作
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 提供对称密钥生成器的功能,支持各种算法
KeyGenerator keygen = KeyGenerator.getInstance(algorithm);
keygen.init(new SecureRandom(seed.getBytes("UTF-8")));
//生成密钥
deskey = keygen.generateKey();
//生成Cipher对象,指定其支持的算法
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出来,值是不一样的,所以不直接将字节数组强转成字符串,转换为16进制字符串返回
//String底层是以Char(2个字节)数组记录的,Byte会转化成Char,因为Char和Byte的长度不同,所以在转化的过程中会对Byte进行整合,主要是用0填充.
return parseByte2HexStr(result);
}
/**
* 对字符串解密
*
* @param str
* @return
* @throws InvalidKeyException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
*/
public byte[] decode(String str) throws InvalidKeyException,
IllegalBlockSizeException, BadPaddingException {
cipher.init(Cipher.DECRYPT_MODE, deskey);
//先解出字节数组
byte[] strBytes = parseHexStr2Byte(str);
return cipher.doFinal(strBytes);
}
/**
* 二进制转16进制字符串
*
* @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进制字符串转为二进制字节数组
*
* @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);
}
}
网友评论