Data type problem in encryption algorithm

F

Fernando Barsoba

Hi all,

I very much need your help here guys.. I'm working on a IPSec
implementation, and when almost finished, I found a considerable
problem. I'm sending a particular array + a key to a HMAC-SHA1 function.
I did the tests with the following:

void icv_Calculation_test(char p_output[20]) {
char msgtest[]="what do ya want for nothing?";
char key[]="Jefe";
uint8_t outputsha[20];
int size_message, size_key;
size_message = strlen(msgtest);
size_key = strlen(key);
hmac_sha(key, size_key, msgtest, size_message, outputsha,
sizeof(outputsha));
strcpy(p_output, outputsha);
return;
}

And I got the expected result, as in test case #2 from RFC 2202:
0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79

However, I thought everything was ok until I tried to match different
HMAC calculations (from sender and receiver).. they didn't match and I
then realized I was generating different HMAC calculations every time I
called the function (from sender). I tried then other test cases from
RFC 2202, and then I realized I had problems with the following:

For instance, when trying to obtain the HMAC result for test case #1
which has:

char msgtest[]="Hi There";
and the key is 0x0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B

I'm not sure how to deal with it.. I tried the following:

strtoul().. like this:

char szInput[]="0x0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B";
char * pEnd;
unsigned long ul;
ul = strtoul (szInput,&pEnd,0);

But the HMAC functions from RFC 2202 need keys as strings.. I'm a little
bit confused because I don't know what to do with it.

Bottom line, I'm not getting the expected HMAC calculation when sending
to the function the following, but when using test case #2, which is all
ascii, it works fine..

Below is the code.. It's a little bit long, but I very much need your
help here.. Tell me if you need something else for this to be more clear..

Here i'm trying to show the data types..
..........
typedef struct {
char * message;
char dest_ip[20];
char src_ip[20];
int msg_length;
int port;
char * key;
char algorithm;
} CONF_PARAMS;
.............
uint8_t payload[sizeof(packet) + sizeof(authenHeader_ext)];
uint8_t output[output_size]
...............
icv_Calculation(payload, sizeof(payload), cnf, output, output_size);
..............


void icv_Calculation(char *hdrs, int hdrs_len, CONF_PARAMS *cnf, uint8_t
*output, int output_len) {

if (cnf->algorithm == 's' )
hmac_sha(cnf->key, strlen(cnf->key), hdrs, hdrs_len, output,
sizeof(output));

}

hdrs is where I have my hex values, the message over which the HMAC
calculation works.

Heres the HMAC function, .h and .c

#ifndef HMACSHA1_H_
#define HMACSHA1_H_

#include "sha1.h"


#ifndef SHA_DIGESTSIZE
#define SHA_DIGESTSIZE 20
#endif

#ifndef SHA_BLOCKSIZE
#define SHA_BLOCKSIZE 64
#endif

void pr_sha(FILE*, unsigned char*, int);
void truncate_sha1 (char*, char*, int);
void hmac_sha (char*, int, char*, int, char*, int);

#endif /*HMACSHA1_H_*/
----------------------------------


#include <stdio.h>
#include "sha1.h"
#include "hmac-sha1.h"
/*
* From sha1.h ------------------------
*
* sha1_context;
* void sha1_starts( sha1_context *ctx );
* void sha1_update( sha1_context *ctx, uint8 *input, uint32 length );
* void sha1_finish( sha1_context *ctx, uint8 digest[20] );
*
*/

/* Function to print the digest */
void pr_sha(FILE* fp, unsigned char* s, int t) {
int i;
fprintf(fp, "0x");
for (i = 0 ; i < t ; i++)
fprintf(fp, "%02x", s);
fprintf(fp, "0");
}

void truncate_sha1 (
char* d1, /* data to be truncated */
char* d2, /* truncated data */
int len /* length in bytes to keep */
) {
int i;
for (i=0; i < len; i++)
d2 = d1;
}

