Hamc算法是一种基于密钥的消息认证码算法,可以看作一个带有安全key的MD5算法。Hamc总是和某一个算法搭配使用
优点:
- HmacMD5使用的可以长度为64字节,更安全
- Hmac是标准算法,同样适用于SHA-1等算法
- Hmac输出和原有的哈希算法长度一致
//Hamc算法
public class Demo1 {
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
String password = "wbjxxmy";
//获取HmacMD5密钥生成器
KeyGenerator keyGen = KeyGenerator.getInstance("HmacMD5");
//生成密钥
SecretKey key = keyGen.generateKey();
System.out.println("秘钥:"+Arrays.toString(key.getEncoded()));
System.out.println("密钥长度(64字节):"+key.getEncoded().length);
System.out.println("密钥:"+HashTools.bytesToHex(key.getEncoded()));
//使用密钥,进行加密
//使用Hmac加密算法对象
Mac mac = Mac.getInstance("HmacMD5");
mac.init(key);//初始化密钥
mac.update(password.getBytes());//更新原始加密内容
byte[] bytes = mac.doFinal();//加密处理,并获取加密结果
String ret = HashTools.bytesToHex(bytes);//加密结果处理成16进制字符串
System.out.println("加密结果16进制字符串:"+ret);
System.out.println("加密结果(字节长度)"+bytes.length);
System.out.println("加密结果(字符长度)"+ret.length());
}
}
其中HashTools.bytesToHex()是我们自定义的方法,主要用于将字节数组转换成16进制字符串
//Hash算法(消息摘要算法工具类)
public class HashTools {
//构造方法私有
private HashTools() {}
//将字节数组转换成16进制字符串
public static String bytesToHex(byte[] bytes) {
StringBuilder ret = new StringBuilder();
for(byte b : bytes) {
//将字节之转换成2位十进制字符串
ret.append(String.format("%02x", b));
}
return ret.toString();
}
}
秘钥只有在第一次使用时生成,并且每次生成不同,所以在数据库存储时,不只需要存储加密后的用户密码,还应存储秘钥,在用户进行登录时,将秘钥与密码一起进行加密,并与数据库中存储的密码进行比对,若一样,则密码正确
所以必须可以根据原始密码与存储的秘钥数组恢复秘钥
秘钥为字节数组
//根据字节数组,"恢复"秘钥
public class Demo2 {
public static void main(String[] args) {
//原始密码
String password = "wbjxxmy";
try {
//秘钥(字节数组)
byte[] keyBytes = {-125, -99, -8, 123, 92, -37, 44, -53, 71, -122, 58, 29, 52, 0, 125, -108, -66, -41, -34, 68, -52, 10, -24, -7, -25, 38, -76, -19, 91, 41, -20, -9, -96, -73, -124, 118, 99, 125, -49, 45, -12, 43, 0, 60, -9, 3, -14, -66, -80, -39, -109, 73, 115, -98, 39, -77, -87, 4, -31, -17, -73, 90, 30, -125};
//恢复秘钥(字节数组)
SecretKey key = new SecretKeySpec(keyBytes, "HmacMD5");
//创建Hmac加密算法对象
Mac mac = Mac.getInstance("HmacMD5");
mac.init(key);//初始化秘钥
mac.update(password.getBytes());
String ret = HashTools.bytesToHex(mac.doFinal());
System.out.println(ret);
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
秘钥为16进制字符串
//秘钥(字符串)
String keyStr = "ab645034baaae4705017b8cf57a8de57eda1a6d18ae6dd5acf275c52036efe9a44102c933e5f69f8fa8cebb566d6b07e4a4420892db81d1b927faf37fddff8d1";
//用于保存秘钥:秘钥长度为64字节
byte[] keyBytes = new byte[64];
for(int i = 0,k =0;i<keyStr.length();i+=2,k++) {
String s = keyStr.substring(i,i+2);
keyBytes[k] = (byte)Integer.parseInt(s,16);
}