所以我试图为了学术目的而实现HMAC function的小型修改版本。以下是Wikipedia提供的算法:
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 :(得分:1)
我没有为密钥实现填充逻辑,因为我是 要求放置前导零而不是原始的尾随零 算法
而且我真的不知道使用前导零填充是否会产生任何效果 数学的差异,或如何使用它
它不会改变数学中的任何内容,但结果会有所不同。
其次,我不确定我是否正确地进行字节数学运算。
你没有正确地做到这一点。您的代码存在很多问题:
密钥可能有任何长度,并且密钥长度超过64位是常见的,这将超过long
的大小。
o_key_pad
和i_key_pad
不会重复填写块大小。
HMAC
和GetMD5Hash
接收并传送string
个数据。加密操作应该对二进制数据执行,而不是对字符串执行。
代码:
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);
}
您可以围绕HMAC
编写一个包装来接收并传递string
。