1<?php
2
3/**
4 * Swift Mailer CRAM-MD5 Authenticator Mechanism
5 * Please read the LICENSE file
6 * @author Chris Corbyn <chris@w3style.co.uk>
7 * @package Swift_Authenticator
8 * @license GNU Lesser General Public License
9 */
10
11require_once dirname(__FILE__) . "/../ClassLoader.php";
12Swift_ClassLoader::load("Swift_Authenticator");
13
14/**
15 * Swift CRAM-MD5 Authenticator
16 * This form of authentication is a secure challenge-response method
17 * @package Swift_Authenticator
18 * @author Chris Corbyn <chris@w3style.co.uk>
19 */
20class Swift_Authenticator_CRAMMD5 implements Swift_Authenticator
21{
22  /**
23   * Try to authenticate using the username and password
24   * Returns false on failure
25   * @param string The username
26   * @param string The password
27   * @param Swift The instance of Swift this authenticator is used in
28   * @return boolean
29   */
30  public function isAuthenticated($user, $pass, Swift $swift)
31  {
32    try {
33      $encoded_challenge = substr($swift->command("AUTH CRAM-MD5", 334)->getString(), 4);
34      $challenge = base64_decode($encoded_challenge);
35      $response = base64_encode($user . " " . self::generateCRAMMD5Hash($pass, $challenge));
36      $swift->command($response, 235);
37    } catch (Swift_ConnectionException $e) {
38      $swift->reset();
39      return false;
40    }
41    return true;
42  }
43  /**
44   * Return the name of the AUTH extension this is for
45   * @return string
46   */
47  public function getAuthExtensionName()
48  {
49    return "CRAM-MD5";
50  }
51  /**
52   * Generate a CRAM-MD5 hash from a challenge
53   * @param string The string to get a hash from
54   * @param string The challenge to use to make the hash
55   * @return string
56   */
57  public static function generateCRAMMD5Hash($password, $challenge)
58  {
59    if (strlen($password) > 64)
60      $password = pack('H32', md5($password));
61
62    if (strlen($password) < 64)
63      $password = str_pad($password, 64, chr(0));
64
65    $k_ipad = substr($password, 0, 64) ^ str_repeat(chr(0x36), 64);
66    $k_opad = substr($password, 0, 64) ^ str_repeat(chr(0x5C), 64);
67
68    $inner  = pack('H32', md5($k_ipad.$challenge));
69    $digest = md5($k_opad.$inner);
70
71    return $digest;
72  }
73}
74