/* Function to compute the digest */
void hmac_sha (
char* k, /* secret key */
int lk, /* length of the key in bytes */
char* d, /* data */
int ld, /* length of data in bytes */
char* out, /* output buffer, at least "t" bytes */
int t
) {
sha1_context ictx, octx;
char isha[SHA_DIGESTSIZE], osha[SHA_DIGESTSIZE];
char key[SHA_DIGESTSIZE];
char buf[SHA_BLOCKSIZE];
int i;
if (lk > SHA_BLOCKSIZE) {

sha1_context tctx;

sha1_starts(&tctx);
sha1_update(&tctx, k, lk);
sha1_finish(&tctx, key);

k = key;
lk = SHA_DIGESTSIZE;
}

/**** Inner Digest ****/

sha1_starts(&ictx);

/* Pad the key for inner digest */
for (i = 0 ; i < lk ; ++i)
buf = k ^ 0x36;
for (i = lk ; i < SHA_BLOCKSIZE ; ++i) buf = 0x36;

sha1_update(&ictx, buf, SHA_BLOCKSIZE);
sha1_update(&ictx, d, ld);

sha1_finish(&ictx, isha);

/**** Outter Digest ****/

sha1_starts(&octx);

/* Pad the key for outter digest */

for (i = 0 ; i < lk ; ++i)
buf = k ^ 0x5C;
for (i = lk ; i < SHA_BLOCKSIZE ; ++i)
buf = 0x5C;

sha1_update(&octx, buf, SHA_BLOCKSIZE);
sha1_update(&octx, isha, SHA_DIGESTSIZE);

sha1_finish(&octx, osha);

/* truncate and print the results */
t = t > SHA_DIGESTSIZE ? SHA_DIGESTSIZE : t;
truncate_sha1(osha, out, t);
pr_sha(stdout, out, t);

}

------------------------

And here's the SHA1 function, sorry if this is a long code, but the
problem I guess is in the origin of the function calls..

/*
* FIPS-180-1 compliant SHA-1 implementation
*
* Copyright (C) 2001-2003 Christophe Devine
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA
*/

#include <string.h>

#include "sha1.h"

#define GET_UINT32(n,b,i) \
{ \
(n) = ( (uint32) (b)[(i) ] << 24 ) \
| ( (uint32) (b)[(i) + 1] << 16 ) \
| ( (uint32) (b)[(i) + 2] << 8 ) \
| ( (uint32) (b)[(i) + 3] ); \
}

#define PUT_UINT32(n,b,i) \
{ \
(b)[(i) ] = (uint8) ( (n) >> 24 ); \
(b)[(i) + 1] = (uint8) ( (n) >> 16 ); \
(b)[(i) + 2] = (uint8) ( (n) >> 8 ); \
(b)[(i) + 3] = (uint8) ( (n) ); \
}

void sha1_starts( sha1_context *ctx )
{
ctx->total[0] = 0;
ctx->total[1] = 0;

ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
ctx->state[4] = 0xC3D2E1F0;
}

