您可以将 php crypt() 的输出转换为有效的 MD5 吗?
我有一些字符串已经使用 PHP 函数 crypt()
.
I have some strings that have been encrypted using the PHP function crypt()
.
输出如下所示:
$1$Vf/.4.1.$CgCo33ebiHVuFhpwS.kMI0
$1$84..vD4.$Ps1PdaLWRoaiWDKCfjLyV1
$1$or1.RY4.$v3xo04v1yfB7JxDj1sC/J/
虽然我认为 crypt() 使用的是 MD5 算法,但输出不是有效的 MD5 哈希.
While I believe crypt() is using the MD5 algorithm, the outputs are not valid MD5 hashes.
有没有办法将生成的哈希转换为有效的 MD5 哈希(16 字节十六进制值)?
Is there a way of converting the produced hashes into valid MD5 hashes (16-byte hex values)?
更新:
感谢您的回复,所以到目前为止的答案.我很确定使用的 crypt 函数正在使用某种 MD5 算法.我要做的是将我拥有的输出转换为类似于以下内容的 MD5 哈希:
Thanks for the replies so answers so far. I'm pretty sure the crypt function used is using some sort of MD5 algorithm. What I'm looking to do is convert the ouput that I have into an MD5 hash that looks something like the following:
9e107d9d372bb6826bd81d3542a419d6
e4d909c290d0fb1ca068ffaddf22cbd0
d41d8cd98f00b204e9800998ecf8427e
(取自 维基百科)
有没有一种方法可以将我拥有的哈希值转换为上述哈希值?
Is there a way of converting from the hashes I have to ones like the above?
推荐答案
好的,所以这个答案可能晚了一年,但我会试一试.在您自己的回答中,您注意到 crypt()
正在使用 FreeBSD MD5,它还在运行哈希之前对 salt 进行了一些有趣的转换,所以我将要给您的结果永远不会与调用 md5()
的结果完全匹配.也就是说,您看到的输出与您习惯的格式之间的唯一区别是您看到的输出编码如下
OK, so maybe this answer is a year late, but I'll give it a shot. In your own answer, you note that crypt()
is using the FreeBSD MD5, which also does some interesting transformations on the salt before running the hash, so the result of what I'm about to give you will never quite match up with the results of a call to md5()
. That said, the only difference between the output you are seeing and the format you are used to is that the output you are seeing is encoded as follows
$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 使用的字母如下所示:
To my knowledge, the alphabet used by crypt looks like this:
./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
因此,考虑到所有这些,以下是如何将 22 个字符的 crypt-base64 哈希转换为 32 个字符的 base16(十六进制)哈希:
So, with all of this borne in mind, here is how you can convert the 22 character crypt-base64 hash into a 32 character base16 (hexadecimal) hash:
首先,您需要将 base64(带有自定义字母)转换为原始 16 字节 MD5 哈希.
First, you need something to convert the base64 (with custom alphabet) into a raw 16-byte MD5 hash.
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 格式,这再简单不过了.
Now that you've got the raw data, you'll need a method to convert it to the base-16 format you're expecting, which couldn't be easier.
/**
* 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 的输出包含很多我们在这个过程中不需要(实际上也不能使用)的数据,所以一个简短而实用的函数不仅可以将这两者联系在一起,而且还允许直接crypt 输出的输入.
Finally, since the output of crypt includes a lot of data we don't need (and, in fact, cannot use) for this process, a short and sweet function to not only tie these two together but to allow for direct input of output from 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 表示是:
Given these functions, the base16 representation of your three examples are:
3ac3b4145aa7b9387a46dd7c780c1850
6f80dba665e27749ae88f58eaef5fe84
ec5f74086ec3fab34957d3ef0f838154
当然,重要的是要记住它们始终有效,只是格式不同.
Of course, it is important to remember that they were always valid, just formatted differently.
相关文章