CramMd5Authenticator.php 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Mailer\Transport\Smtp\Auth;
  11. use Symfony\Component\Mailer\Exception\InvalidArgumentException;
  12. use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport;
  13. /**
  14. * Handles CRAM-MD5 authentication.
  15. *
  16. * @author Chris Corbyn
  17. */
  18. class CramMd5Authenticator implements AuthenticatorInterface
  19. {
  20. public function getAuthKeyword(): string
  21. {
  22. return 'CRAM-MD5';
  23. }
  24. /**
  25. * @see https://www.ietf.org/rfc/rfc4954.txt
  26. */
  27. public function authenticate(EsmtpTransport $client): void
  28. {
  29. $challenge = $client->executeCommand("AUTH CRAM-MD5\r\n", [334]);
  30. $challenge = base64_decode(substr($challenge, 4));
  31. $message = base64_encode($client->getUsername().' '.$this->getResponse($client->getPassword(), $challenge));
  32. $client->executeCommand(\sprintf("%s\r\n", $message), [235]);
  33. }
  34. /**
  35. * Generates a CRAM-MD5 response from a server challenge.
  36. */
  37. private function getResponse(#[\SensitiveParameter] string $secret, string $challenge): string
  38. {
  39. if (!$secret) {
  40. throw new InvalidArgumentException('A non-empty secret is required.');
  41. }
  42. if (\strlen($secret) > 64) {
  43. $secret = pack('H32', md5($secret));
  44. }
  45. if (\strlen($secret) < 64) {
  46. $secret = str_pad($secret, 64, \chr(0));
  47. }
  48. $kipad = substr($secret, 0, 64) ^ str_repeat(\chr(0x36), 64);
  49. $kopad = substr($secret, 0, 64) ^ str_repeat(\chr(0x5C), 64);
  50. $inner = pack('H32', md5($kipad.$challenge));
  51. return md5($kopad.$inner);
  52. }
  53. }