HMAC 实现 - 伪代码
HMAC Implementation - Pseudo code
我必须实现自己的 HMAC-SHA256 以便在嵌入式项目中使用。我无法让它工作。我什至不能得到伪代码,手工计算的工作,所以我知道我做错了什么!
我的伪代码计算。按照维基百科中的图表
1 function hmac (key, message)
2 if (length(key) > blocksize) then
3 // keys longer than blocksize are shortened
4 key = hash(key)
5 end if
6 if (length(key) < blocksize) then
7 // keys shorter than blocksize are zero-padded
8 key = key ∥ zeroes(blocksize - length(key))
9 end if
10
11 // Where blocksize is that of the underlying hash function
12 o_key_pad = [0x5c * blocksize] ⊕ key
13 i_key_pad = [0x36 * blocksize] ⊕ key // Where ⊕ is exclusive or (XOR)
14 // Where ∥ is concatenation
15 return hash(o_key_pad ∥ hash(i_key_pad ∥ message))
16 end function
当我对 key="mykey" 和 message="helloworld" 进行手工计算时,我得到以下结果:
key = 0x6d796b6579000000000000000000000000000000000000000000000000000000
o_key_pad = 0x31253739255c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c
i_key_pad = 0x5b4f5d534f363636363636363636363636363636363636363636363636363636
hash(i_key_pad ∥ message) = 6fb2e91de7b8b5ec6283846ff7245cd6eb4a4fd26056b529bd42d99fcf3314d2
和0d76a16089f85cd2169bb64b6f2c818e6a404a218896483fcd97fee5cce185ae
的整体hmac
固定key长度和计算内外padding时,需要用到底层hash函数的blocksize,与其[=32]不同=]输出大小。这是函数操作的输入块的大小。在 SHA256 的情况下,块大小为 512 位(64 字节),输出大小为 256 位(32 字节)。
如果您使用 32 作为块大小,您的结果就是您得到的结果。
使用正确的长度 blocksize key
、o_key_pad
和 i_key_pad
基本相同,只有尾随 00
、5c
的两倍长或分别 36
字节。
内部散列的结果(即hash(i_key_pad ∥ message)
是:
8bf029764919f9e35249d0d55ffb8fd6c62fe23a85c1515e0120c5005aa813d5
最终值 (hash(o_key_pad ∥ hash(i_key_pad ∥ message))
) 为:
7fdfaa9c9c0931f52d9ebf2538bc99700f2e771f3af1c1d93945c2256c11aedd
这与我从 OpenSSL 的 HMAC 实现中获得的结果相匹配。
这是我想出的代码:
/**
* This function takes in a key, the length of that key, a message (null terminated) and a pointer to a char[32] or greater array
* It calculates the HMAC-SHA256 of the given key message combo and returns the resulting code in binary form, 32 hex pairs
1 @example ???? todo function hmac (key, message)
2 if (length(key) > blocksize) then
3 // keys longer than blocksize are shortened
4 key = hash(key)
5 end if
6 if (length(key) < blocksize) then
7 // keys shorter than blocksize are zero-padded
8 key = key ∥ zeroes(blocksize - length(key))
9 end if
10
11 // Where blocksize is that of the underlying hash function
12 o_key_pad = [0x5c * blocksize] ⊕ key
13 i_key_pad = [0x36 * blocksize] ⊕ key // Where ⊕ is exclusive or (XOR)
14 // Where ∥ is concatenation
15 return hash(o_key_pad ∥ hash(i_key_pad ∥ message))
16 end function
* @param key todo
* @param length todo
* @param message todo
* @param hmac todo
*/
void hmac(char key[], int length, char message[], char *hmac){
int msgLen = strlen(message); //get the length of the message to be encrypted
char keyFinal[BLOCK_SIZE] = {0}; //setup array for the data to go into
if(length > BLOCK_SIZE){ //if the given data is too long, hash it
shaHash(key, keyFinal);
}
if(length < BLOCK_SIZE){ //if the given data is too short, pad it with 0x00
int i;
for(i = 0; i < BLOCK_SIZE; i++){
if(i < length){ //read in the data
keyFinal[i] = key[i];
}else{ //if there is no more data to read, read in zeros
keyFinal[i] = 0x00;
}
}
}
if(length == BLOCK_SIZE){ //if the given data is the right size, transfer it to keyFinal
int i;
for(i = 0; i < BLOCK_SIZE; i++){
keyFinal[i] = key[i];
}
}
char oKeyPad[BLOCK_SIZE] = {0}; //setup the oKeyPad
char iKeyPad[BLOCK_SIZE] = {0}; //setup the ikeypad
int i;
for(i = 0; i < BLOCK_SIZE; i++){ //for each item in key final, xor it with O_KEY_PAD and I_KEY_PAD
oKeyPad[i] = keyFinal[i] ^ O_KEY_PAD;
iKeyPad[i] = keyFinal[i] ^ I_KEY_PAD;
}
char iandmesg[BLOCK_SIZE+MAX_SHA]; //setup the inner hash ikeypad concat with message
char hash_iandmesg[HASH_LEN] = {0}; //get ready to get bytes back from the hashing function
//make the message to be hashed, ikeypad concatinated with message
for(i = 0; i < BLOCK_SIZE; i++){ //read in ikeypad
iandmesg[i] = iKeyPad[i];
}
for(i = BLOCK_SIZE; i < (msgLen + BLOCK_SIZE); i++){ //read in message
iandmesg[i] = message[i-BLOCK_SIZE];
}
shaHash_len(iandmesg, (msgLen+BLOCK_SIZE), hash_iandmesg); //create the inner hash (ikeypad + message)
char oandihash[(BLOCK_SIZE + HASH_LEN)]; //setup the outter hash, okeypad + (hash of ikeypad + message)
//make the message to be hashed, okeypad concatinated with the hash of (ikeypad + message)
for(i = 0; i < BLOCK_SIZE; i++){ //read in okeypad
oandihash[i] = oKeyPad[i];
}
for(i = BLOCK_SIZE; i < (BLOCK_SIZE + HASH_LEN); i++){ //read in hash of ikeypad + message
oandihash[i] = hash_iandmesg[i-BLOCK_SIZE];
}
//return the result of the hash of (okeypad + hash(ikeypad + message))
shaHash_len(oandihash, (BLOCK_SIZE + HASH_LEN), hmac);
}
我必须实现自己的 HMAC-SHA256 以便在嵌入式项目中使用。我无法让它工作。我什至不能得到伪代码,手工计算的工作,所以我知道我做错了什么!
我的伪代码计算。按照维基百科中的图表
1 function hmac (key, message)
2 if (length(key) > blocksize) then
3 // keys longer than blocksize are shortened
4 key = hash(key)
5 end if
6 if (length(key) < blocksize) then
7 // keys shorter than blocksize are zero-padded
8 key = key ∥ zeroes(blocksize - length(key))
9 end if
10
11 // Where blocksize is that of the underlying hash function
12 o_key_pad = [0x5c * blocksize] ⊕ key
13 i_key_pad = [0x36 * blocksize] ⊕ key // Where ⊕ is exclusive or (XOR)
14 // Where ∥ is concatenation
15 return hash(o_key_pad ∥ hash(i_key_pad ∥ message))
16 end function
当我对 key="mykey" 和 message="helloworld" 进行手工计算时,我得到以下结果:
key = 0x6d796b6579000000000000000000000000000000000000000000000000000000
o_key_pad = 0x31253739255c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c
i_key_pad = 0x5b4f5d534f363636363636363636363636363636363636363636363636363636
hash(i_key_pad ∥ message) = 6fb2e91de7b8b5ec6283846ff7245cd6eb4a4fd26056b529bd42d99fcf3314d2
和0d76a16089f85cd2169bb64b6f2c818e6a404a218896483fcd97fee5cce185ae
固定key长度和计算内外padding时,需要用到底层hash函数的blocksize,与其[=32]不同=]输出大小。这是函数操作的输入块的大小。在 SHA256 的情况下,块大小为 512 位(64 字节),输出大小为 256 位(32 字节)。
如果您使用 32 作为块大小,您的结果就是您得到的结果。
使用正确的长度 blocksize key
、o_key_pad
和 i_key_pad
基本相同,只有尾随 00
、5c
的两倍长或分别 36
字节。
内部散列的结果(即hash(i_key_pad ∥ message)
是:
8bf029764919f9e35249d0d55ffb8fd6c62fe23a85c1515e0120c5005aa813d5
最终值 (hash(o_key_pad ∥ hash(i_key_pad ∥ message))
) 为:
7fdfaa9c9c0931f52d9ebf2538bc99700f2e771f3af1c1d93945c2256c11aedd
这与我从 OpenSSL 的 HMAC 实现中获得的结果相匹配。
这是我想出的代码:
/**
* This function takes in a key, the length of that key, a message (null terminated) and a pointer to a char[32] or greater array
* It calculates the HMAC-SHA256 of the given key message combo and returns the resulting code in binary form, 32 hex pairs
1 @example ???? todo function hmac (key, message)
2 if (length(key) > blocksize) then
3 // keys longer than blocksize are shortened
4 key = hash(key)
5 end if
6 if (length(key) < blocksize) then
7 // keys shorter than blocksize are zero-padded
8 key = key ∥ zeroes(blocksize - length(key))
9 end if
10
11 // Where blocksize is that of the underlying hash function
12 o_key_pad = [0x5c * blocksize] ⊕ key
13 i_key_pad = [0x36 * blocksize] ⊕ key // Where ⊕ is exclusive or (XOR)
14 // Where ∥ is concatenation
15 return hash(o_key_pad ∥ hash(i_key_pad ∥ message))
16 end function
* @param key todo
* @param length todo
* @param message todo
* @param hmac todo
*/
void hmac(char key[], int length, char message[], char *hmac){
int msgLen = strlen(message); //get the length of the message to be encrypted
char keyFinal[BLOCK_SIZE] = {0}; //setup array for the data to go into
if(length > BLOCK_SIZE){ //if the given data is too long, hash it
shaHash(key, keyFinal);
}
if(length < BLOCK_SIZE){ //if the given data is too short, pad it with 0x00
int i;
for(i = 0; i < BLOCK_SIZE; i++){
if(i < length){ //read in the data
keyFinal[i] = key[i];
}else{ //if there is no more data to read, read in zeros
keyFinal[i] = 0x00;
}
}
}
if(length == BLOCK_SIZE){ //if the given data is the right size, transfer it to keyFinal
int i;
for(i = 0; i < BLOCK_SIZE; i++){
keyFinal[i] = key[i];
}
}
char oKeyPad[BLOCK_SIZE] = {0}; //setup the oKeyPad
char iKeyPad[BLOCK_SIZE] = {0}; //setup the ikeypad
int i;
for(i = 0; i < BLOCK_SIZE; i++){ //for each item in key final, xor it with O_KEY_PAD and I_KEY_PAD
oKeyPad[i] = keyFinal[i] ^ O_KEY_PAD;
iKeyPad[i] = keyFinal[i] ^ I_KEY_PAD;
}
char iandmesg[BLOCK_SIZE+MAX_SHA]; //setup the inner hash ikeypad concat with message
char hash_iandmesg[HASH_LEN] = {0}; //get ready to get bytes back from the hashing function
//make the message to be hashed, ikeypad concatinated with message
for(i = 0; i < BLOCK_SIZE; i++){ //read in ikeypad
iandmesg[i] = iKeyPad[i];
}
for(i = BLOCK_SIZE; i < (msgLen + BLOCK_SIZE); i++){ //read in message
iandmesg[i] = message[i-BLOCK_SIZE];
}
shaHash_len(iandmesg, (msgLen+BLOCK_SIZE), hash_iandmesg); //create the inner hash (ikeypad + message)
char oandihash[(BLOCK_SIZE + HASH_LEN)]; //setup the outter hash, okeypad + (hash of ikeypad + message)
//make the message to be hashed, okeypad concatinated with the hash of (ikeypad + message)
for(i = 0; i < BLOCK_SIZE; i++){ //read in okeypad
oandihash[i] = oKeyPad[i];
}
for(i = BLOCK_SIZE; i < (BLOCK_SIZE + HASH_LEN); i++){ //read in hash of ikeypad + message
oandihash[i] = hash_iandmesg[i-BLOCK_SIZE];
}
//return the result of the hash of (okeypad + hash(ikeypad + message))
shaHash_len(oandihash, (BLOCK_SIZE + HASH_LEN), hmac);
}