« お(狼)みくじ | トップページ | マネージメント »

2010年2月20日 (土)

HMAC SHA256 BASE64

 何に使うかって…とあるWebサービスを使うための認証キーの生成に必要なのですが
 .NETやJava/JavaScript、PHP果てはVBAまで様々な実装例がありますがC/C++での実装例が無いんですよね。

 SHA256はオープンソースのSHA256クラスがそのまま使えます。
 MHACはRFC2104に仕様解説があります。
 文章が読みにくいのですが、仕様自体は単純で
 (1)ハッシュ・キーがブロック長(64Byte)より大きければ、ハッシュ・キー自体をsha256でハッシュ化して32Byteに縮める。
 (2)ハッシュ・キーがブロック長(64Byte)より小さければ、足りない分は0で埋める。
 (3)ipadkeyは、ブロック長(64Byte)分の0x36とハッシュ・キーのxorをとって作る。
 (4)opadkeyは、ブロック長(64Byte)分の0x5cとハッシュ・キーのxorをとって作る。
 (5)ipadkeyとメッセージ(ハッシュ化データ)を結合して、sha256でハッシュ化する。
 (6)opadkeyと(5)の結果を結合して、sha256でハッシュ化する。

 RFC2104の解説にあるソースの
 MD5の部分をオープンソースのSHA256クラスに置き換えればそのまま使えます。

----- HMAC-MD5をHMAC-SHA256に書き換えたサンプル
面倒なのでスコープ切ってごまかしてるけど、SHA256クラスには再利用の為の初期化処理を入れたほうが良いと思う。

001 void HMAC(char *text,char *key,unsigned char *hmac)
002 {
003   if (text == NULL || key == NULL || hmac == NULL) return ;
004
005   int testLen = (int)strlen(text) ;
006   int keyLen = (int)strlen(key) ;
007
008   unsigned char k_ipad[65]; /* inner padding -
009                  * key XORd with ipad
010                  */
011   unsigned char k_opad[65]; /* outer padding -
012                 * key XORd with opad
013                 */
014   unsigned char KeyHash[32];
015
016   /* if key is longer than 64 bytes reset it to key=MD5(key) */
017   if (keyLen > 64) {
018     SHA256 sha256;
019     sha256.Push((unsigned char*)key, keyLen);
020     sha256.Final(KeyHash);
021     key = (char *)KeyHash ;
022     keyLen = 32;
023   }
024
025   memset(k_ipad,0,sizeof(k_ipad)) ;
026   memset(k_opad,0,sizeof(k_opad)) ;
027   memcpy(k_ipad,key,keyLen) ;
028   memcpy(k_opad,key,keyLen) ;
029
030   /* XOR key with ipad and opad values */
031   for (int i=0; i<64; i++) {
032     k_ipad[i] ^= 0x36;
033     k_opad[i] ^= 0x5c;
034   }
035
036   unsigned char Hash[32];
037   {
038     SHA256 sha256;
039     sha256.Push(k_ipad, 64);
040     sha256.Push((unsigned char*)text, testLen);
041     sha256.Final(Hash);
042   }
043
044   {
045     SHA256 sha256;
046     sha256.Push(k_opad, 64);
047     sha256.Push(Hash, 32);
048     sha256.Final(Hash);
049   }
050
051   memcpy(hmac,Hash,32) ;
052 }

BASE64はVisualC++2003以降はCrypt APIに含まれていますのでCrypt32.libをリンクしてwincrypt.hをインクルードすれば使えます。
※Windows.hが同時に必要です。

----- HMAC-SHA256をBASE64変換するサンプル
001 #include <stdio.h>
002 #include <string.h>
003 #include <conio.h>
004
005 #include <windows.h>
006 #include <wincrypt.h>
007
008 int main( )
009 {
010   HMAC hmac;
011   unsigned char Hash[32];
012   char Text[1024] ;
013   char Key[1024] ;
014   char Text[1024] ;
015   DWORD TextLen = 1024;
016
017   strcpy(Text,"Text Data") ;
018   strcpy(Key,"1234567890") ;
019
020   HMAC(Data,Key,Hash) ;
021
022   if( CryptBinaryToString( Hash, 32, CRYPT_STRING_BASE64, Text, &TextLen ) ){
023     printf("HMAC-SHA256 BASE64 : %s\n",Text) ;
024   }
025
026   _getch() ;
027   return 0;
028 }

大丈夫だとは思うけど、Blog用に書き換えたので、このままでは動かんかも。
※HMACはクラス化してるしSHA256もアチコチ書き直してるが、改変したのを公開するわけにもいかんので。
公式にあるサンプルリクエストのデータ食わせればサンプルと同じハッシュ値が得られます。
同じハッシュが得られない場合は食わせるデータが間違ってます。
私は / が抜けてるのに気づくまでに4時間かかった… orz

|

« お(狼)みくじ | トップページ | マネージメント »

元ヲタのつぶやき」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/25792/47613704

この記事へのトラックバック一覧です: HMAC SHA256 BASE64:

« お(狼)みくじ | トップページ | マネージメント »