HMAC + 何か

HMAC - Wikipedia
http://ja.wikipedia.org/wiki/HMAC

RFC2104 - HMAC: Keyed-Hashing for Message Authentication
http://tools.ietf.org/html/rfc2104


要するに、データをキーでハッシュします。これによりデータを認証できます。
Perlで簡単に実装できるのでやってみた。
OAuthのためのBase64エンコードについても少し触れています。

use Digest::SHA1;
use Digest::MD5;
sub hmac{
	my ($object, $key, $msg) = @_;
	
	# init
	if(length($key) > 64){
		 $key = $object->add($key)->digest;
		 $object->reset();
	}
	
	# calc
	$msg = $object->add($key ^ "\x36" x 64, $msg)->digest;
	$object->reset();
	
	# return
	return $object->add($key ^ "\x5C" x 64, $msg);
}


my $key = "Jefe";
my $msg = "what do ya want for nothing?";
print hmac(new Digest::MD5, $key, $msg)->hexdigest . "\n"; # HMAC-MD5 : Hex
print hmac(new Digest::SHA1, $key, $msg)->b64digest . '=' . "\n"; # HMAC-SHA1 : Base64

750c783e6ab0b503eaa86e310a5db738
7/zfauXrL6LSdBbV8YTfnCWafHk=

HMACは様々なハッシュに対応できるので、それを生かすためにこんな実装にしてみました。
new, reset, add, digestメソッドが備わったモジュールであれば何でも使えます(Digest::MD5などの実装に習った実装であれば、ですが)。
Outputされるのは1つ目の例はHMAC-MD5で16進数文字列で出力、2つ目の例はHMAC-SHA1Base64エンコードで出力しています。


HMAC-SHA1OAuth認証で使われていたりします。
OAuth認証ではBase64エンコードされたデータでやりとりするので、b64digestで変換します。
ここで大事なのは、'='を1個つける事です。
理由を以下で説明します。


Base64エンコードは6bitを8bitで表現する符号化です。
また、Byte数が4の倍数になるように、'='で調整することになっています。
つまり、Base64に変換したときの情報量の変化は4/3倍+1〜3byteになります。
一方、SHA1で得られるハッシュは160bitで固定です。
このハッシュをBase64エンコードを行うと、データ量は以下になります。
160bit * 4/3 / 8bit = 26.625byte ≒ 27byte
4の倍数になるように調整するので、'='を1個加えて、28byteとなります。


SHA1の演算結果は固定なので、わざわざ長さを求めて'='を何個くわえるか、といった処理はする必要はないです。
もちろん使うDigestアルゴリズムが定まってない場合は必要です。
Perlであれば以下の感じで4の倍数になるように'='を連結させる事ができます。

$digest .= ('=' x (3-(length($digest)+3)%4) );