problem with encryption function sending hex values

F

Fernando Barsoba

Dear all,

I have been posting about a problem trying to encrypt certain data using
HMAC-SHA1 functions. I posted that my problem was solved, but
unfortunately, I was being overly optimistic. I am really desperate now,
because I havent' been able to locate the origin of the problem for a
couple of days now..

PROBLEM: the message digest obtained differs each time I execute the
code, but works perfectly when applying the "control", that is the test
case #3 from RFC 2202 that I show below.

I did my best trying to create a code that can be compiled and executed
and that clearly shows the problem. I would really appreciate any help,
I have to finish this project in a couple of days and I have been stuck
here for a long while..

Explanation of functions:
- I send an array over a function that obtains a message digest applying
hmac-sha1. This authentication function requires a message and a key.
The message simulates and IP header of lenght=31 (I hardcoded the value
for clarity).
- The 'build_ip_packet' function does bit manipulatation therefore the
final message is just gibberish, but their hexadecimal content is valid
and represents the ip packet.
- I treat the message with the function 'hexString_to_hexRepresent'
because I thought that this translation had to be made (hex to its hex
representation)
- Finally, 'icv_Calculation' performs the message digest calculation.
- 'icv_Calculation_test' uses the same function but sends to it the test
case #3 from RFC 2202
- 'pr_hexstring' prints out the result.

RFC 2202 has different test cases. #3 is the following:
test_case = 3
key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
key_len = 20
data = 0xdd repeated 50 times
data_len = 50
digest = 0x125d7342b9ac11cd91a39af48aa17b4f63f175d3

http://www.zvon.org/tmRFC/RFC2202/Output/index.html

As you can see executing the program, I get the correct result in my
second icv call. However, the first call shows completely different
results each time I call it. Why is that?

output:
$ ./icv_test.exe
0xf28b25b3793ff29a248932ebe8fa6114934be0f2
0x125d7342b9ac11cd91a39af48aa17b4f63f175d3

Again, thank you in advance for any help that you can provide me.

I attach the complete code. It's a lot, but if someone wants to try,
they are complementary functions that are needed but they are not the
origin of the problem. 'main' and first level functions is where the
core of the problem may be.

You may find string conversions which may not have much sense.. i
apologize for that, I can't think clearly anymore.. :-(

Fernando

-------------------------- main.c ----------------
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <arpa/inet.h> /* inet(3) functions */
#include <errno.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/ip.h>
#include <sys/types.h>

#include "hmac-sha1.h"


#define HEADER_OFFSET 20
#define IP_VERSION 4

typedef struct {
char * message;
char dest_ip[20];
char src_ip[20];
int msg_length;
int port;
char * key;
char algorithm;
} CONF_PARAMS;

void build_ip_packet(unsigned char *packet, unsigned short length,
CONF_PARAMS *cnf) {
struct ip *iphdr;
int packet_size;

struct in_addr ipsrc_addr, ipdst_addr; /* 'in_addr' structures needed
to change byte ordering */

packet_size = sizeof(struct ip) + cnf->msg_length; /* obtain size
for datagram */

bzero(packet, packet_size); /* fills with 0; deprecated, change
with memset */
iphdr = (struct ip *)packet; /* assign ip header structure to our
IP packet */

inet_aton(cnf->src_ip, &ipsrc_addr);
inet_aton(cnf->dest_ip, &ipdst_addr);

/* IP header construction */
iphdr->ip_v = IP_VERSION; /* version = 4, IP */
iphdr->ip_hl = 5; /* length = 5, no option */
iphdr->ip_tos = 0;
iphdr->ip_len = htons(length); /* length of the datagram */
iphdr->ip_id = htons(getpid()); /* identification for this packet,
assigned process id */
iphdr->ip_off = 0;
iphdr->ip_ttl = 64; /* time to live = 64 */
iphdr->ip_p = 51; /* protocol number = 51, AH code */
iphdr->ip_src = ipsrc_addr;
iphdr->ip_dst = ipdst_addr;
iphdr->ip_sum = 0;

// iphdr->ip_sum = in_cksum((u_short *) iphdr, (iphdr->ip_hl) << 2);
/* calculate checksum */

memcpy(packet + HEADER_OFFSET, cnf->message, cnf->msg_length); /* copy
data to end ip packet, which is
20 bytes by default. If options included,
this value has to be changed */
return;
}

