上一篇,我们已经搭建简单的搭建好了基于mysql数据库数据的shiro安全框架。接下来,我们为密码进行3DES加密。
需要注意的是,密码字段加密,正常思路是在注册时,把注册信息存进数据库前对密码进行加密后再存入。我们这里没有注册业务,所以我们自行提供一个接口为密码字段进行加密,然后再更新进数据库。
这里简单的说下,3DES,也称为3DESede或TripleDES,属于双向加密,是三重数据加密,且可以逆推的一种算法方案。1975年美国IBM公司成功研究并发布了DES加密算法,但DES密码长度容易被暴力破解,通过对DES算法进行改进,针对每个数据块进行三次DES加密,也就是3DES加密算法。算法本身是公开的,主要是依靠唯一密钥,也就是key,来确保数据加密解密的安全。
ThreeDES.class:
@SuppressWarnings({ "restriction" })
public class ThreeDES {
private static final String IV = "1234567-";
public static final String KEY = "uatspdbcccgame2014061800";
/**
* DESCBC加密
*
* @param src
* 数据源
* @param key
* 密钥,长度必须是8的倍数
* @return 返回加密后的数据
* @throws Exception
*/
public String encryptDESCBC(final String src, final String key) throws Exception {
// --生成key,同时制定是des还是DESede,两者的key长度要求不同
final DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
final SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
// --加密向量
final IvParameterSpec iv = new IvParameterSpec(IV.getBytes("UTF-8"));
// --通过Chipher执行加密得到的是一个byte的数组,Cipher.getInstance("DES")就是采用ECB模式,cipher.init(Cipher.ENCRYPT_MODE,
// secretKey)就可以了.
final Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
final byte[] b = cipher.doFinal(src.getBytes("UTF-8"));
// --通过base64,将加密数组转换成字符串
final BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(b);
}
/**
* DESCBC解密
*
* @param src
* 数据源
* @param key
* 密钥,长度必须是8的倍数
* @return 返回解密后的原始数据
* @throws Exception
*/
public String decryptDESCBC(final String src, final String key) throws Exception {
// --通过base64,将字符串转成byte数组
final BASE64Decoder decoder = new BASE64Decoder();
final byte[] bytesrc = decoder.decodeBuffer(src);
// --解密的key
final DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
final SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
// --向量
final IvParameterSpec iv = new IvParameterSpec(IV.getBytes("UTF-8"));
// --Chipher对象解密Cipher.getInstance("DES")就是采用ECB模式,cipher.init(Cipher.DECRYPT_MODE,
// secretKey)就可以了.
final Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
final byte[] retByte = cipher.doFinal(bytesrc);
return new String(retByte);
}
// 3DESECB加密,key必须是长度大于等于 3*8 = 24 位哈
public String encryptThreeDESECB(final String src, final String key) throws Exception {
final DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));
final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
final SecretKey securekey = keyFactory.generateSecret(dks);
final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, securekey);
final byte[] b = cipher.doFinal(src.getBytes());
final BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(b).replaceAll("\r", "").replaceAll("\n", "");
}
// 3DESECB解密,key必须是长度大于等于 3*8 = 24 位哈
public String decryptThreeDESECB(final String src, final String key) throws Exception {
// --通过base64,将字符串转成byte数组
final BASE64Decoder decoder = new BASE64Decoder();
final byte[] bytesrc = decoder.decodeBuffer(src);
// --解密的key
final DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));
final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
final SecretKey securekey = keyFactory.generateSecret(dks);
// --Chipher对象解密
final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, securekey);
final byte[] retByte = cipher.doFinal(bytesrc);
return new String(retByte);
}
}
为UserController.class添加更新密码的接口:
@ApiOperation("根据用户名为密码加密")
@RequestMapping(value = "/encrypt/{username}", method = RequestMethod.GET)
@ResponseBody
public Object updatePasswordWithEncryption(@PathVariable String username) throws Exception {
ThreeDES threeDES = new ThreeDES();
User user = userService.getUserInfoByName(username);
String password = user.getPassword();
// 密码加密
password = threeDES.encryptThreeDESECB(URLEncoder.encode(password, "UTF-8"), key);
int i = userService.updatePasswordWithEncryption(username, password);
return i == 1? "加密成功":"加密失败";
}
接下来,可以通过http://localhost:8080/user/encrypt/{需要加密的用户名},进行加密,加密完可以在数据库中看到加密后的密码,也可以通过接口查询出用户的信息看到加密后的密码。
如果你只是想用3DES加密,不要整合shiro框架的话,那你可以直接使用以下代码进行加密解密。
//唯一密钥,即key
final String key = "cf410f84904a44cc8a7f48fc4134e8f9";
ThreeDES threeDES = new ThreeDES();
//加密
String str_encrypt = threeDES.encryptThreeDESECB(URLEncoder.encode(str, "UTF-8"), key);
//解密
String str_dencrypt = threeDES.decryptThreeDESECB(str, key);
上面已经为数据库中的密码进行加密了,那么我们在UserRealm类的AuthenticationInfo()方法中,执行密码验证那里,需要先给密码进行解密再验证。
//判断密码
try {
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user, threeDES.decryptThreeDESECB(user.getPassword(), key), "");
return simpleAuthenticationInfo;
} catch (Exception e) {
e.printStackTrace();
return null;
}
到这里,我们整合3DES加密就完成了。下一篇我们进行基于redis的cache缓存管理和session会话管理整合。
如果有什么需要改进的,还请多加指教。