HMAC-SHA256 written in C with OpenSSL 0.9.8k
#include <openssl/x509.h> | |
#include <openssl/hmac.h> | |
void | |
hmac_sha256( | |
const unsigned char *text, /* pointer to data stream */ | |
int text_len, /* length of data stream */ | |
const unsigned char *key, /* pointer to authentication key */ | |
int key_len, /* length of authentication key */ | |
void *digest) /* caller digest to be filled in */ | |
{ | |
unsigned char k_ipad[65]; /* inner padding - | |
* key XORd with ipad | |
*/ | |
unsigned char k_opad[65]; /* outer padding - | |
* key XORd with opad | |
*/ | |
unsigned char tk[SHA256_DIGEST_LENGTH]; | |
unsigned char tk2[SHA256_DIGEST_LENGTH]; | |
unsigned char bufferIn[1024]; | |
unsigned char bufferOut[1024]; | |
int i; | |
/* if key is longer than 64 bytes reset it to key=sha256(key) */ | |
if ( key_len > 64 ) { | |
SHA256( key, key_len, tk ); | |
key = tk; | |
key_len = SHA256_DIGEST_LENGTH; | |
} | |
/* | |
* the HMAC_SHA256 transform looks like: | |
* | |
* SHA256(K XOR opad, SHA256(K XOR ipad, text)) | |
* | |
* where K is an n byte key | |
* ipad is the byte 0x36 repeated 64 times | |
* opad is the byte 0x5c repeated 64 times | |
* and text is the data being protected | |
*/ | |
/* start out by storing key in pads */ | |
memset( k_ipad, 0, sizeof k_ipad ); | |
memset( k_opad, 0, sizeof k_opad ); | |
memcpy( k_ipad, key, key_len ); | |
memcpy( k_opad, key, key_len ); | |
/* XOR key with ipad and opad values */ | |
for ( i = 0; i < 64; i++ ) { | |
k_ipad[i] ^= 0x36; | |
k_opad[i] ^= 0x5c; | |
} | |
/* | |
* perform inner SHA256 | |
*/ | |
memset( bufferIn, 0x00, 1024 ); | |
memcpy( bufferIn, k_ipad, 64 ); | |
memcpy( bufferIn + 64, text, text_len ); | |
SHA256( bufferIn, 64 + text_len, tk2 ); | |
/* | |
* perform outer SHA256 | |
*/ | |
memset( bufferOut, 0x00, 1024 ); | |
memcpy( bufferOut, k_opad, 64 ); | |
memcpy( bufferOut + 64, tk2, SHA256_DIGEST_LENGTH ); | |
SHA256( bufferOut, 64 + SHA256_DIGEST_LENGTH, digest ); | |
} | |
#ifdef TEST | |
void | |
printdump( const char *buffer, size_t sz ) | |
{ | |
int i, c; | |
unsigned char buf[80]; | |
for ( i = 0; (unsigned)i < sz; i++ ) { | |
if ( (i != 0) && (i % 16 == 0) ) { | |
buf[16] = NUL; | |
fprintf( stderr, " %s\n", buf ); | |
} | |
if ( i % 16 == 0 ) | |
fprintf( stderr, "%08x:", &buffer[i] ); | |
c = buffer[i] & 0xFF; | |
if ( (c >= ' ') && (c <= 0x7E) ) | |
buf[i % 16] = (unsigned char)c; | |
else | |
buf[i % 16] = '.'; | |
fprintf( stderr, " %02x", c & 0xFF ); | |
} | |
if ( i % 16 == 0 ) | |
buf[16] = NUL; | |
else { | |
buf[i % 16] = NUL; | |
for ( i = i % 16; i < 16; i++ ) | |
fputs( " ", stderr ); | |
} | |
fprintf( stderr, " %s\n", buf ); | |
} | |
static char b[] = | |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
/* 0000000000111111111122222222223333333333444444444455555555556666 */ | |
/* 0123456789012345678901234567890123456789012345678901234567890123 */ | |
char * | |
base64( const unsigned char *src, size_t sz ) | |
{ | |
unsigned char *pp, *p, *q; | |
Thread static unsigned char *qq = NULL; | |
size_t i, safe = sz; | |
if ( qq ) { | |
free( qq ); | |
qq = NULL; | |
} | |
if ( !src || (sz == 0) ) | |
return ( NULL ); | |
if ( (sz % 3) == 1 ) { | |
p = (unsigned char *)malloc( sz + 2 ); | |
if ( !p ) | |
return ( NULL ); | |
memcpy( p, src, sz ); | |
p[sz] = p[sz + 1] = '='; | |
sz += 2; | |
} | |
else if ( (sz % 3) == 2 ) { | |
p = (unsigned char *)malloc( sz + 1 ); | |
if ( !p ) | |
return ( NULL ); | |
memcpy( p, src, sz ); | |
p[sz] = '='; | |
sz++; | |
} | |
else | |
p = (unsigned char *)src; | |
q = (unsigned char *)malloc( (sz / 3) * 4 + 2 ); | |
if ( !q ) { | |
if ( p != src ) | |
free( p ); | |
return ( NULL ); | |
} | |
pp = p; | |
qq = q; | |
for ( i = 0; i < sz; i += 3 ) { | |
q[0] = b[(p[0] & 0xFC) >> 2]; | |
q[1] = b[((p[0] & 0x03) << 4) | ((p[1] & 0xF0) >> 4)]; | |
q[2] = b[((p[1] & 0x0F) << 2) | ((p[2] & 0xC0) >> 6)]; | |
q[3] = b[p[2] & 0x3F]; | |
p += 3; | |
q += 4; | |
} | |
*q = NUL; | |
if ( (safe % 3) == 1 ) { | |
*(q - 1) = '='; | |
*(q - 2) = '='; | |
} | |
if ( (safe % 3) == 2 ) | |
*(q - 1) = '='; | |
if ( pp != src ) | |
free( pp ); | |
return ( (char *)qq ); | |
} | |
int | |
main( int argc, char *argv[] ) | |
{ | |
// via http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?rest-signature.html | |
// see also: | |
// http://chalow.net/2009-05-09-1.html | |
// http://d.hatena.ne.jp/zorio/20090509/1241886502 | |
char *p; | |
const char *key = "1234567890"; | |
char req[2048]; | |
char message[10240]; | |
char digest[BUFSIZ]; | |
sprintf( req, | |
"AWSAccessKeyId=%s&" | |
"ItemId=%s&" | |
"Operation=%s&" | |
"ResponseGroup=%s&" | |
"Service=%s&" | |
"Timestamp=%s&" | |
"Version=%s", | |
"00000000000000000000", | |
"0679722769", | |
"ItemLookup", | |
"ItemAttributes%2COffers%2CImages%2CReviews", | |
"AWSECommerceService", | |
"2009-01-01T12%3A00%3A00Z", | |
"2009-01-06" ); | |
sprintf( message, | |
"%s\n" | |
"%s\n" | |
"%s\n" | |
"%s", | |
"GET", | |
"webservices.amazon.com", | |
"/onca/xml", | |
req ); | |
memset( digest, 0x00, BUFSIZ ); | |
hmac_sha256( message, strlen(message), key, strlen(key), digest ); | |
printdump( digest, BUFSIZ ); | |
{ int c; fputs( ": ", stderr ); c = getchar(); } | |
// 35 a7 1e f9 4d c0 cf 83 a1 37 bb 48 4a a8 2c d6 | |
// f7 4b 04 70 44 8a 35 9c 05 e0 aa 2f 9c 4d f7 18 | |
p = base64( digest, SHA256_DIGEST_LENGTH ); | |
if ( p ) | |
printf( "RESULT: %s\n", p ); | |
{ int c; fputs( ": ", stderr ); c = getchar(); } | |
// RESULT: Nace+U3Az4OhN7tISqgs1vdLBHBEijWcBeCqL5xN9xg= | |
/* | |
// via http://stackoverflow.com/questions/699041/hmacsha256-in-php-and-c-differ | |
string password = "Password"; | |
string filename = "Filename"; | |
var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(password)); | |
hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(filename)); | |
foreach(byte test in hmacsha256.Hash){ | |
Console.Write(test.ToString("X2")); | |
} | |
// 5FE2AE06FF9828B33FE304545289A3F590BFD948CA9AB731C980379992EF41F1 | |
*/ | |
key = "Password"; | |
sprintf( message, "Filename" ); | |
memset( digest, 0x00, BUFSIZ ); | |
hmac_sha256( message, strlen(message), key, strlen(key), digest ); | |
printdump( digest, BUFSIZ ); | |
{ int c; fputs( ": ", stderr ); c = getchar(); } | |
// 5f e2 ae 06 ff 98 28 b3 3f e3 04 54 52 89 a3 f5 | |
// 90 bf d9 48 ca 9a b7 31 c9 80 37 99 92 ef 41 f1 | |
p = base64( digest, SHA256_DIGEST_LENGTH ); | |
if ( p ) | |
printf( "RESULT: %s\n", p ); | |
{ int c; fputs( ": ", stderr ); c = getchar(); } | |
// X+KuBv+YKLM/4wRUUomj9ZC/2UjKmrcxyYA3mZLvQfE= | |
} | |
#endif |
This comment has been minimized.
This comment has been minimized.
comment afte test! |
This comment has been minimized.
This comment has been minimized.
comment afte test! |
This comment has been minimized.
This comment has been minimized.
What is the value of BUFSIZ? |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
Somehow the OpenSSL HMAC(EVP_sha256(), does not produce the same hmac for Keys that are longer than SHA256 key len.Your function creates a new SHA256 hash if the key is longer than 32 bytes. The hmac both functions then produce are different.
nevermind: I had the message and key args mixed up.