void sha1_process( sha1_context *ctx, uint8 data[64] )
{
uint32 temp, W[16], A, B, C, D, E;

GET_UINT32( W[0], data, 0 );
GET_UINT32( W[1], data, 4 );
GET_UINT32( W[2], data, 8 );
GET_UINT32( W[3], data, 12 );
GET_UINT32( W[4], data, 16 );
GET_UINT32( W[5], data, 20 );
GET_UINT32( W[6], data, 24 );
GET_UINT32( W[7], data, 28 );
GET_UINT32( W[8], data, 32 );
GET_UINT32( W[9], data, 36 );
GET_UINT32( W[10], data, 40 );
GET_UINT32( W[11], data, 44 );
GET_UINT32( W[12], data, 48 );
GET_UINT32( W[13], data, 52 );
GET_UINT32( W[14], data, 56 );
GET_UINT32( W[15], data, 60 );

#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))

#define R(t) \
( \
temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \
W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \
( W[t & 0x0F] = S(temp,1) ) \
)

#define P(a,b,c,d,e,x) \
{ \
e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \
}

A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
E = ctx->state[4];

#define F(x,y,z) (z ^ (x & (y ^ z)))
#define K 0x5A827999

P( A, B, C, D, E, W[0] );
P( E, A, B, C, D, W[1] );
P( D, E, A, B, C, W[2] );
P( C, D, E, A, B, W[3] );
P( B, C, D, E, A, W[4] );
P( A, B, C, D, E, W[5] );
P( E, A, B, C, D, W[6] );
P( D, E, A, B, C, W[7] );
P( C, D, E, A, B, W[8] );
P( B, C, D, E, A, W[9] );
P( A, B, C, D, E, W[10] );
P( E, A, B, C, D, W[11] );
P( D, E, A, B, C, W[12] );
P( C, D, E, A, B, W[13] );
P( B, C, D, E, A, W[14] );
P( A, B, C, D, E, W[15] );
P( E, A, B, C, D, R(16) );
P( D, E, A, B, C, R(17) );
P( C, D, E, A, B, R(18) );
P( B, C, D, E, A, R(19) );

#undef K
#undef F

#define F(x,y,z) (x ^ y ^ z)
#define K 0x6ED9EBA1

P( A, B, C, D, E, R(20) );
P( E, A, B, C, D, R(21) );
P( D, E, A, B, C, R(22) );
P( C, D, E, A, B, R(23) );
P( B, C, D, E, A, R(24) );
P( A, B, C, D, E, R(25) );
P( E, A, B, C, D, R(26) );
P( D, E, A, B, C, R(27) );
P( C, D, E, A, B, R(28) );
P( B, C, D, E, A, R(29) );
P( A, B, C, D, E, R(30) );
P( E, A, B, C, D, R(31) );
P( D, E, A, B, C, R(32) );
P( C, D, E, A, B, R(33) );
P( B, C, D, E, A, R(34) );
P( A, B, C, D, E, R(35) );
P( E, A, B, C, D, R(36) );
P( D, E, A, B, C, R(37) );
P( C, D, E, A, B, R(38) );
P( B, C, D, E, A, R(39) );

#undef K
#undef F

#define F(x,y,z) ((x & y) | (z & (x | y)))
#define K 0x8F1BBCDC

P( A, B, C, D, E, R(40) );
P( E, A, B, C, D, R(41) );
P( D, E, A, B, C, R(42) );
P( C, D, E, A, B, R(43) );
P( B, C, D, E, A, R(44) );
P( A, B, C, D, E, R(45) );
P( E, A, B, C, D, R(46) );
P( D, E, A, B, C, R(47) );
P( C, D, E, A, B, R(48) );
P( B, C, D, E, A, R(49) );
P( A, B, C, D, E, R(50) );
P( E, A, B, C, D, R(51) );
P( D, E, A, B, C, R(52) );
P( C, D, E, A, B, R(53) );
P( B, C, D, E, A, R(54) );
P( A, B, C, D, E, R(55) );
P( E, A, B, C, D, R(56) );
P( D, E, A, B, C, R(57) );
P( C, D, E, A, B, R(58) );
P( B, C, D, E, A, R(59) );

#undef K
#undef F

#define F(x,y,z) (x ^ y ^ z)
#define K 0xCA62C1D6

P( A, B, C, D, E, R(60) );
P( E, A, B, C, D, R(61) );
P( D, E, A, B, C, R(62) );
P( C, D, E, A, B, R(63) );
P( B, C, D, E, A, R(64) );
P( A, B, C, D, E, R(65) );
P( E, A, B, C, D, R(66) );
P( D, E, A, B, C, R(67) );
P( C, D, E, A, B, R(68) );
P( B, C, D, E, A, R(69) );
P( A, B, C, D, E, R(70) );
P( E, A, B, C, D, R(71) );
P( D, E, A, B, C, R(72) );
P( C, D, E, A, B, R(73) );
P( B, C, D, E, A, R(74) );
P( A, B, C, D, E, R(75) );
P( E, A, B, C, D, R(76) );
P( D, E, A, B, C, R(77) );
P( C, D, E, A, B, R(78) );
P( B, C, D, E, A, R(79) );

#undef K
#undef F

ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
ctx->state[4] += E;
}

void sha1_update( sha1_context *ctx, uint8 *input, uint32 length )
{
uint32 left, fill;

if( ! length ) return;

left = ctx->total[0] & 0x3F;
fill = 64 - left;

ctx->total[0] += length;
ctx->total[0] &= 0xFFFFFFFF;

if( ctx->total[0] < length )
ctx->total[1]++;

if( left && length >= fill )
{
memcpy( (void *) (ctx->buffer + left),
(void *) input, fill );
sha1_process( ctx, ctx->buffer );
length -= fill;
input += fill;
left = 0;
}

while( length >= 64 )
{
sha1_process( ctx, input );
length -= 64;
input += 64;
}

if( length )
{
memcpy( (void *) (ctx->buffer + left),
(void *) input, length );
}
}