/* 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;

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;
}


unsigned char* hexString_to_hexRepresent(const char *payload, const char
*hexvalue, int payload_size, int output_size) {
int ii, tt=payload_size;
unsigned char hexvalue2[payload_size*2];
memcpy(hexvalue2, hexvalue, payload_size*2);
for (ii = 0 ; ii < tt ; ii++)
sprintf(hexvalue2+(ii*2), "%02x", payload[ii]);
unsigned char *msgICV;
msgICV = hexstr_to_bytes(hexvalue2);
return msgICV;
}

void icv_Calculation_test(char p_output[20]) {
uint8_t
tmp_msgtest[]="DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD";
char tmp_key[]="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
unsigned char* key, *msgtest;
key = hexstr_to_bytes(tmp_key);
msgtest = hexstr_to_bytes(tmp_msgtest);
uint8_t outputsha[20];

int size_message, size_key;
size_message = strlen(msgtest);
size_key = strlen(key)-1;

hmac_sha(key, size_key, msgtest, size_message, outputsha,
sizeof(outputsha));
strcpy(p_output, outputsha);
free(key);
free(msgtest);
return;
}

unsigned char * icv_Calculation(unsigned char *hdrs, int hdrs_len,
CONF_PARAMS *cnf, uint8_t *output, int output_len) {
unsigned char outputshax[20];
unsigned char payloadh[hdrs_len];
memcpy(payloadh, hdrs, hdrs_len);

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

unsigned char * ret_output=malloc(20);
memcpy(ret_output, outputshax, 20);
return ret_output;
}


/* Function to print strings in hex */
void pr_hexstring(FILE* fp, unsigned char* s, int t) {
int i;
fprintf(fp, "0x");
for (i = 0 ; i < t ; i++) {
fprintf(fp, "%02x", s);
}
fprintf(fp, "\n");
}



int main(int argc, char **argv) {
CONF_PARAMS * cnf;
cnf = malloc(sizeof(*cnf));

cnf->message = "hello world";
cnf->key = "Jefe";
strcpy(cnf->dest_ip, "192.168.2.2");
strcpy(cnf->src_ip, "192.168.2.2");
cnf->msg_length = strlen(cnf->message);
cnf->algorithm='s';

unsigned char packet[31];
build_ip_packet(packet, sizeof(packet), cnf);

unsigned char m_output[20];
unsigned char d_packet[sizeof(packet)*2];
unsigned char * p_icv = hexString_to_hexRepresent(packet, d_packet ,
sizeof(packet), strlen(m_output));

unsigned char *ret_output = icv_Calculation(p_icv, 31, cnf, m_output, 20);

pr_hexstring(stdout, ret_output, 20);

char p_output_sha[20];
icv_Calculation_test(p_output_sha);

pr_hexstring(stdout, p_output_sha, 20);

free(ret_output);
free(p_icv);
free(cnf);
exit(0);
}


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

---------------------- hmac-sha1.h ----------------------------

#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 (uint8_t*, uint8_t*, int);
void hmac_sha (uint8_t*, int, uint8_t*, int, uint8_t*, int);

#endif /*HMACSHA1_H_*/

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


---------------------- hmac-sha1.c ----------------------------
#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 (
uint8_t* d1, /* data to be truncated */
uint8_t* 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 (
uint8_t* k, /* secret key */
int lk, /* length of the key in bytes */
uint8_t* d, /* data */
int ld, /* length of data in bytes */
uint8_t* out, /* output buffer, at least "t" bytes */
int t
) {
sha1_context ictx, octx;
uint8_t isha[SHA_DIGESTSIZE], osha[SHA_DIGESTSIZE];
uint8_t key[SHA_DIGESTSIZE];
uint8_t 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);


}

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

---------------------- sha1.h ----------------------------

#ifndef _SHA1_H
#define _SHA1_H

#ifndef uint8
#define uint8 unsigned char
#endif

#ifndef uint32
#define uint32 unsigned long int
#endif

typedef struct
{
uint32 total[2];
uint32 state[5];
uint8 buffer[64];
}
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] );

#endif /* sha1.h */

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

---------------------- sha1.c ----------------------------

