% telnet mail.zzz.dom 25 220 mail.zzz.dom SMTP-Gateway ... EHLO mail.zzz.dom 250-mail.zzz.dom Hello mail.zzz.dom ... 250-AUTH CRAM-MD5 LOGIN PLAIN ←SMTP AUTH をサポートしていることを示す 250-ENHANCEDSTATUSCODES 250-8BITMIME 250-SIZE 10485760 250-DSN 250-ONEX 250-XUSR 250 HELP AUTH PLAIN dGFuYWthAHRhbmFrYQBoaS5taS50dQ== 235 Authentication successful QUIT 221 Closing connection. Good bye.
AUTH PLAIN コマンドには、"ユーザ名\0ユーザ名\0パスワード" または "\0ユーザ名\0パスワード" を BASE64 エンコードしたものを指定する。\0 はヌル文字を意味する。AUTH PLAIN とパスワードは別の行で送信される場合もある。PLAIN の場合はパスワードを隠蔽することはできない。
$user = "tanaka"; $pass = "hi.mi.tu"; $res1 = base64encode("$user\0$user\0$pass");
CRAM-MD5 は Challenge Response Authentication Mechanism の略。チャレンジレスポンスを用いることでパスワードが平文でネットワークを流れてしまうのを防ぐ。演算はちょっと面倒。
S: 220 mail.biglobe.ne.jp SMTP-Gateway ... C: EHLO mail.zzz.dom S: 250-mail.zzz.dom Hello mail.zzz.dom... S: 250-AUTH CRAM-MD5 LOGIN PLAIN S: 250-ENHANCEDSTATUSCODES S: 250-8BITMIME S: 250-SIZE 10485760 S: 250-DSN S: 250-ONEX S: 250-XUSR S: 250 HELP C: AUTH CRAM-MD5 S: 334 PDM0ODAuNjAxLjEwNTkyMzkyNTRAbWFpbC56enouZG9tPg== C: dGFuYWthIDU4M2UzMTBhZTRiNjBhZGU0Yjc4YzlhYWU5ZDdjY2Y2 S: 235 Authentication successful C: QUIT S: 221 Closing connection. Good bye.
dGFuYWthID... の部分は、サーバーから得られるチャレンジコード(PDM0ODAu...)、ユーザ名(例:tanaka)およびパスワード(例:hi.mi.tu)から、次の演算で求める。
$pass = "hi.mi.tu"; # パスワード $user = "tanaka"; # ユーザ名 $opad = "\x5c" x 64; # 64個の 5c(固定値) $ipad = "\x36" x 64; # 64個の 36(固定値) $cha1 = "PDM0ODAuNjAxLjEwNTkyMzkyNTRAbWFpbC56enouZG9tPg=="; $cha2 = base64decode($cha1); $res1 = bin2hex(md5(exor($pass, $opad), md5(exor($pass, $ipad), $cha2))); $res2 = "$user $res1"; $res3 = base64encode($res2);
ここで、md5() は MD5 によるハッシュ値を求める関数、exor() は 2つの文字列を 1バイトずつ XOR 演算する関数。bin2hex() はバイナリデータを 16進表記の文字列に変換する関数である。計算途中のそれぞれの値は次のようになる。
cha1 = PDM0ODAuNjAxLjEwNTkyMzkyNTRAbWFpbC56enouZG9tPg== cha2 = <3480.601.1059239254@mail.zzz.dom> res1 = 583e310ae4b60ade4b78c9aae9d7ccf6 res2 = tanaka 583e310ae4b60ade4b78c9aae9d7ccf6 res3 = dGFuYWthIDU4M2UzMTBhZTRiNjBhZGU0Yjc4YzlhYWU5ZDdjY2Y2
サーバが 334 でチャレンジコードを送信してくるので、これに対する演算結果を応答として返す。サーバが 235 を返してきた場合は認証は成功。再度 334 でチャレンジコードを返してきた場合は処理を繰り返す。535 を返してきた場合は認証失敗。
LOGIN認証は、サーバが "Username:" を BASE64エンコードした値をチャレンジコードとして送信してくるので、ログイン名を BASE64エンコードして返し、再度 "Password:" をチャレンジコードとして送信してくるのでパスワードを BASE64エンコードして返す。毎回チャレンジコードが同じため、ログイン名とパスワードを暗号化することはできない。