function hmac_md5($data, $key = '') { // Creates a HMAC digest that can be used for auth purposes // See RFCs 2104, 2617, 2831 // Uses mhash() extension if available if (extension_loaded('mhash')) { if ($key == '') { $mhash = mhash(MHASH_MD5, $data); } else { $mhash = mhash(MHASH_MD5, $data, $key); } return $mhash; } if (!$key) { return pack('H*', md5($data)); } $key = str_pad($key, 64, chr(0x0)); if (strlen($key) > 64) { $key = pack("H*", md5($key)); } $k_ipad = $key ^ str_repeat(chr(0x36), 64); $k_opad = $key ^ str_repeat(chr(0x5c), 64); /* Heh, let's get recursive. */ $hmac = hmac_md5($k_opad . pack("H*", md5($k_ipad . $data))); return $hmac; }
/** * Creates a HMAC digest that can be used for auth purposes * See RFCs 2104, 2617, 2831 * Uses mhash() extension if available * * @param string $data Data to apply hash function to. * @param string $key Optional key, which, if supplied, will be used to * calculate data's HMAC. * @return string HMAC Digest string */ function hmac_md5($data, $key = '') { if (extension_loaded('mhash')) { if ($key == '') { $mhash = mhash(MHASH_MD5, $data); } else { $mhash = mhash(MHASH_MD5, $data, $key); } return $mhash; } if (!$key) { return pack('H*', md5($data)); } $key = str_pad($key, 64, chr(0x0)); if (strlen($key) > 64) { $key = pack("H*", md5($key)); } $k_ipad = $key ^ str_repeat(chr(0x36), 64); $k_opad = $key ^ str_repeat(chr(0x5c), 64); /* Heh, let's get recursive. */ $hmac = hmac_md5($k_opad . pack("H*", md5($k_ipad . $data))); return $hmac; }
/** * Perform SASL authentication to SIEVE server. * * Attempts to authenticate to SIEVE, using some SASL authentication method * such as PLAIN or DIGEST-MD5. * */ function authenticate() { switch ($this->auth_in_use) { case "PLAIN": $auth = base64_encode($this->auth . "" . $this->user . "" . $this->pass); $this->len = strlen($auth); $this->__fputs('AUTHENTICATE "PLAIN" {' . $this->len . '+}'); $this->__fputs($auth); $this->line = $this->__fgets(1024); while (sieve::status($this->line) == F_DATA) { $this->line = $this->__fgets(1024); } if (sieve::status($this->line) == F_NO) { return false; } $this->loggedin = true; return true; break; case "DIGEST-MD5": // SASL DIGEST-MD5 support works with timsieved 1.1.0 // follows rfc2831 for generating the $response to $challenge $this->__fputs('AUTHENTICATE "DIGEST-MD5"'); // $clen is length of server challenge, we ignore it. $clen = $this->__fgets(1024); // read for 2048, rfc2831 max length allowed $challenge = $this->__fgets(2048); // vars used when building $response_value and $response $cnonce = base64_encode(bin2hex(hmac_md5(microtime()))); $ncount = "00000001"; $qop_value = "auth"; $digest_uri_value = "sieve/{$this->host}"; // decode the challenge string $result = decode_challenge($challenge); // verify server supports qop=auth $qop = explode(",", $result['qop']); if (!in_array($qop_value, $qop)) { // rfc2831: client MUST fail if no qop methods supported return false; } // build the $response_value $string_a1 = utf8_encode($this->user) . ":"; $string_a1 .= utf8_encode($result['realm']) . ":"; $string_a1 .= utf8_encode($this->pass); $string_a1 = hmac_md5($string_a1); $A1 = $string_a1 . ":" . $result['nonce'] . ":" . $cnonce . ":" . utf8_encode($this->auth); $A1 = bin2hex(hmac_md5($A1)); $A2 = bin2hex(hmac_md5("AUTHENTICATE:{$digest_uri_value}")); $string_response = $result['nonce'] . ":" . $ncount . ":" . $cnonce . ":" . $qop_value; $response_value = bin2hex(hmac_md5($A1 . ":" . $string_response . ":" . $A2)); // build the challenge $response $reply = "charset=utf-8,username=\"" . $this->user . "\",realm=\"" . $result['realm'] . "\","; $reply .= "nonce=\"" . $result['nonce'] . "\",nc={$ncount},cnonce=\"{$cnonce}\","; $reply .= "digest-uri=\"{$digest_uri_value}\",response={$response_value},"; $reply .= "qop={$qop_value},authzid=\"" . utf8_encode($this->auth) . "\""; $response = base64_encode($reply); $this->__fputs('"' . $response . '"'); $this->line = $this->__fgets(1024); while (sieve::status($this->line) == F_DATA) { $this->line = $this->__fgets(1024); } if (sieve::status($this->line) == F_NO) { return false; } $this->loggedin = TRUE; return TRUE; break; case "CRAM-MD5": // SASL CRAM-MD5 support works with timsieved 1.1.0 // follows rfc2195 for generating the $response to $challenge // CRAM-MD5 does not support proxy of $auth by $user // requires php mhash extension $this->__fputs('AUTHENTICATE "CRAM-MD5"'); // $clen is the length of the challenge line the server gives us $clen = $this->__fgets(1024); // read for 1024, should be long enough? $challenge = $this->__fgets(1024); // build a response to the challenge $hash = bin2hex(hmac_md5(base64_decode($challenge), $this->pass)); $response = base64_encode($this->user . " " . $hash); // respond to the challenge string $this->__fputs('"' . $response . '"'); $this->line = $this->__fgets(1024); while (sieve::status($this->line) == F_DATA) { $this->line = $this->__fgets(1024); } if (sieve::status($this->line) == F_NO) { return false; } $this->loggedin = TRUE; return TRUE; break; case "LOGIN": $login = base64_encode($this->user); $pass = base64_encode($this->pass); $this->__fputs('AUTHENTICATE "LOGIN"'); $this->__fputs('{' . strlen($login) . '+}'); $this->__fputs($login); $this->__fputs('{' . strlen($pass) . '+}'); $this->__fputs($pass); $this->line = $this->__fgets(1024); while (sieve::status($this->line) == F_HEAD || sieve::status($this->line) == F_DATA) { $this->line = $this->__fgets(1024); } if (sieve::status($this->line) == F_NO) { return false; } $this->loggedin = true; return true; break; default: return false; break; } //end switch }
admShowError("Invalid username/password", "Check your username and password and try again.", $adm_pageerr_title); exit; } } else { /* * Group administration is not enabled, terminate */ admShowError("Invalid username/password", "Check your username and password and try again.", $adm_pageerr_title); exit; } } else { /* * The username entered matches the "root" password * Check to see if the hashes match for the password */ if (hmac_md5($_POST["id"], md5($admin_pass)) != $_POST["passmd5"]) { admShowError("Invalid username/password", "Check your username and password and try again.", $adm_pageerr_title); exit; } /* * Okay the root password matches, now set the permission variable */ $_SESSION["admin_perms"]["root"] = true; } } else { admShowError("There was a problem processing your request", "It appears you are trying to steal a session. Shame on you!", $adm_pageerr_title); } } /* * Wow. All the tests pass. There should be a variable set in _SESSION now to verify * that the login was successful. Also, we can now redirect to the "main" administration panel.
<?php // refs-1: http://en.wikipedia.org/wiki/HMAC // refs-2: http://www.ietf.org/rfc/rfc2104.txt function hmac_md5($data, $key) { $b = 64; // 每个分组中的字节数, md5是64 if (strlen($key) > $b) { $key = pack("H*", hash('md5', $key)); } $key = str_pad($key, $b, chr(0x0)); $ipad = str_pad('', $b, chr(0x36)); $opad = str_pad('', $b, chr(0x5c)); $k_ipad = $key ^ $ipad; $k_opad = $key ^ $opad; return hash('md5', $k_opad . pack("H*", hash('md5', $k_ipad . $data))); } $a = hmac_md5('applied cryptology', 'hello'); $b = hash_hmac('md5', 'applied cryptology', 'hello'); // http://cn2.php.net/manual/zh/function.hash-hmac.php if ($a === $b) { echo "we did HMAC-MD5 right\n"; } else { echo 'oops ...'; }
// Xor key with opad & ipad for ($i = 0; $i < strlen($key); $i++) { $opad[$i] = $opad[$i] ^ $key[$i]; $ipad[$i] = $ipad[$i] ^ $key[$i]; } return sha1($opad . sha1($ipad . $data, true)); } function hmac_md5($key, $data) { // Adjust key to exactly 64 bytes if (strlen($key) > 64) { $key = str_pad(sha1($key, true), 64, chr(0)); } if (strlen($key) < 64) { $key = str_pad($key, 64, chr(0)); } // Outter and Inner pad $opad = str_repeat(chr(0x5c), 64); $ipad = str_repeat(chr(0x36), 64); // Xor key with opad & ipad for ($i = 0; $i < strlen($key); $i++) { $opad[$i] = $opad[$i] ^ $key[$i]; $ipad[$i] = $ipad[$i] ^ $key[$i]; } print "md5 of ipad.data: " . md5($ipad . $data) . "\n"; print "md5 of full hash: " . md5($opad . md5($ipad . $data, true)) . "\n"; print "md5 of just opad: " . md5($opad) . "\n"; return md5($opad . md5($ipad . $data, true)); } hmac_md5("key", "The quick brown fox jumps over the lazy dog");
/** * Creates a HMAC digest that can be used for authentication purposes * See RFCs 2104, 2617, 2831 * * Uses PHP's Hash extension if available (enabled by default in PHP * 5.1.2+ - see http://www.php.net/manual/en/hash.requirements.php * or, if installed on earlier PHP versions, the PECL hash module - * see http://pecl.php.net/package/hash * * Otherwise, will attempt to use the Mhash extension - see * http://www.php.net/manual/en/mhash.requirements.php * * Finally, a fall-back custom implementation is used if none of * the above are available. * * @param string $data The data to be encoded/hashed * @param string $key The (shared) secret key that will be used * to build the keyed hash. This argument is * technically optional, but only for internal * use (when the custom hash implementation is * being used) - external callers should always * specify a value for this argument. * * @return string The HMAC-MD5 digest string * @since 1.4.0 * */ function hmac_md5($data, $key = '') { // use PHP's native Hash extension if possible // if (function_exists('hash_hmac')) { return pack('H*', hash_hmac('md5', $data, $key)); } // otherwise, use (obsolete) mhash extension if available // if (extension_loaded('mhash')) { if ($key == '') { $mhash = mhash(MHASH_MD5, $data); } else { $mhash = mhash(MHASH_MD5, $data, $key); } return $mhash; } // or, our own implementation... // if (!$key) { return pack('H*', md5($data)); } $key = str_pad($key, 64, chr(0x0)); if (strlen($key) > 64) { $key = pack("H*", md5($key)); } $k_ipad = $key ^ str_repeat(chr(0x36), 64); $k_opad = $key ^ str_repeat(chr(0x5c), 64); $hmac = hmac_md5($k_opad . pack('H*', md5($k_ipad . $data))); return $hmac; }