/** * APR compatible MD5 encryption * * @access public * @return mixed * @param string $plain plaintext to crypt * @param string $salt the salt to use for encryption */ function crypt_apr_md5($plain, $salt = null) { if (is_null($salt)) { $salt = File_Passwd::salt(8); } elseif (preg_match('/^\\$apr1\\$/', $salt)) { $salt = preg_replace('/^\\$apr1\\$([^$]+)\\$.*/', '\\1', $salt); } else { $salt = substr($salt, 0, 8); } $length = strlen($plain); $context = $plain . '$apr1$' . $salt; if (PEAR_ZE2) { $binary = md5($plain . $salt . $plain, true); } else { $binary = pack('H32', md5($plain . $salt . $plain)); } for ($i = $length; $i > 0; $i -= 16) { $context .= substr($binary, 0, min(16, $i)); } for ($i = $length; $i > 0; $i >>= 1) { $context .= $i & 1 ? chr(0) : $plain[0]; } if (PEAR_ZE2) { $binary = md5($plain . $salt . $plain, true); } else { $binary = pack('H32', md5($plain . $salt . $plain)); } for ($i = 0; $i < 1000; $i++) { $new = $i & 1 ? $plain : $binary; if ($i % 3) { $new .= $salt; } if ($i % 7) { $new .= $plain; } $new .= $i & 1 ? $binary : $plain; $binary = PEAR_ZE2 ? md5($new, true) : pack('H32', md5($new)); } $p = array(); for ($i = 0; $i < 5; $i++) { $k = $i + 6; $j = $i + 12; if ($j == 16) { $j = 5; } $p[] = File_Passwd::_64(ord($binary[$i]) << 16 | ord($binary[$k]) << 8 | ord($binary[$j]), 5); } return '$apr1$' . $salt . '$' . implode($p) . File_Passwd::_64(ord($binary[11]), 3); }
/** * Regression test for File_Passwd.salt method * @access public */ function testsalt() { $this->assertEquals(strlen(File_Passwd::salt()), strlen(File_Passwd::salt(2))); $regex = '/^[' . preg_quote($GLOBALS['_FILE_PASSWD_64'], '/') . ']+$/'; $this->assertTrue(preg_match($regex, File_Passwd::salt(20))); }