PostgreSQL MD5 加密验证算法分析

    因为QDAC 3.0里,PostgreSQL不打算继续带一大堆动态链接库,所以驱动打算直接写。开源的好处就是可以拿到源码来分析,然后写出自己的实现。

    我们首先来看PostgreSQL的登录过程(非SSL方式):

    1、发送初始化数据包,告诉服务器我们是谁,要连那个数据库及一些额外的参数。

    2、如果没有问题,服务回送一个数据包,告诉客户端,我接受你那些密码验证方式及初始参数。

    3、客户端根据返回的值,然后需要的密码发送给服务器端。

    4、服务器端返回密码验证结果,如果成功,服务器返回登录成功和服务器相关的设置,登录也就完成了,接下来该干啥干啥。如果失败,就返回具体的错误信息。很详细,实际上给用户提示时反而用不到那么多,TQPgSQLProvider会根据这些错误信息设置LastError和LastErrorMsg的内容。由于PostgreSQL的错误代码是xxPyy的样子,所以错误代码高16位存贮了xx的值,低16位存贮了yy的值,这个简单的说明。

    今晚主要是调试了第3步,发送密码给服务器。服务器我设置的使用MD5加密,因此,服务器请求使用MD5加密,通过分析它的代码,发现PostgreSQL的实现逻辑如下:

    1、首先,要求MD5加密时,服务器端会在第2步返回4个字节的随机值,以便使生成的MD5摘要进一步随机化。

    2、客户端程序首先将密码和用户名拼在一起,然后计算出一个MD5哈希值,如密码为password,用户名为postgres,则拼成的串为passwordpostgres,然后计算这个串的MD5哈希值。

    3、将生成的哈希值转换为16进制小写表示形式,32字节,然后再追加前面服务器返回的4个字节的随机值,构成36字节的数据,然后计算这36字节数据的MD5哈希值,这个哈希值就是要传给服务器验证的加密后的密码。而就在这一步我被自己坑苦了,由于前期写的QDigest中,MD5Init初始化清零时,传递的长度参数错误,造成实际上没有清零,结果是怎么折腾服务器端都报告认证失败。

    4、发送给服务器的数据包实际上包含了一个小写字母p代表消息是密码,然后是网络字节顺序的40代表包含自身的后续内容长度,然后是字符串md5,最后是第3步生成的md5哈希值的十六进制小写表示。实际数据包截图如下:

分享到: