APOPとIMAP(CRAM-MD5)をC#で使おう |
作成日:2003/8/14 最終更新日: 2005/1/18 |
◆概要 | |||
.Net Frameworkには,SMTPを操作するためのライブラリは標準で付属しますが,POPやIMAPを扱うライブラリは付属していません.Active Mail のようなサードパーティ製のライブラリは存在しますが,フリーで利用できるものはあまり見当たりません.そこで,ここではVisual Studio .NetとC#を用いて,APOPとIMAP(CRAM-MD5)の基本的な操作を行うプログラムを紹介します. 以下のサンプルコードは,指定したメールサーバーにAPOPかIMAP(CRAM-MD5)経由でアクセスし,一定時間ごとに新着メールの数を取得して,ダイアログを表示するものです.「通信過程のメッセージを表示する」をチェックすることで,やり取りされるメッセージ(の一部)を表示することもできます. 今回はまず,APOPやIMAPを使う際に最大のポイントとなるMD5という暗号化アルゴリズムとCRAM-MD5という認証手法について簡単に解説し,次にソースコードを参照しながら実際の通信の様子を紹介していきます. |
|||
|
|||
サンプルコード (zip) 実行ファイルのみ (zip) |
|||
|
◆MD5 |
MD5は,簡単に言えば,復元の難しい高度な暗号化アルゴリズムです.
このように,もとの文字が一文字違うだけで,出力結果がまったく異なるため,もとの文字列を予測するのがかなり難しくなります.詳しい記述は,RFC 1321 などを参考にしてください. C#でMD5を利用するには,MD5CryptoServiceProviderというクラスを利用します.
|
◆CRAM-MD5 |
CRAMとは,Challenge-Response Authentication Mechanismの略で,APOPやIMAP(CRAM-MD5)の認証に利用される仕組みです.APOPの場合を例にして簡単に説明すると,だいたい以下のような流れで利用されています.(IMAPの場合は,もう少し複雑な手順を踏むことになります.C#でIMAPの項や, HMAC-MD5の項を参照してください.)
ポイントとしては,ネットワーク上には生のパスワードが一度も流れないことです.また前述のように,MD5で暗号化された文字列は,もとの文字列が一文字異なるだけで,大きく変化してきます.よって,「ランダムな文字列」と「パスワード」の両方を知っている場合以外,つまりサーバーとクライアント以外のコンピュータでは,非常に解読が難しくなります. 詳しい記述は,RFC 2095 やIMAP4 and CRAM-MD5 Authentication などを参考にしてください. |
◆C#でAPOP |
APOPを用いた基本的な通信の流れを,C#のソースコードと出力結果をもとに解説します. APOPの通信は,MailCheckerクラスのConnectApopServerというメソッドを中心に実装しました.
まず,TcpClientを用いて,APOPのポート(110番)にソケット接続します.
次にサーバーからの返答を読み取り,簡単な正規表現を用いてChallengeキー(ランダムに生成される文字列)を 抜き出します.
サーバーから受信する文字列の例 次に,Challengeキー(上の例では<26978.1060839180@mail>)とパスワードを連結し,MD5で暗号化した文字列を生成します.
サーバーからの返答を読み取ります.認証が成功した場合,"+OK"で始まる文字列が返ってきます.
ここでは,正規表現を用いて,サーバーに格納されたメールの数を抜き出しています.
認証成功時のメッセージの例 最後に,"QUIT\r\n"という文字列を送信し,APOPサーバーからログアウトします. そして,ソケット接続を終了します.
おおむね,APOPの通信手順はこのようなものです. 個々のメールの読み取りなどをする場合,認証後に特定の文字列を送信することで行います. 利用できるコマンドについては, RFC 1939 や,@ITのAPOP記事 を参照してください. |
◆C#でIMAP (CRAM-MD5) |
今度は,IMAPを用いた基本的な通信の流れを,C#のソースコードと出力結果をもとに解説します. IMAPの通信は,MailCheckerクラスのConnectImapServerというメソッドを中心に実装しました.
まず,TcpClientを用いて,IMAPのポート(143番)にソケット接続します.
次にサーバーからの返答を読み取り,認証を開始するために以下のような文字列( クライアント名 + " AUTHENTICATE CRAM-MD5\r\n")を送信します.
ソケット接続時にサーバーから返される文字列の例 次のサーバーからの返答には,Base64でエンコードされたChallengeキーが含まれます.まず,Base64をデコードして,Challengeキーを取得します.次に,ChallengeキーとパスワードをHMAC-MD5というアルゴリズムを用いて,暗号化します.(HMAC-MD5については後述).その後,ユーザ名と暗号化した文字列を連結して,サーバーに送信します.実際に送信する文字列は "user 329435e5e66be809a656af105f42401e\r\n"といったものになります.
Base64でエンコードされた状態のChallengeキーの例 平文のChallengeキーの例 次に,サーバーからの返答を読み取ります.認証が成功した場合は,その旨を示す文字列が返されます.
認証成功時のサーバーからの受信文字列の例 次に,メールボックスの状態を調べるために,クライアント名 + " EXAMINE INBOX\r\n"という文字列をサーバーに送信します.サーバーから返される文字列には,メールボックス内のメール数や,新着メールの数などが含まれます.ここでは,正規表現を用いて,新着メールの数を抜き出しています.
EXAMINEコマンドによりサーバーから返される文字列 最後に,クライアント名 + "LOGOUT\r\n"という文字列を送信して,ログアウトします.
おおむね,IMAPの通信手順はこのようなものです. 全体の流れはAPOPとほぼ同様ですが,暗号化に使うアルゴリズム(HMAC-MD5)は結構複雑なものになっています(次の章で簡単に説明します).個々のメールの読み取りなどをする場合,認証後に特定の文字列を送信することで行います. 利用できるコマンドについては, RFC 2060 などを参照してください. |
◆補足: HMAC-MD5 |
IMAPの認証では,HMAC-MD5という暗号化手法が使われています.これは,二重にMD5で暗号化を行うなどの方法で,解読をさらに難しくする手法のようです. 詳しく知りたい方は RFC 2140 などを参考にしてください.ここでは,実装の方法のみを紹介します. サンプルプログラムでは,MailCheckerのCreateHmacMD5というメソッドで実装しています.
まず,パスワードを64バイトのChar型配列(passChars)に格納します.パスワードの長さを越えた部分は,初期値としてNUL(0x00)が格納されます.
次に,HMAC-MD5の計算に利用するpassIpadとpassOpadの値を設定します.passIpad[i]は passChars[i] と 0x36, passOpad[i]は passChars[i]と0x5cの排他的論理和(XOR)となります.
次に, passIpadとchallenge文字列を連結して,MD5を計算します.ここでの計算結果は16進の文字列ではなく,バイト配列として保持します.
最後に,passOpadと上のバイト配列を連結し,もう一度MD5を計算します.この計算結果を,今度は16進の文字列として返します.
|
◆参考URL |
|