summaryrefslogtreecommitdiffstats
path: root/libhmac/hmac.c
blob: b624fa9776db865c32dba2b08dbb2aed9adbc844 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
** Copyright 1998 - 1999 Double Precision, Inc.
** See COPYING for distribution information.
*/

#if	HAVE_CONFIG_H
#include	"config.h"
#endif

#include	"hmac.h"


struct hmac_hashinfo *hmac_list[]= {HMAC_LIST};

struct hhki {
	const struct hmac_hashinfo *hh;
	const char *k;
        size_t kl;
	unsigned char *kxopad;
	unsigned char *kxipad;

	void *context;
	} ;

static void dohashkey(unsigned char *, void *);
static void docalcc(void *, void *);

void hmac_hashkey(const struct hmac_hashinfo *hh, const char *k,
        size_t kl, unsigned char *kxopad, unsigned char *kxipad)
{
struct hhki i;

	i.hh=hh;
	i.k=k;
	i.kl=kl;
	i.kxopad=kxopad;
	i.kxipad=kxipad;

	(*hh->hh_allocacontext)( docalcc, (void *)&i );
}

static void dokeycalc(struct hhki *);

static void docalcc(void *c, void *v)
{
struct hhki *i=(struct hhki *)v;

	i->context=c;

	if (i->kl > i->hh->hh_B)
		(*i->hh->hh_allocaval)(dohashkey, (void *)i);
	else
		dokeycalc( i );
}

static void dohashkey(unsigned char *keybuf, void *v)
{
struct hhki *i=(struct hhki *)v;

	(*i->hh->hh_init)(i->context);
	(*i->hh->hh_hash)(i->context, i->k, i->kl);
	(*i->hh->hh_endhash)(i->context, i->kl);
	(*i->hh->hh_getdigest)(i->context, keybuf);
	i->k=(char *)keybuf;
	i->kl=i->hh->hh_L;
	dokeycalc(i);
}

static void dokeycalc(struct hhki *i)
{
char	buf[64];	/* Random guess :-) */
unsigned n;
unsigned l;

	(*i->hh->hh_init)(i->context);
	n=0;
	for (l=0; l<i->hh->hh_B; l++)
	{
		buf[n] = ( l < i->kl ? i->k[l]:0) ^ 0x5C;
		if ( ++n >= sizeof(buf))
		{
			(*i->hh->hh_hash)(i->context, buf, sizeof(buf));
			n=0;
		}
	}
	if (n)
		(*i->hh->hh_hash)(i->context, buf, n);
	(*i->hh->hh_getdigest)(i->context, i->kxopad);

	(*i->hh->hh_init)(i->context);
	n=0;
	for (l=0; l<i->hh->hh_B; l++)
	{
		buf[n] = ( l < i->kl ? i->k[l]:0) ^ 0x36;
		if ( ++n >= sizeof(buf))
		{
			(*i->hh->hh_hash)(i->context, buf, sizeof(buf));
			n=0;
		}
	}
	if (n)
		(*i->hh->hh_hash)(i->context, buf, n);
	(*i->hh->hh_getdigest)(i->context, i->kxipad);
}

struct hhko {
	const struct hmac_hashinfo *hh;
	const char *t;
        size_t tl;
	const unsigned char *kxopad;
	const unsigned char *kxipad;
	unsigned char *hash;
	} ;

static void docalch(void *, void *);

void hmac_hashtext (
        const struct hmac_hashinfo *hh,
        const char *t,
        size_t tl,
        const unsigned char *kxopad,
        const unsigned char *kxipad,
        unsigned char *hash)
{
struct hhko o;

	o.hh=hh;
	o.t=t;
	o.tl=tl;
	o.kxopad=kxopad;
	o.kxipad=kxipad;
	o.hash=hash;

	(*hh->hh_allocacontext)( docalch, (void *)&o );
}

static void docalch(void *c, void *v)
{
struct hhko *o=(struct hhko *)v;

	(o->hh->hh_setdigest)(c, o->kxipad);
	(o->hh->hh_hash)(c, o->t, o->tl);
	(o->hh->hh_endhash)(c, o->tl+o->hh->hh_B);
	(o->hh->hh_getdigest)(c, o->hash);

	(o->hh->hh_setdigest)(c, o->kxopad);
	(o->hh->hh_hash)(c, o->hash, o->hh->hh_L);
	(o->hh->hh_endhash)(c, o->hh->hh_L + o->hh->hh_B);
	(o->hh->hh_getdigest)(c, o->hash);
}