我有一些使用PHP函数crypt()
加密的字符串.
输出看起来像这样:
$1$Vf/.4.1.$CgCo33ebiHVuFhpwS.kMI0 $1$84..vD4.$Ps1PdaLWRoaiWDKCfjLyV1 $1$or1.RY4.$v3xo04v1yfB7JxDj1sC/J/
虽然我相信crypt()正在使用MD5算法,但输出不是有效的MD5哈希值.
有没有办法将生成的哈希值转换为有效的MD5哈希值(16字节十六进制值)?
更新:
感谢回复到目前为止的答案.我很确定使用的crypt函数是使用某种MD5算法.我要做的是将我拥有的输出转换为MD5哈希,如下所示:
9e107d9d372bb6826bd81d3542a419d6 e4d909c290d0fb1ca068ffaddf22cbd0 d41d8cd98f00b204e9800998ecf8427e
(取自维基百科)
有没有办法从我有的哈希转换成上面的哈希?
好吧,也许这个答案迟了一年,但我会试一试.在你自己的回答中,你注意到crypt()
正在使用FreeBSD MD5,它在运行哈希之前也对salt做了一些有趣的转换,所以我要给你的结果永远不会与a的结果完全匹配.打电话给md5()
.也就是说,您看到的输出与您习惯使用的格式之间的唯一区别是您看到的输出编码如下
$1$ # this indicates that it is MD5 Vf/.4.1. # these eight characters are the significant portion of the salt $ # this character is technically part of the salt, but it is ignored CgCo33eb # the last 22 characters are the actual hash iHVuFhpw # they are base64 encoded (to be printable) using crypt's alphabet S.kMI0 # floor(22 * 6 / 8) = 16 (the length in bytes of a raw MD5 hash)
据我所知,crypt使用的字母表如下所示:
./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
因此,考虑到所有这些,下面是如何将22个字符的crypt-base64哈希转换为32个字符的base16(十六进制)哈希:
首先,您需要将base64(使用自定义字母)转换为原始的16字节MD5哈希.
define('CRYPT_ALPHA','./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'); /** * Decodes a base64 string based on the alphabet set in constant CRYPT_ALPHA * Uses string functions rather than binary transformations, because said * transformations aren't really much faster in PHP * @params string $str The string to decode * @return string The raw output, which may include unprintable characters */ function base64_decode_ex($str) { // set up the array to feed numerical data using characters as keys $alpha = array_flip(str_split(CRYPT_ALPHA)); // split the input into single-character (6 bit) chunks $bitArray = str_split($str); $decodedStr = ''; foreach ($bitArray as &$bits) { if ($bits == '$') { // $ indicates the end of the string, to stop processing here break; } if (!isset($alpha[$bits])) { // if we encounter a character not in the alphabet return false; // then break execution, the string is invalid } // decbin will only return significant digits, so use sprintf to pad to 6 bits $decodedStr .= sprintf('%06s', decbin($alpha[$bits])); } // there can be up to 6 unused bits at the end of a string, so discard them $decodedStr = substr($decodedStr, 0, strlen($decodedStr) - (strlen($decodedStr) % 8)); $byteArray = str_split($decodedStr, 8); foreach ($byteArray as &$byte) { $byte = chr(bindec($byte)); } return join($byteArray); }
现在您已经获得了原始数据,您需要一种方法将其转换为您期望的base-16格式,这可能会更容易.
/** * Takes an input in base 256 and encodes it to base 16 using the Hex alphabet * This function will not be commented. For more info: * @see http://php.net/str-split * @see http://php.net/sprintf * * @param string $str The value to convert * @return string The base 16 rendering */ function base16_encode($str) { $byteArray = str_split($str); foreach ($byteArray as &$byte) { $byte = sprintf('%02x', ord($byte)); } return join($byteArray); }
最后,由于crypt的输出包含了大量的数据,我们不需要(事实上,不能使用)这个过程,一个短而甜的功能,不仅将这两个结合在一起,而且允许直接输入输出来自地穴
/** * Takes a 22 byte crypt-base-64 hash and converts it to base 16 * If the input is longer than 22 chars (e.g., the entire output of crypt()), * then this function will strip all but the last 22. Fails if under 22 chars * * @param string $hash The hash to convert * @param string The equivalent base16 hash (therefore a number) */ function md5_b64tob16($hash) { if (strlen($hash) < 22) { return false; } if (strlen($hash) > 22) { $hash = substr($hash,-22); } return base16_encode(base64_decode_ex($hash)); }
给定这些函数,您的三个示例的base16表示形式为:
3ac3b4145aa7b9387a46dd7c780c1850 6f80dba665e27749ae88f58eaef5fe84 ec5f74086ec3fab34957d3ef0f838154
当然,重要的是要记住它们总是有效的,只是格式不同.