static uint8 sha1_padding[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

void sha1_finish( sha1_context *ctx, uint8 digest[20] )
{
uint32 last, padn;
uint32 high, low;
uint8 msglen[8];

high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );

PUT_UINT32( high, msglen, 0 );
PUT_UINT32( low, msglen, 4 );

last = ctx->total[0] & 0x3F;
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );

sha1_update( ctx, sha1_padding, padn );
sha1_update( ctx, msglen, 8 );

PUT_UINT32( ctx->state[0], digest, 0 );
PUT_UINT32( ctx->state[1], digest, 4 );
PUT_UINT32( ctx->state[2], digest, 8 );
PUT_UINT32( ctx->state[3], digest, 12 );
PUT_UINT32( ctx->state[4], digest, 16 );
}


FBM
 
S

Skarmander

Fernando said:
Hi all,

I very much need your help here guys.. I'm working on a IPSec
implementation, and when almost finished, I found a considerable
problem. I'm sending a particular array + a key to a HMAC-SHA1 function.
I did the tests with the following:

void icv_Calculation_test(char p_output[20]) {
char msgtest[]="what do ya want for nothing?";
char key[]="Jefe";
uint8_t outputsha[20];
int size_message, size_key;
size_message = strlen(msgtest);
size_key = strlen(key);
hmac_sha(key, size_key, msgtest, size_message, outputsha,
sizeof(outputsha));
strcpy(p_output, outputsha);
return;
}

And I got the expected result, as in test case #2 from RFC 2202:
0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79

However, I thought everything was ok until I tried to match different
HMAC calculations (from sender and receiver).. they didn't match and I
then realized I was generating different HMAC calculations every time I
called the function (from sender). I tried then other test cases from
RFC 2202, and then I realized I had problems with the following:

For instance, when trying to obtain the HMAC result for test case #1
which has:

char msgtest[]="Hi There";
and the key is 0x0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B

I'm not sure how to deal with it.. I tried the following:

strtoul().. like this:

<snip>

Forget strtoul(), this is too long for a long. You need to convert this
hexstring to an actual sequence of bytes. See if you have a library
function somewhere to do this.

If not, here's an example implementation I whipped up in a few seconds
(so don't trust it, and don't count on it being fast):

#include <stdlib.h>
#include <string.h>

/* Convert the single hexadecimal digit 'c' to the corresponding
integer, or -1 if 'c' is not a hex digit. */
int hexdigit_to_int(char c) {
if (c >= '0' && c <= '9') return c - '0';
switch (c) {
case 'a': case 'A': return 10;
case 'b': case 'B': return 11;
case 'c': case 'C': return 12;
case 'd': case 'D': return 13;
case 'e': case 'E': return 14;
case 'f': case 'F': return 15;
default: {
return -1;
}
}
}

/* Convert the hexadecimal representation of a sequence of bytes to
the sequence of bytes. */
/* Returns a malloc()-allocated block of strlen(hex) / 2 bytes if
successful or a null pointer otherwise. */
unsigned char* hexstr_to_bytes(const char* hex) {
size_t l = strlen(hex);
size_t n = 0;
unsigned char* result;
if (l % 2 != 0) return NULL;

result = malloc(l / 2);
if (!result) return NULL;

while (n < l) {
int d1 = hexdigit_to_int(hex[n]) * 16;
int d2 = hexdigit_to_int(hex[n + 1]);
if (d1 == -1 || d2 == -1) {
free(result);
return NULL;
}
result[n / 2] = d1 + d2;
n += 2;
}
return result;
}

Keep in mind that the input string must not begin with "0x", that you
must free() the result and that it is *not* a null-terminated string but
a sequence of bytes of a length you must keep track of yourself, so no
calling strlen() on it.

S.
 
F

Fernando Barsoba

Skarmander said:
Fernando said:
Hi all,

I very much need your help here guys.. I'm working on a IPSec
implementation, and when almost finished, I found a considerable
problem. I'm sending a particular array + a key to a HMAC-SHA1
function. I did the tests with the following:

void icv_Calculation_test(char p_output[20]) {
char msgtest[]="what do ya want for nothing?";
char key[]="Jefe";
uint8_t outputsha[20];
int size_message, size_key;
size_message = strlen(msgtest);
size_key = strlen(key);
hmac_sha(key, size_key, msgtest, size_message, outputsha,
sizeof(outputsha));
strcpy(p_output, outputsha);
return;
}

And I got the expected result, as in test case #2 from RFC 2202:
0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79