/*
* 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 );
}

----------------------------------------------------------------
 
F

FBM

Fernando said:
Dear all,

I have been posting about a problem trying to encrypt certain data using
HMAC-SHA1 functions. I posted that my problem was solved, but
unfortunately, I was being overly optimistic. I am really desperate now,
because I havent' been able to locate the origin of the problem for a
couple of days now..

PROBLEM: the message digest obtained differs each time I execute the
code, but works perfectly when applying the "control", that is the test
case #3 from RFC 2202 that I show below.

I did my best trying to create a code that can be compiled and executed
and that clearly shows the problem. I would really appreciate any help,
I have to finish this project in a couple of days and I have been stuck
here for a long while..

Explanation of functions:
- I send an array over a function that obtains a message digest applying
hmac-sha1. This authentication function requires a message and a key.
The message simulates and IP header of lenght=31 (I hardcoded the value
for clarity).
- The 'build_ip_packet' function does bit manipulatation therefore the
final message is just gibberish, but their hexadecimal content is valid
and represents the ip packet.
- I treat the message with the function 'hexString_to_hexRepresent'
because I thought that this translation had to be made (hex to its hex
representation)
- Finally, 'icv_Calculation' performs the message digest calculation.
- 'icv_Calculation_test' uses the same function but sends to it the test
case #3 from RFC 2202
- 'pr_hexstring' prints out the result.

RFC 2202 has different test cases. #3 is the following:
test_case = 3
key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
key_len = 20
data = 0xdd repeated 50 times
data_len = 50
digest = 0x125d7342b9ac11cd91a39af48aa17b4f63f175d3

http://www.zvon.org/tmRFC/RFC2202/Output/index.html

As you can see executing the program, I get the correct result in my
second icv call. However, the first call shows completely different
results each time I call it. Why is that?

output:
$ ./icv_test.exe
0xf28b25b3793ff29a248932ebe8fa6114934be0f2
0x125d7342b9ac11cd91a39af48aa17b4f63f175d3

Again, thank you in advance for any help that you can provide me.

I attach the complete code. It's a lot, but if someone wants to try,
they are complementary functions that are needed but they are not the
origin of the problem. 'main' and first level functions is where the
core of the problem may be.

You may find string conversions which may not have much sense.. i
apologize for that, I can't think clearly anymore.. :-(

Fernando

-------------------------- main.c ----------------
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <arpa/inet.h> /* inet(3) functions */
#include <errno.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/ip.h>
#include <sys/types.h>

#include "hmac-sha1.h"


#define HEADER_OFFSET 20
#define IP_VERSION 4

typedef struct {
char * message;
char dest_ip[20];
char src_ip[20];
int msg_length;
int port;
char * key;
char algorithm;
} CONF_PARAMS;

void build_ip_packet(unsigned char *packet, unsigned short length,
CONF_PARAMS *cnf) {
struct ip *iphdr;
int packet_size;

struct in_addr ipsrc_addr, ipdst_addr; /* 'in_addr' structures needed
to change byte ordering */

packet_size = sizeof(struct ip) + cnf->msg_length; /* obtain size
for datagram */

bzero(packet, packet_size); /* fills with 0; deprecated, change
with memset */
iphdr = (struct ip *)packet; /* assign ip header structure to our
IP packet */

inet_aton(cnf->src_ip, &ipsrc_addr);
inet_aton(cnf->dest_ip, &ipdst_addr);

/* IP header construction */
iphdr->ip_v = IP_VERSION; /* version = 4, IP */
iphdr->ip_hl = 5; /* length = 5, no option */
iphdr->ip_tos = 0;
iphdr->ip_len = htons(length); /* length of the datagram */
iphdr->ip_id = htons(getpid()); /* identification for this packet,
assigned process id */
iphdr->ip_off = 0;
iphdr->ip_ttl = 64; /* time to live = 64 */
iphdr->ip_p = 51; /* protocol number = 51, AH code */
iphdr->ip_src = ipsrc_addr;
iphdr->ip_dst = ipdst_addr;
iphdr->ip_sum = 0;

// iphdr->ip_sum = in_cksum((u_short *) iphdr, (iphdr->ip_hl) << 2);
/* calculate checksum */

memcpy(packet + HEADER_OFFSET, cnf->message, cnf->msg_length); /* copy
data to end ip packet, which is
20 bytes by default. If options included,
this value has to be changed */
return;
}

