extmail 密码加密方式修改为plain-md5的方法

extmail默认密码加密方式是md5crypt,但是有些时候会遇到这样的问题——老的邮件系统中的用户密码是md5加密的。

此时需要将extmail的密码加密方式修改为md5,通过官方解释(md5和md5crypt没有区别),修改为plain-md5即可。但是,这只解决了web登陆的验证问题,没有解决smtp以及pop3的验证问题。

通过 http://www.extmail.org/forum/viewthread.php?tid=3175 帖子解决了验证问题,内容摘录如下:

courier-authlibauth_generic手册里提到crypted密码的格式支持3类:

1)传统的crypted 的密码,如crypt()或md5-salted的密码
2){MD5}为前缀,后面是base64编码后的md5密码
3){SHA}为前缀(实际还支持{SAH256},这个看source知道)后面是base64编码的sha密码

如何能实现2呢?在目前的extmail/extman实现里,md5密码只支持以16进制形式存在的密码,例如:

d41d8cd98f00b204e9800998ecf8427e



经过base64编码后依然无法通过authlib的认证,后来仔细看Digest::MD5手册里的介绍,发现md5函数返回的是二进制的、产度为16个字节的密文,而md5_hex(也就是目前extmail/extman使用的)是其16进制的形式(长度32个字节)。

于是测试用md5函数产生md5密文并用base64编码后,加上{MD5}前缀,塞到mysql里,发现通过了authtest的测试!再查看了一下courier-authlib的checkpasswd.c及checkpasswdmd5.c和md5目录下的md5加密函数,证实了就是校验二进制+base64编码后的md5密文,而不是hex后的密文。

问题是如何从hex格式的密文转成binary格式?很多用户从其他系统转到ext*下时,密码大多是md5 hex格式的,于是编写如下代码实现转换:

use MIME::Base64;

my $s = 'd41d8cd98f00b204e9800998ecf8427e';

$s =~ s/(..)/bin($1)/ge;
$s = '{MD5}'.encode_base64($s);
$s =~ s/\s+//; # remove newline

print $s, "\n";

sub bin {
      my $n = shift;
      sprintf("%c", hex($n));
}



这样常规的md5密文就被转成符合要求的{MD5}XXXXX格式了。刚才这个脚本的执行结果:

{MD5}1B2M2Y8AsgTpgAmY7PhCfg==