However, I thought everything was ok until I tried to match different
HMAC calculations (from sender and receiver).. they didn't match and I
then realized I was generating different HMAC calculations every time
I called the function (from sender). I tried then other test cases
from RFC 2202, and then I realized I had problems with the following:

For instance, when trying to obtain the HMAC result for test case #1
which has:

char msgtest[]="Hi There";
and the key is 0x0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B

I'm not sure how to deal with it.. I tried the following:

strtoul().. like this:

<snip>

Forget strtoul(), this is too long for a long. You need to convert this
hexstring to an actual sequence of bytes. See if you have a library
function somewhere to do this.

If not, here's an example implementation I whipped up in a few seconds
(so don't trust it, and don't count on it being fast):

#include <stdlib.h>
#include <string.h>
Thanks a lot, I'll try this.. however, what is the concept behind the
problem I'm having? I mean, why when I try to obtain a message digest of
a particular 'string' message and particular 'string' key the function
works (message digest is always the same), and it doesn't when I try the
same with identical string key, but a different 'string' message? The
only difference between those messages is that with the latter the hex
content is what is important to me.. I mean, instead of having:

char msgtest[]="what do ya want for nothing?";
char key[]="Jefe";

I have a char * whose hex content is what matters to me..

thanks,

FBM
 
S

Skarmander

Fernando said:
Skarmander said:
Fernando said:
Hi all,

I very much need your help here guys.. I'm working on a IPSec
implementation, and when almost finished, I found a considerable
problem. I'm sending a particular array + a key to a HMAC-SHA1
function. I did the tests with the following:

void icv_Calculation_test(char p_output[20]) {
char msgtest[]="what do ya want for nothing?";
char key[]="Jefe";
uint8_t outputsha[20];
int size_message, size_key;
size_message = strlen(msgtest);
size_key = strlen(key);
hmac_sha(key, size_key, msgtest, size_message, outputsha,
sizeof(outputsha));
strcpy(p_output, outputsha);
return;
}

And I got the expected result, as in test case #2 from RFC 2202:
0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79
For instance, when trying to obtain the HMAC result for test case #1
which has:

char msgtest[]="Hi There";
and the key is 0x0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B
I mean, why when I try to obtain a message digest of
a particular 'string' message and particular 'string' key the function
works (message digest is always the same), and it doesn't when I try the
same with identical string key, but a different 'string' message? The
only difference between those messages is that with the latter the hex
content is what is important to me.. I mean, instead of having:

char msgtest[]="what do ya want for nothing?";
char key[]="Jefe";

I have a char * whose hex content is what matters to me..

The SHA function (apparently) expects a key that is a sequence of bytes.
As it so happens, "Jefe" is a sequence of bytes: assuming your system
uses an ASCII-compatible character set, the sequence can be represented
in hexadecimal as 0x4A65666500.

This is why passing a string to the function "just works": a string is
already a sequence of bytes. In the second example (key = 0x0b0b0b...)
you want to pass an actual byte sequence represented as a string of
hexadecimal digits, not the string "0x0b0b0b...", which is something
completely different.

S.
 
F

Flash Gordon

Skarmander said:
Fernando Barsoba wrote:
char msgtest[]="Hi There";
and the key is 0x0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B

I'm not sure how to deal with it.. I tried the following:

strtoul().. like this:

<snip>

Forget strtoul(), this is too long for a long.

True, and good advice.
> You need to convert this
hexstring to an actual sequence of bytes. See if you have a library
function somewhere to do this.

Be aware that any such library function is non-standard and may not be
available on all platforms.
If not, here's an example implementation I whipped up in a few seconds
(so don't trust it, and don't count on it being fast):

