0x00 mysql密码的保存
mysql 4.1之后的版本中,密码采用password()函数哈希后保存。
具体保存在mysql数据库user表的authentication_string字段中。
相应文件为/mysqld/mysql-5.7/data/mysql/user.MYD。
0x01 password函数的实现原理
采用"*".sha1(sha1(xxx))的原理实现
0x02 password(xxx)为啥跟sha1(sha1(xxx))不同
因为通用的sha1(xxx)会内置的把字符串转为16进制表示,而password采用的是第一次sha1结果中的字符串。
因此,在mysql中password(xxx)=sha1(unhex(sha1(xxx)))
java代码模拟mysql的password函数
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Test {
private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
private static String getFormattedText(byte[] bytes) {
int len = bytes.length;
StringBuilder buf = new StringBuilder(len * 2);
// 把密文转换成十六进制的字符串形式
for (int j = 0; j < len; j++) {
buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
}
return buf.toString();
}
/**
* @param args
*/
public static void main(String[] args) {
System.out.println("hello world");
String str = "123456";
MessageDigest messageDigest;
try {
messageDigest = MessageDigest.getInstance("SHA1");
messageDigest.update(str.getBytes());
byte[] b_itr1 = messageDigest.digest();
String s_itr1 = getFormattedText(b_itr1);
System.out.println("itr1:"+s_itr1);
//messageDigest.update(s_itr1.getBytes());
messageDigest.update(b_itr1);
String itr2 = getFormattedText(messageDigest.digest());
System.out.println("itr2:"+itr2);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
}
}
}
0x03 采用linux shell计算sha1中的坑
正确的写法如下:
echo -n 'xxx' | sha1sum
注意:添加"-n"参数,不打印换行;采用单引号,xxx中可以包括特殊字符,如"!"
0x04 参考链接
https://blog.pythian.com/hashing-algorithm-in-mysql-password-2/
https://blog.csdn.net/guotianlaile/article/details/51423443
https://dev.mysql.com/doc/dev/mysql-server/8.0.16/page_protocol_connection_phase_authentication_methods_native_password_authentication.html
https://dev.mysql.com/doc/refman/5.7/en/password-hashing.html