照着JeeSite代码搬出来的。
需要了解的知识 Hex编码 散列算法
用户 注册/修改 密码的时候根据输入的密码生成一段加密串,每次验证密码时候根据算法进行密文比对,想要通过密文解出明文密码需要花费大量时间。
<1> 加密
1. 生成一段salt,值随机,长度自定义。 // 个人理解就是捣乱的,因为是随机的
2. 将 明文密码 + salt 进行散列N次。 // N自定义,哈希算法自定义。
3. 将 1 2 分别Hex编码,并且相加的密文密码。
<2> 解密
1. 截取密文密码前 xx 位数,进行Hex解码取得salt。
2. 将 用户输入的明文密码 + salt 进行散列N次。
3. 将 1 2 分别Hex编码 相加,最后与密文密码对比。
因为salt是随机生成的,如果想要破解需要针对每条密文数据进行破解。
根据哈希算法的不同于计算次数不同增加了破解的难度。
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.Validate;
public class Security {
public static final int SALT_SIZE = 8;
private static final String SHA1 = "SHA-1";
private static SecureRandom random = new SecureRandom();
public static final int HASH_INTERATIONS = 1024;
/**
* 传入明文密码,生成密文密码
*/
public static String entryptPassword(String plainPassword) {
String plain = unescapeHtml(plainPassword);
byte[] salt = generateSalt(SALT_SIZE);
byte[] hashPassword = sha1(plain.getBytes(), salt, HASH_INTERATIONS);
return encodeHex(salt) + encodeHex(hashPassword);
}
/**
* 对比
* @param plainPassword(明文密码)
* 与
* @param encryptedPassword(密文密码)
*/
public static boolean comparePassword(String plainPassword,
String encryptedPassword) {
byte[] salt = decodeHex(encryptedPassword.substring(0, 16));
String plain = unescapeHtml(plainPassword);
byte[] hashPassword = sha1(plain.getBytes(), salt, HASH_INTERATIONS);
if (encodeHex(hashPassword).equals(encryptedPassword.substring(16))) {
return true;
}
return false;
}
/**
* @param args
*/
public static void main(String[] args) {
String plainPassword = "123456";
String encryptedPassword = "ac2246ecf3b6ef595da8b0d0210a6239adbf7a93cf73f799dbadb744";
// System.out.println(entryptPassword("123456"));
System.out.println(comparePassword(plainPassword, encryptedPassword));
}
/**
* Html 解码.
*/
private static String unescapeHtml(String htmlEscaped) {
return StringEscapeUtils.unescapeHtml4(htmlEscaped);
}
/**
* 生成随机的Byte[]作为salt.
*
* @param numBytes
* byte数组的大小
*/
private static byte[] generateSalt(int numBytes) {
Validate.isTrue(numBytes > 0,
"numBytes argument must be a positive integer (1 or larger)",
numBytes);
byte[] bytes = new byte[numBytes];
random.nextBytes(bytes);
return bytes;
}
private static byte[] sha1(byte[] input, byte[] salt, int iterations) {
return digest(input, SHA1, salt, iterations);
}
/**
* 对字符串进行散列, 支持md5与sha1算法.
*/
private static byte[] digest(byte[] input, String algorithm, byte[] salt,
int iterations) {
try {
MessageDigest digest = MessageDigest.getInstance(algorithm);
if (salt != null) {
digest.update(salt);
}
byte[] result = digest.digest(input);
for (int i = 1; i < iterations; i++) {
digest.reset();
result = digest.digest(result);
}
return result;
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
}
/**
* Hex编码.
*/
private static String encodeHex(byte[] input) {
return new String(Hex.encodeHex(input));
}
/**
* Hex解码.
*/
private static byte[] decodeHex(String input) {
try {
return Hex.decodeHex(input.toCharArray());
} catch (DecoderException e) {
throw new RuntimeException(e);
}
}
}