Some suggested improvements/simplifications/things to make it easier to
read.
#include <stdlib.h>
#include <string.h>
/* Convert the single hexadecimal digit 'c' to the corresponding
integer, or -1 if 'c' is not a hex digit. */
int hexdigit_to_int(char c) {
int hexdigit_to_int(const unsigned char) {

so I don't have to cast to unsigned char later.
if (c >= '0' && c <= '9') return c - '0';
if (isdigit(c)) return c - '0';
Yours was correct, but I think mine is easier to read.
switch (c) {
switch (isupper(c)) {
case 'A': return 10;
and so on.
case 'a': case 'A': return 10;
case 'b': case 'B': return 11;
case 'c': case 'C': return 12;
case 'd': case 'D': return 13;
case 'e': case 'E': return 14;
case 'f': case 'F': return 15;
default: {
return -1;
}
}
}

Or the following:
int hexdigit_to_int(const char c) {
char t[] = { c, '\0' };
int res = strcspn("0123456789ABCDEF",
isupper((unsigned char)c);
return (res>15)?-1:res;
}
/* Convert the hexadecimal representation of a sequence of bytes to
the sequence of bytes. */
/* Returns a malloc()-allocated block of strlen(hex) / 2 bytes if
successful or a null pointer otherwise. */
unsigned char* hexstr_to_bytes(const char* hex) {
size_t l = strlen(hex);

Using l as a variable name is not a good idea. I initialy misread some
instances of it below as 1 and wondered what you were up to.
size_t n = 0;
unsigned char* result;
if (l % 2 != 0) return NULL;

result = malloc(l / 2);
if (!result) return NULL;

while (n < l) {
int d1 = hexdigit_to_int(hex[n]) * 16;
int d2 = hexdigit_to_int(hex[n + 1]);
if (d1 == -1 || d2 == -1) {
Oops. Last I checked -1*16 was not -1 ! ;-)
free(result);
return NULL;
}
result[n / 2] = d1 + d2;
n += 2;
}

I would be more likely to do something like:
for (n = 0; n < l; n += 2) {
int d1 = hexdigit_to_int(hex[n]);
int d2 = hexdigit_to_int(hex[n+1]);
if (d1 < 0 || d2 < 0) {
free(result);
return NULL;
}
result[n/2] = (d1 << 4) + d2;
}
return result;
}

Keep in mind that the input string must not begin with "0x", that you
must free() the result and that it is *not* a null-terminated string but
a sequence of bytes of a length you must keep track of yourself, so no
calling strlen() on it.

All good points.
 
F

Fernando Barsoba

Skarmander said:
Fernando said:
Skarmander said:
Fernando Barsoba wrote:

Hi all,

I very much need your help here guys.. I'm working on a IPSec
implementation, and when almost finished, I found a considerable
problem. I'm sending a particular array + a key to a HMAC-SHA1
function. I did the tests with the following:

void icv_Calculation_test(char p_output[20]) {
char msgtest[]="what do ya want for nothing?";
char key[]="Jefe";
uint8_t outputsha[20];
int size_message, size_key;
size_message = strlen(msgtest);
size_key = strlen(key);
hmac_sha(key, size_key, msgtest, size_message, outputsha,
sizeof(outputsha));
strcpy(p_output, outputsha);
return;
}

And I got the expected result, as in test case #2 from RFC 2202:
0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79
For instance, when trying to obtain the HMAC result for test case #1
which has:

char msgtest[]="Hi There";
and the key is 0x0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B
I mean, why when I try to obtain a message digest of a particular
'string' message and particular 'string' key the function works
(message digest is always the same), and it doesn't when I try the
same with identical string key, but a different 'string' message? The
only difference between those messages is that with the latter the hex
content is what is important to me.. I mean, instead of having:

char msgtest[]="what do ya want for nothing?";
char key[]="Jefe";

I have a char * whose hex content is what matters to me..

The SHA function (apparently) expects a key that is a sequence of bytes.
As it so happens, "Jefe" is a sequence of bytes: assuming your system
uses an ASCII-compatible character set, the sequence can be represented
in hexadecimal as 0x4A65666500.

This is why passing a string to the function "just works": a string is
already a sequence of bytes. In the second example (key = 0x0b0b0b...)
you want to pass an actual byte sequence represented as a string of
hexadecimal digits, not the string "0x0b0b0b...", which is something
completely different.

S.
Thanks... I think I mixed two different things in my explanation.. The
test with the key=0x0b0b0b is something I tried later on.. and then I
realized I didn't know how to deal with hex keys.. however, my first
problem came when I found that I was generating different digests even
though I was using the same info... THAT doesn't happen with the example
above, and I always get the same hex string (key="Jefe" message="what do
you want.." But it is happening with key="Jefe" but message being a
char* instead of a char message[]="what do you..."

Any idea why is that..? This is the core of my problem. For the key, I
may want to use hex keys or I may not.. but the other problem is critical..

Thanks again for you *extended* help!

FBM
 
S

Skarmander

Flash said:
Be aware that any such library function is non-standard and may not be
available on all platforms.
Yes, the implication was that this function could be part of his SHA
library (not his C library). Seems like a common enough thing to want in
this case.
If not, here's an example implementation I whipped up in a few seconds
(so don't trust it, and don't count on it being fast):

Some suggested improvements/simplifications/things to make it easier to
read.
while (n < l) {
int d1 = hexdigit_to_int(hex[n]) * 16;
int d2 = hexdigit_to_int(hex[n + 1]);
if (d1 == -1 || d2 == -1) {

Oops. Last I checked -1*16 was not -1 ! ;-)
That thing where I said it shouldn't be trusted? Yeah, that's this. :)

for (n = 0; n < l; n += 2) {
int d1 = hexdigit_to_int(hex[n]);
int d2 = hexdigit_to_int(hex[n+1]);
if (d1 < 0 || d2 < 0) {
free(result);
return NULL;
}
result[n/2] = (d1 << 4) + d2;

I've switched away from bit-shifting lately to using multiplication,
unless I'm really working with bits. In this case I'm not. Your version
is a tad inconsistent conceptually: why + and not | if you use <<
instead of *?

S.
 
S

Skarmander

Fernando said:
Skarmander said:
Fernando said:
Skarmander wrote:

Fernando Barsoba wrote:

Hi all,

I very much need your help here guys.. I'm working on a IPSec
implementation, and when almost finished, I found a considerable
problem. I'm sending a particular array + a key to a HMAC-SHA1
function. I did the tests with the following:

void icv_Calculation_test(char p_output[20]) {
char msgtest[]="what do ya want for nothing?";
char key[]="Jefe";
uint8_t outputsha[20];
int size_message, size_key;
size_message = strlen(msgtest);
size_key = strlen(key);
hmac_sha(key, size_key, msgtest, size_message, outputsha,
sizeof(outputsha));
strcpy(p_output, outputsha);
return;
}

And I got the expected result, as in test case #2 from RFC 2202:
0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79
<snip>
however, my first problem came when I found that I was generating
different digests even though I was using the same info... THAT
doesn't happen with the example above, and I always get the same hex
string (key="Jefe" message="what do you want.." But it is happening
with key="Jefe" but message being a char* instead of a char
message[]="what do you..."

Any idea why is that..? This is the core of my problem. For the key,
I may want to use hex keys or I may not.. but the other problem is
critical..
There is no conceptual difference when passing a char* instead of a
char[] to a function, so my only guess is that your call is incorrect.

Are you certain the char* is a string, for example? If, like in the
example above, it's a byte sequence, there is no terminator character,
and calling strlen() will simply not work; you must keep track of the
key length explicitly.

S.
 
S

Skarmander

Skarmander wrote:
Are you certain the char* is a string, for example? If, like in the
example above [..]

That should be "upthread". I snipped a little too enthusiastically.

S.
 
F

Flash Gordon

Skarmander said:
Flash said:
Skarmander wrote:
result[n/2] = (d1 << 4) + d2;

I've switched away from bit-shifting lately to using multiplication,
unless I'm really working with bits.

I consider this to be a case of working with bits. Although looking at
it as multiplication is equally valid.
> In this case I'm not. Your version
is a tad inconsistent conceptually: why + and not | if you use <<
instead of *?

Because having shifted it to the right place you can just add the bits
together? ;-)
 
R

Roman Mashak

Hello, Flash!
You wrote on Fri, 25 Nov 2005 20:47:50 +0000:

[skip]
??>> if (c >= '0' && c <= '9') return c - '0';
FG> if (isdigit(c)) return c - '0';
FG> Yours was correct, but I think mine is easier to read.

??>> switch (c) {
FG> switch (isupper(c)) {
isupper() returns non-zero or zero, so this snippet is wrong, I suppose

FG> case 'A': return 10;

With best regards, Roman Mashak. E-mail: (e-mail address removed)
 
F

Flash Gordon

Roman said:
Hello, Flash!
You wrote on Fri, 25 Nov 2005 20:47:50 +0000:

[skip]
??>> if (c >= '0' && c <= '9') return c - '0';
FG> if (isdigit(c)) return c - '0';
FG> Yours was correct, but I think mine is easier to read.

??>> switch (c) {
FG> switch (isupper(c)) {
isupper() returns non-zero or zero, so this snippet is wrong, I suppose

I meant toupper.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top