1 packagecom.hjp.exercise.md5test;2
3 importjava.io.UnsupportedEncodingException;4 importjava.security.MessageDigest;5 importjava.security.NoSuchAlgorithmException;6 importjava.security.SecureRandom;7 importjava.util.Arrays;8
9 public classMd5SaltTool {10
11 private static final String HEX_NUMS_STR="0123456789ABCDEF";12 private static final Integer SALT_LENGTH = 12;13
14 /**
15 * 将16进制字符串转换成字节数组16 *@paramhex17 *@return
18 */
19 public static byte[] hexStringToByte(String hex) {20 int len = (hex.length() / 2);21 byte[] result = new byte[len];22 char[] hexChars =hex.toCharArray();23 for (int i = 0; i < len; i++) {24 int pos = i * 2;25 result[i] = (byte) (HEX_NUMS_STR.indexOf(hexChars[pos]) << 4
26 | HEX_NUMS_STR.indexOf(hexChars[pos + 1]));27 }28 returnresult;29 }30
31 /**
32 * 将指定byte数组转换成16进制字符串33 *@paramb34 *@return
35 */
36 public static String byteToHexString(byte[] b) {37 StringBuffer hexString = newStringBuffer();38 for (int i = 0; i < b.length; i++) {39 String hex = Integer.toHexString(b[i] & 0xFF);40 if (hex.length() == 1) {41 hex = '0' +hex;42 }43 hexString.append(hex.toUpperCase());44 }45 returnhexString.toString();46 }47
48 /**
49 * 验证口令是否合法50 *@parampassword51 *@parampasswordInDb52 *@return
53 *@throwsNoSuchAlgorithmException54 *@throwsUnsupportedEncodingException55 */
56 public static booleanvalidPassword(String password, String passwordInDb)57 throwsNoSuchAlgorithmException, UnsupportedEncodingException {58 //将16进制字符串格式口令转换成字节数组
59 byte[] pwdInDb =hexStringToByte(passwordInDb);60 //声明盐变量
61 byte[] salt = new byte[SALT_LENGTH];62 //将盐从数据库中保存的口令字节数组中提取出来
63 System.arraycopy(pwdInDb, 0, salt, 0, SALT_LENGTH);64 //创建消息摘要对象
65 MessageDigest md = MessageDigest.getInstance("MD5");66 //将盐数据传入消息摘要对象
67 md.update(salt);68 //将口令的数据传给消息摘要对象
69 md.update(password.getBytes("UTF-8"));70 //生成输入口令的消息摘要
71 byte[] digest =md.digest();72 //声明一个保存数据库中口令消息摘要的变量
73 byte[] digestInDb = new byte[pwdInDb.length -SALT_LENGTH];74 //取得数据库中口令的消息摘要
75 System.arraycopy(pwdInDb, SALT_LENGTH, digestInDb, 0, digestInDb.length);76 //比较根据输入口令生成的消息摘要和数据库中消息摘要是否相同
77 if(Arrays.equals(digest, digestInDb)) {78 //口令正确返回口令匹配消息
79 return true;80 } else{81 //口令不正确返回口令不匹配消息
82 return false;83 }84 }85
86 /**
87 * 获得加密后的16进制形式口令88 *@parampassword89 *@return
90 *@throwsNoSuchAlgorithmException91 *@throwsUnsupportedEncodingException92 */
93 public staticString getEncryptedPwd(String password)94 throwsNoSuchAlgorithmException, UnsupportedEncodingException {95 //声明加密后的口令数组变量
96 byte[] pwd = null;97 //随机数生成器
98 SecureRandom random = newSecureRandom();99 //声明盐数组变量 12
100 byte[] salt = new byte[SALT_LENGTH];101 //将随机数放入盐变量中
102 random.nextBytes(salt);103
104 //声明消息摘要对象
105 MessageDigest md = null;106 //创建消息摘要
107 md = MessageDigest.getInstance("MD5");108 //将盐数据传入消息摘要对象
109 md.update(salt);110 //将口令的数据传给消息摘要对象
111 md.update(password.getBytes("UTF-8"));112 //获得消息摘要的字节数组
113 byte[] digest =md.digest();114
115 //因为要在口令的字节数组中存放盐,所以加上盐的字节长度
116 pwd = new byte[digest.length +SALT_LENGTH];117 //将盐的字节拷贝到生成的加密口令字节数组的前12个字节,以便在验证口令时取出盐
118 System.arraycopy(salt, 0, pwd, 0, SALT_LENGTH);119 //将消息摘要拷贝到加密口令字节数组从第13个字节开始的字节
120 System.arraycopy(digest, 0, pwd, SALT_LENGTH, digest.length);121 for(int i=0;i
125 returnbyteToHexString(pwd);126 }127 }