/** * Retrieve response string * * @return string */ public function getString() { $cnonce = base64_encode(bin2hex(HMAC_MD5::hash(microtime()))); $ncount = sprintf('%08d', $this->ncount); $username_value = HMAC_MD5::hash(sprintf('%s:%s:%s', $this->_encode($this->user), $this->_encode($this->realm), $this->_encode($this->pass))); // If authzid is specified, then A1 is // // A1 = { H( { username-value, ":", realm-value, ":", passwd } ), // ":", nonce-value, ":", cnonce-value, ":", authzid-value } // // If authzid is not specified, then A1 is // // A1 = { H( { username-value, ":", realm-value, ":", passwd } ), // ":", nonce-value, ":", cnonce-value } // $a1 = sprintf('%s:%s:%s%s', $username_value, $this->nonce, $cnonce, $this->authzid ? ':' . $this->_encode($this->authzid) : ''); // If the "qop" directive's value is "auth", then A2 is: // // A2 = { "AUTHENTICATE:", digest-uri-value } // // If the "qop" value is "auth-int" or "auth-conf" then A2 is: // // A2 = { "AUTHENTICATE:", digest-uri-value, // ":00000000000000000000000000000000" } switch ($this->qop) { case 'auth': $a2 = 'AUTHENTICATE:' . $this->digestUri; break; case 'auth-int': case 'auth-conf': $a2 = 'AUTHENTICATE:' . $this->digestUri . ':00000000000000000000000000000000'; break; } // response-value = // // HEX( KD ( HEX(H(A1)), // { nonce-value, ":" nc-value, ":", // cnonce-value, ":", qop-value, ":", HEX(H(A2)) })) $response_value = bin2hex(HMAC_MD5::hash(sprintf('%s:%s:%s:%s:%s:%s', bin2hex(HMAC_MD5::hash($a1)), $this->nonce, $ncount, $cnonce, $this->qop, bin2hex(HMAC_MD5::hash($a2))))); return sprintf('%susername="******",realm="%s",nonce="%s",nc=%s,' . 'cnonce="%s",digest-uri="%s",response=%s,qop=%s%s', $this->charset ? 'charset=' . $this->charset . ',' : '', $this->_encode($this->user), $this->_encode($this->realm), $this->nonce, $ncount, $cnonce, $this->digestUri, $response_value, $this->qop, $this->authzid ? ',authzid="' . $this->_encode($this->authzid) . '"' : ''); }
/** * Authenticate * * Supported methods: * <ul> * <li>PLAIN</li> * <li>LOGIN</li> * <li>DIGEST-MD5</li> * <li>CRAM-MD5</li> * </ul> * * @param string method one of the SIEVE_SASL_* constants * @param string user * @param string pass * @param string auth default NULL * @return bool success * @throws lang.IllegalArgumentException when the specified method is not supported */ public function authenticate($method, $user, $pass, $auth = NULL) { if (!$this->hasAuthenticationMethod($method)) { throw new IllegalArgumentException('Authentication method ' . $method . ' not supported'); } // Check whether we want to impersonate if (NULL === $auth) { $auth = $user; } // Send auth request depending on specified authentication method switch ($method) { case SIEVE_SASL_PLAIN: $e = base64_encode($auth . "" . $user . "" . $pass); $this->_sendcmd('AUTHENTICATE "PLAIN" {%d+}', strlen($e)); $this->_sendcmd($e); break; case SIEVE_SASL_LOGIN: $this->_sendcmd('AUTHENTICATE "LOGIN"'); $ue = base64_encode($user); $this->_sendcmd('{%d+}', strlen($ue)); $this->_sendcmd($ue); $pe = base64_encode($pass); $this->_sendcmd('{%d+}', strlen($pe)); $this->_sendcmd($pe); break; case SIEVE_SASL_DIGEST_MD5: $this->_sendcmd('AUTHENTICATE "DIGEST-MD5"'); // Read server challenge. Example (decoded): // // realm="example.com",nonce="GMybUaOM4lpMlJbeRwxOLzTalYDwLAxv/sLf8de4DPA=", // qop="auth,auth-int,auth-conf",cipher="rc4-40,rc4-56,rc4",charset=utf-8, // algorithm=md5-sess // // See also xp://security.sasl.DigestChallenge $len = $this->_sock->readLine(0x400); $str = base64_decode($this->_sock->readLine()); $this->cat && $this->cat->debug('Challenge (length ' . $len . '):', $str); $challenge = DigestChallenge::fromString($str); $response = $challenge->responseFor(DC_QOP_AUTH, $user, $pass, $auth); $this->cat && $this->cat->debug($challenge, $response); // Build and send challenge response $response->setDigestUri('sieve/' . $this->_sock->host); $cmd = $response->getString(); $this->cat && $this->cat->debug('Sending challenge response', $cmd); $this->_sendcmd('"%s"', base64_encode($cmd)); // Finally, read the response auth $len = $this->_sock->readLine(); $str = base64_decode($this->_sock->readLine()); $this->cat && $this->cat->debug('Response auth (length ' . $len . '):', $str); return TRUE; case SIEVE_SASL_CRAM_MD5: $this->_sendcmd('AUTHENTICATE "CRAM-MD5"'); // Read server challenge. Example (decoded): // // <*****@*****.**> // // See also rfc://2195 $len = $this->_sock->readLine(0x400); $challenge = base64_decode($this->_sock->readLine()); $this->cat && $this->cat->debug('Challenge (length ' . $len . '):', $challenge); // Build response and send it $response = sprintf('%s %s', $user, bin2hex(HMAC_MD5::hash($challenge, $pass))); $this->cat && $this->cat->debug('Sending challenge response', $response); $this->_sendcmd('"%s"', base64_encode($response)); break; default: throw new IllegalArgumentException('Authentication method ' . $method . ' not implemented'); } // Read the response. Examples: // // - OK // - NO ("SASL" "authentication failure") "Authentication error" return $this->_response(TRUE); }
/** * Create a new checksum from a file object * * @param io.File file * @param string key default NULL * @return security.checksum.HMAC_MD5 */ public static function fromFile($file, $key = NULL) { return new HMAC_MD5(HMAC_MD5::hash(FileUtil::getContents($file), $key)); }