/* 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;

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;
}


unsigned char* hexString_to_hexRepresent(const char *payload, const char
*hexvalue, int payload_size, int output_size) {
int ii, tt=payload_size;
unsigned char hexvalue2[payload_size*2];
memcpy(hexvalue2, hexvalue, payload_size*2);
for (ii = 0 ; ii < tt ; ii++)
sprintf(hexvalue2+(ii*2), "%02x", payload[ii]);
unsigned char *msgICV;
msgICV = hexstr_to_bytes(hexvalue2);
return msgICV;
}

void icv_Calculation_test(char p_output[20]) {
uint8_t
tmp_msgtest[]="DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD";
char tmp_key[]="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
unsigned char* key, *msgtest;
key = hexstr_to_bytes(tmp_key);
msgtest = hexstr_to_bytes(tmp_msgtest);
uint8_t outputsha[20];

int size_message, size_key;
size_message = strlen(msgtest);
size_key = strlen(key)-1;

hmac_sha(key, size_key, msgtest, size_message, outputsha,
sizeof(outputsha));
strcpy(p_output, outputsha);
free(key);
free(msgtest);
return;
}

unsigned char * icv_Calculation(unsigned char *hdrs, int hdrs_len,
CONF_PARAMS *cnf, uint8_t *output, int output_len) {
unsigned char outputshax[20];
unsigned char payloadh[hdrs_len];
memcpy(payloadh, hdrs, hdrs_len);

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

unsigned char * ret_output=malloc(20);
memcpy(ret_output, outputshax, 20);
return ret_output;
}


/* Function to print strings in hex */
void pr_hexstring(FILE* fp, unsigned char* s, int t) {
int i;
fprintf(fp, "0x");
for (i = 0 ; i < t ; i++) {
fprintf(fp, "%02x", s);
}
fprintf(fp, "\n");
}



int main(int argc, char **argv) {
CONF_PARAMS * cnf;
cnf = malloc(sizeof(*cnf));

cnf->message = "hello world";
cnf->key = "Jefe";
strcpy(cnf->dest_ip, "192.168.2.2");
strcpy(cnf->src_ip, "192.168.2.2");
cnf->msg_length = strlen(cnf->message);
cnf->algorithm='s';

unsigned char packet[31];
build_ip_packet(packet, sizeof(packet), cnf);

unsigned char m_output[20];
unsigned char d_packet[sizeof(packet)*2];
unsigned char * p_icv = hexString_to_hexRepresent(packet, d_packet ,
sizeof(packet), strlen(m_output));

unsigned char *ret_output = icv_Calculation(p_icv, 31, cnf, m_output, 20);

pr_hexstring(stdout, ret_output, 20);

char p_output_sha[20];
icv_Calculation_test(p_output_sha);

pr_hexstring(stdout, p_output_sha, 20);

free(ret_output);
free(p_icv);
free(cnf);
exit(0);
}


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

---------------------- hmac-sha1.h ----------------------------

#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 (uint8_t*, uint8_t*, int);
void hmac_sha (uint8_t*, int, uint8_t*, int, uint8_t*, int);

#endif /*HMACSHA1_H_*/

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


---------------------- hmac-sha1.c ----------------------------
#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 (
uint8_t* d1, /* data to be truncated */
uint8_t* 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 (
uint8_t* k, /* secret key */
int lk, /* length of the key in bytes */
uint8_t* d, /* data */
int ld, /* length of data in bytes */
uint8_t* out, /* output buffer, at least "t" bytes */
int t
) {
sha1_context ictx, octx;
uint8_t isha[SHA_DIGESTSIZE], osha[SHA_DIGESTSIZE];
uint8_t key[SHA_DIGESTSIZE];
uint8_t 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);


}

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

---------------------- sha1.h ----------------------------

#ifndef _SHA1_H
#define _SHA1_H

#ifndef uint8
#define uint8 unsigned char
#endif

#ifndef uint32
#define uint32 unsigned long int
#endif

typedef struct
{
uint32 total[2];
uint32 state[5];
uint8 buffer[64];
}
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] );

#endif /* sha1.h */

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

---------------------- sha1.c ----------------------------

/*
* 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 );
}

----------------------------------------------------------------
 
F

Fernando Barsoba

Fernando said:
Dear all,

I have been posting about a problem trying to encrypt certain data using
HMAC-SHA1 functions. I posted that my problem was solved, but
unfortunately, I was being overly optimistic. I am really desperate now,
because I havent' been able to locate the origin of the problem for a
couple of days now..

PROBLEM: the message digest obtained differs each time I execute the
code, but works perfectly when applying the "control", that is the test
case #3 from RFC 2202 that I show below.

Thanks to all. Posting the code made me realize what the problem was. It
turns out that:
phdr->ip_id = htons(getpid()); /* identification for this packet, assigned process

made the icv generate a complete message digest every time the program
was executed.

Pretty silly after all!

Thanks,

Fernando
 

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,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top