Date: Sun, 27 Apr 2008 14:59:17 +0900 Comment: linux/tipsにWineを追加, programming/tipsに「Modified UTF-7のエンコード・デコード」と「CRAM-MD5による認証」を追加 ================================================================== === linux/tips/wine/index.wiki.txt ================================================================== --- linux/tips/wine/index.wiki.txt +++ linux/tips/wine/index.wiki.txt @@ -0,0 +1,48 @@ +${smdncms:tags,Wine} +*Wine +[[Wine:http://www.winehq.org/]]に関するTips + +**論理ドライブ +~~/.wine/dosdevices配下にシンボリックリンクを作成することでファイルシステム上の任意のパスを論理ドライブとして参照させることが出来る。 Wineのインストール後はこのようになっていた。 + $ ls -l ~/.wine/dosdevices/ + 合計 0 + lrwxrwxrwx 1 santamarta santamarta 10 2008-04-06 12:20 c: -> ../drive_c + lrwxrwxrwx 1 santamarta santamarta 13 2008-04-09 19:52 d: -> /media/cdrom0 + lrwxrwxrwx 1 santamarta santamarta 8 2008-04-09 19:52 d:: -> /dev/hdc + lrwxrwxrwx 1 santamarta santamarta 1 2008-04-06 12:20 z: -> / + +ディレクトリ/srv/smb/をドライブレターe:の論理ドライブとして参照させるには、次のようにする。 + ln -s /srv/smb/ e: + +**WMAへのエンコード +Linuxで使えるWindows Media Audioエンコーダはおそらく存在しないので、Linux上でWMAへエンコードするにはWineを使ってWindows用のWMAエンコーダを使う。 まず[[Windows Media 9 シリーズ - Windows Media Encoding Utility:http://www.microsoft.com/japan/windows/windowsmedia/WM8/encoding.aspx]]からwm8eutil_setup.exeをダウンロードし、インストールする。 + wine wm8eutil_setup.exe +インストールウィザードが表示されるが、Windowsと同様ウィザードに従って適当に設定して[次へ]で進む。 エンコーダは~/.wine/drive_c/Program Files/Windows Media Components/Tools下にインストールされる。 エンコード例は以下のとおり。 + wine WM8EUTIL.exe -input ~/music.wav -output ~/music.wma -a_setting 96_44_2 +コマンドラインオプションはwine WM8EUTIL.exe /?で確認できる。 + $ wine WM8EUTIL.exe /? + + HELP usage for wm8eutil. Use one of the following for how to use wm8eutil.exe. + + [-help?] Display the user help doc for wm8eutil. + [-all?] Usage for all settings. + [-io?] Usage for Input/Output and config file. + [-profile?] Profile numbers and basic descriptions. + [-profileall?] Details for all profiles. + [-profile_aN?] Details for audio-only profile N. + [-profile_vN?] Details for video-only profile N. + [-profile_avN?] Details for audio/video profile N. + NOTE: It uses the actual bitrate for N. + Example: -profile_a32?. + [-audio?] Usage for Audio Codec settings. + [-video?] Usage for Video Codec settings. + [-default?] All default values for custom settings. + [-a_default?] Audio default values for custom settings. + [-v_default?] Video default values for custom settings. + [-cont_desc?] Usage for how to put content descriptions in the WMV/WMA files. + [-example?] Examples for how to use wm8eutil. + [-a_example?] Examples for how to use wm8eutil for audio-only encoding. + [-v_example?] Examples for how to use wm8eutil for video-only encoding. + [-av_example?] Examples for how to use wm8eutil for audio/video encoding. + [-d_example?] Examples for how to use wm8eutil for directory mode encoding. + === programming/tips/modified_utf7/index.wiki.txt ================================================================== --- programming/tips/modified_utf7/index.wiki.txt +++ programming/tips/modified_utf7/index.wiki.txt @@ -0,0 +1,140 @@ +${smdncms:tags,C#,Modified,修正,UTF-7,UTF7,IMAP-UTF7} +*Modified UTF-7のエンコード・デコード +Modified UTF-7は修正 UTF-7, IMAP-UTF7とも呼ばれるもので、IMAPで非ASCII文字を含むメールボックス名をASCII文字のみで表記するためのエンコード方式。 UTF-7へのエンコードはUTF-16文字列中の非ASCII文字のみBase64に変換することで得られるが、Modified UTF-7へのエンコードはUTF-16文字列(ビッグエンディアン)に対して次の変換ルールを適用することで得ることが出来る。 ++'&'は'&-'に変換する ++'&'を除く印字可能な文字(0x20〜0x25と0x27〜0x7e)はそのまま ++上記以外の印字不可能な文字は後述するModified Base64に変換し、'&'(shift)と'-'(shift back)で括る +例えば文字列「INBOX.日本語」を変換するときは、「INBOX.&日本語-」とシフトしたあと「日本語」のところだけModified Base64を適用する。 Modified Base64の変換ルールは次のとおり。 ++基本の変換ルールは通常のBase64と同じ ++ただし変換テーブルは'/'の代わりに','を使う ++上記ルールで変換した後の文字数が4の倍数にならなくてもパディング('=')は入れない ++印字可能な文字(0x20〜0x25と0x27〜0x7e)にModified Base64を適用してはいけない +このルールに則り文字列「日本語」を変換すると「ZeVnLIqe」となるので、「INBOX.日本語」をModified UTF-7へエンコードした結果は「INBOX.&ZeVnLIqe-」となる。 + +**C#での実装 +Modified UTF-7へのエンコード(コメントはRFC 3501のsection 5.1.3より抜粋) + public static string ToModifiedUTF7String(string str) + { + var encoded = new StringBuilder(); + var shiftFrom = -1; + + for { + var c = str[index]; + + if { + if { + // string -> modified UTF7 + encoded.Append('&'); + encoded.Append(ToModifiedUTF7(str.Substring(shiftFrom, index - shiftFrom))); + encoded.Append('-'); + + shiftFrom = -1; + } + + // printable US-ASCII characters + if + // except for "&" + encoded.Append("&-"); + else + encoded.Append(c); + } + else { + if + shiftFrom = index; + } + } + + if { + // string -> modified UTF7 + encoded.Append('&'); + encoded.Append(ToModifiedUTF7(str.Substring(shiftFrom))); + encoded.Append('-'); + } + + return encoded.ToString(); + } + + private static string ToModifiedUTF7(string str) + { + return ToModifiedBase64(Encoding.BigEndianUnicode.GetBytes(str)); + } + + private static string ToModifiedBase64(byte[] bytes) + { + var base64 = Convert.ToBase64String(bytes).Replace('/', ','); + var padding = base64.IndexOf('='); + + if + return base64.Substring(0, padding); + else + return base64; + } + +Modified UTF-7からのデコード + public static string FromModifiedUTF7String(string str) + { + if + return str; + + var bytes = Encoding.ASCII.GetBytes(str); + var decoded = new StringBuilder(); + + for { + // In modified UTF-7, printable US-ASCII characters, except for "&", + // represent themselves + // "&" is used to shift to modified BASE64 + if { // '&' + decoded.Append((char)bytes[index]); + continue; + } + + if + // incorrect form + throw new FormatException("incorrect form"); + + if { // '-' + // The character "&" is represented by the two-octet sequence "&-". + decoded.Append('&'); + continue; + } + + var nonprintable = new StringBuilder(); + + for { + if // '-' + // "-" is used to shift back to US-ASCII + break; + + nonprintable.Append((char)bytes[index]); + } + + // modified UTF7 -> string + decoded.Append(FromModifiedUTF7(nonprintable.ToString())); + } + + return decoded.ToString(); + } + + private static string FromModifiedUTF7(string str) + { + return Encoding.BigEndianUnicode.GetString(FromModifiedBase64(str)); + } + + private static byte[] FromModifiedBase64(string str) + { + // "," is used instead of "/" + str = str.Replace(',', '/'); + + var padding = 4 - str.Length & 3; + + if + return Convert.FromBase64String(str); + else if + throw new FormatException("incorrect form"); + else + return Convert.FromBase64String(str +; + } + +**参考資料 +-[[RFC 3501 INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1 5.1.3. Mailbox International Naming Convention:http://tools.ietf.org/html/rfc3501#section-5.1.3]] +-[[Unicode - Wikipedia:http://ja.wikipedia.org/wiki/Unicode]] === programming/tips/cram_md5/index.wiki.txt ================================================================== --- programming/tips/cram_md5/index.wiki.txt +++ programming/tips/cram_md5/index.wiki.txt @@ -0,0 +1,113 @@ +${smdncms:tags,C#,CRAM-MD5} +*CRAM-MD5による認証 +CRAM-MD5はPOP, IMAPで使用されるチャレンジ・レスポンス方式の認証方法で、HMAC-MD5ハッシュアルゴリズムを用いてパスワードを暗号化する。 IMAPでのAUTHENTICATE CRAM-MD5による認証のシーケンスは次の例のようになる。 + C: 0001 AUTHENTICATE CRAM-MD5 + S: + PDIxMDQ1OTA2MjYzMjA1MjguMTIwMzkzMDcwMkBoYXlhbWk+ + C: c2FudGFtYXJ0YSAzNTY0MzhmMGU0MzhhZDdlZTdhYTZkYzJjYzE5MmIwMg== + S: 0001 OK Logged in. +上記の送受信内容をBase64デコードするとこのようになっている。 + S: + <2104590626320528.1203930702@hayami> + C: santamarta 356438f0e438ad7ee7aa6dc2cc192b02 + +AUTHENTICATEコマンドに対して、サーバからはBase64エンコードされたタイムスタンプとホスト名を含むチャレンジコードが返され、クライアントはユーザ名と、パスワードをキーにしてHMAC-MD5ハッシュアルゴリズムを適用したチャレンジコードをBase64エンコードしてレスポンスとしてを返す。 簡略化して表記するなら + S: + Base64(チャレンジコード) + C: Base64(ユーザ名 HMAC-MD5(パスワード, チャレンジコード)) + + チャレンジコード = <タイムスタンプ@ホスト名> +のようになる。 + +**C#でのCRAM-MD5認証の実装 +Mono/.NET FrameworkではHMAC-MD5ハッシュ値の計算にSystem.Security.Cryptography.HMACMD5クラスのComputeHashメソッドを用いることが出来る。 次の例は受信したチャレンジコードと、ユーザ名、パスワードを引数としてCRAM-MD5認証のレスポンスを返すメソッド。 + + public string AuthenticateCramMD5(string challenge, string username, string password) + { + // Base64デコードしたチャレンジコードに対してパスワードをキーとしたHMAC-MD5ハッシュ値を計算する + var keyed =; + + // 計算したHMAC-MD5ハッシュ値のbyte[]を16進表記の文字列に変換する + var digest = string.Empty; + + foreach { + digest += octet.ToString("x02"); + } + + // ユーザ名と計算したHMAC-MD5ハッシュ値をBase64エンコードしてレスポンスとして返す + return Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0} {1}", username, digest))); + } + +**C#でのHMAC-MD5の実装 +次の例はRFC 2104で記述されている内容に基づいて作成したHMAC-MD5ハッシュ値の計算を行うメソッド。 System.Security.Cryptography.HMACMD5.ComputeHashメソッドに相当するものを実装したもの。 (コメントはRFCより抜粋) + public byte[] HmacMd5(byte[] key, byte[] text) + { + const int B = 64; + + // 2. Definition of HMAC + + // The definition of HMAC requires a cryptographic hash function, + // which we denote by H, + var H = new MD5CryptoServiceProvider(); + + // and a secret key K + var K = new byte[B]; + + // We assume H to be a cryptographic hash function where data is + // hashed by iterating a basic compression function on blocks of data. + // We denote by B the byte-length of such blocks + // + + // The authentication key K can be of any length up to B, the + // block length of the hash function. + if + throw new InvalidOperationException("key length is too long"); + + // We define two fixed and different strings ipad and opad as follows + //: + var ipad = new byte[B]; // ipad = the byte 0x36 repeated B times + var opad = new byte[B]; // opad = the byte 0x5C repeated B times + + // To compute HMAC over the data `text' we perform + // H(K XOR opad, H(K XOR ipad, text)) + + // append zeros to the end of K to create a B byte string + key.CopyTo(K, 0); + + for { + K[i] = 0x00; + } + + for { + // the B byte string computed in + // step with ipad + ipad[i] =; + + // the B byte string computed in + // step with opad + opad[i] =; + } + + // append the stream of data 'text' to the B byte string + // resulting from step + var hi = new byte[ipad.Length + text.Length]; // hi = K XOR ipad, text + ipad.CopyTo(hi, 0); + text.CopyTo(hi, ipad.Length); + + // + var Hi = H.ComputeHash(hi); // Hi = H(hi) = H(K XOR ipad, text) + + // to the B byte string + // resulting from step + var ho = new byte[opad.Length + Hi.Length]; // ho = K XOR opad, H(hi) + opad.CopyTo(ho, 0); + Hi .CopyTo(ho, opad.Length); + + // and output + // the result + H.Initialize(); + + return H.ComputeHash(ho); // Ho = H(ho) = H(K XOR opad, H(hi)) + } + +**参考資料 +-[[RFC 2195 IMAP/POP AUTHorize Extension for Simple Challenge/Response:http://tools.ietf.org/html/rfc2195]] +-[[RFC 2104 HMAC: Keyed-Hashing for Message Authentication:http://tools.ietf.org/html/rfc2104]] +