2016-06-12 16 views
0

私はHMAC functionの小さな修正バージョンを学術目的で実装しようとしています。ここでWikipediaによって提供されるアルゴリズムは次のとおりです。変更されたHMACの実装

function hmac (key, message) 
    if (length(key) > blocksize) then 
     key = hash(key) // keys longer than blocksize are shortened 
    end if 
    if (length(key) < blocksize) then 
     // keys shorter than blocksize are zero-padded (where ∥ is concatenation) 
     key = key ∥ [0x00 * (blocksize - length(key))] // Where * is repetition. 
    end if 

    o_key_pad = [0x5c * blocksize] ⊕ key // Where blocksize is that of the underlying hash function 
    i_key_pad = [0x36 * blocksize] ⊕ key // Where ⊕ is exclusive or (XOR) 

    return hash(o_key_pad ∥ hash(i_key_pad ∥ message)) // Where ∥ is concatenation 
end function 

ここで私は(もちろんこれは私の不適切な結果を与える、私は与えられた解決策で確認)書いたコードがあります。 ブロックサイズは512ビットです。

は、私はすでに私が先頭にゼロを置くことを求め、独自のアルゴリズムのようなゼロを末尾おりませんので、私はキー、のためのパディングのロジックを実装していないです、私のコードが失敗した理由を一つのキーの理由を特定していると思います。

そして、先頭のゼロパディングを使用すると、数学のための任意の違いを生むだろうか、私は正しくバイト数学をやっている場合、それは

第二に、私はわからない使用方法ならば、私は本当に知りません。ここで

は私のコードです:

私が間違って行っている
private static string HMAC(string message) 
{ 
    //Every charecter corresponds to 4bits. 
    long hex_key = 0x0a7cb27e52; 

    //padding for an 64 Bit Key. 2 Chars = 1 Byte. Leading zeros I need (512-(10*4))/4 = 118 
    string asc_key = "0a7cb27e52"; 
    //Did Not KnowWhere To Use 
    asc_key = asc_key.PadLeft(128, '0'); 

    byte[] keyInBytes = Encoding.UTF8.GetBytes(asc_key); 
    var hexString = BitConverter.ToString(keyInBytes); 
    hexString = hexString.Replace("-", ""); 

    //Wikipedia Style naming 

    long o_key_pad = (0x5c * 0x40)^hex_key; 
    long i_key_pad = (0x36 * 0x40)^hex_key; 
    return GetMD5Hash(o_key_pad.ToString() + GetMD5Hash(i_key_pad.ToString() + message)); 
} 


public static String GetMD5Hash(String TextToHash) 
{ 
    //Check wether data was passed 
    if ((TextToHash == null) || (TextToHash.Length == 0)) 
    { 
     return String.Empty; 
    } 

    //Calculate MD5 hash. This requires that the string is splitted into a byte[]. 
    MD5 md5 = new MD5CryptoServiceProvider(); 
    byte[] textToHash = Encoding.Default.GetBytes(TextToHash); 
    byte[] result = md5.ComputeHash(textToHash); 

    //Convert result back to string. 
    return System.BitConverter.ToString(result); 
} 

+0

はい、あなたは 'i_pad'と' o_pad'を実装するときに '*'の定義を忘れてしまいました。また、 'long 'は埋め込みのための有用な型ではありません。 @ArtjomB。 –

+0

'*'の定義とパディングに使うデータ型は何ですか? –

+0

7行目に "// Where * is repetition"というコメントがあります。あなたは文字通り乗算として記号を使用しました。とにかくlong型は512ビットのデータを保持することができないので、バイト配列などの他のデータ型が必要であり、それをXORに対応するキーバイトで繰り返します。 @ArtjomB。 –

答えて

1

私は が先行ゼロを置くことを求め、元 アルゴリズムのようなゼロを末尾おりませんので、私は、キーのパディングのロジックを実装しておりません。

と私はそれが数学で何も変更しませんが、結果は意志先行ゼロパディングを使用すると、数学のための任意の 違いを作れば本当に知らない、またはそれに

を使用する方法異なる。

第2に、正しくバイト計算を行っているかどうかわかりません。

正しく実行していません。あなたのコードで問題がたくさんあります:

  • キーは、任意の長さを持っている可能性があり、それがlongのサイズを超える長い64ビットよりキーを持つことが一般的です。

  • o_key_padおよびi_key_padは、ブロックサイズを満たすために繰り返されません。

  • HMACおよびGetMD5Hashstringデータを受け取ります。暗号操作はバイナリデータで実行する必要がありますが、文字列で実行する必要はありません。

コード:

private static int BlockSize = 64; 

public static byte[] HMAC(byte[] message) 
{ 
    byte[] key = {0x0a, 0x7c, 0xb2, 0x7e, 0x52}; 
    if (key.Length > BlockSize) { 
     key = GetMD5Hash(key); 
    } 
    byte[] paddedKey = new byte[BlockSize]; 
    key.CopyTo(paddedKey, BlockSize-key.Length); 

    byte[] o_key_pad = new byte[BlockSize]; 
    byte[] i_key_pad = new byte[BlockSize]; 
    for(int i = 0; i < BlockSize; i++) { 
     o_key_pad[i] = (byte)(0x5c^paddedKey[i]); 
     i_key_pad[i] = (byte)(0x36^paddedKey[i]); 
    } 

    byte[] inner_hash = GetMD5Hash(concat(i_key_pad, message)); 
    return GetMD5Hash(concat(o_key_pad, inner_hash)); 
} 

private static byte[] concat(byte[] a1, byte[] a2) { 
    byte[] res = new byte[a1.Length + a2.Length]; 
    a1.CopyTo(res, 0); 
    a2.CopyTo(res, a1.Length); 
    return res; 
} 

private static byte[] GetMD5Hash(byte[] ToHash) 
{ 
    MD5 md5 = new MD5CryptoServiceProvider(); 
    return md5.ComputeHash(ToHash); 
} 

あなたはstringを取って提供するHMAC周りのラッパーを書くことができます。

+0

うわー!時間をかけて私を助けてくれてありがとう! –

関連する問題