Statistics
| Revision:

root / libsylph / md5_hmac.c @ 2735

History | View | Annotate | Download (3.5 kB)

1
/*
2
 * LibSylph -- E-Mail client library
3
 * Copyright (C) 1999-2006 Hiroyuki Yamamoto
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2.1 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 */
19
20
#ifdef HAVE_CONFIG_H
21
#  include "config.h"
22
#endif
23
24
#include <glib.h>
25
#include <string.h>
26
27
#include "md5.h"
28
#include "md5_hmac.h"
29
30
/*
31
** Function: md5_hmac_get
32
** taken from the file rfc2104.txt
33
** originally written by Martin Schaaf <mascha@ma-scha.de>
34
** rewritten by Hiroyuki Yamamoto <hiro-y@kcn.ne.jp>
35
*/
36
static SMD5*
37
md5_hmac_get(const guchar *text, gint text_len,
38
             const guchar *key, gint key_len)
39
{
40
        SMD5 *md5;
41
        guchar k_ipad[64];    /* inner padding -
42
                               * key XORd with ipad
43
                               */
44
        guchar k_opad[64];    /* outer padding -
45
                               * key XORd with opad
46
                               */
47
        guchar digest[S_GNET_MD5_HASH_LENGTH];
48
        gint i;
49
50
        /* start out by storing key in pads */
51
        memset(k_ipad, 0, sizeof k_ipad);
52
        memset(k_opad, 0, sizeof k_opad);
53
54
        if (key_len > 64) {
55
                /* if key is longer than 64 bytes reset it to key=MD5(key) */
56
                SMD5 *tmd5;
57
58
                tmd5 = s_gnet_md5_new(key, key_len);
59
                memcpy(k_ipad, s_gnet_md5_get_digest(tmd5),
60
                       S_GNET_MD5_HASH_LENGTH);
61
                memcpy(k_opad, s_gnet_md5_get_digest(tmd5),
62
                       S_GNET_MD5_HASH_LENGTH);
63
                s_gnet_md5_delete(tmd5);
64
        } else {
65
                memcpy(k_ipad, key, key_len);
66
                memcpy(k_opad, key, key_len);
67
        }
68
69
        /*
70
         * the HMAC_MD5 transform looks like:
71
         *
72
         * MD5(K XOR opad, MD5(K XOR ipad, text))
73
         *
74
         * where K is an n byte key
75
         * ipad is the byte 0x36 repeated 64 times
76
         * opad is the byte 0x5c repeated 64 times
77
         * and text is the data being protected
78
         */
79
80
81
        /* XOR key with ipad and opad values */
82
        for (i = 0; i < 64; i++) {
83
                k_ipad[i] ^= 0x36;
84
                k_opad[i] ^= 0x5c;
85
        }
86
87
        /*
88
         * perform inner MD5
89
         */
90
        md5 = s_gnet_md5_new_incremental();        /* init context for 1st
91
                                                 * pass */
92
        s_gnet_md5_update(md5, k_ipad, 64);        /* start with inner pad */
93
        s_gnet_md5_update(md5, text, text_len);        /* then text of datagram */
94
        s_gnet_md5_final(md5);                        /* finish up 1st pass */
95
        memcpy(digest, s_gnet_md5_get_digest(md5), S_GNET_MD5_HASH_LENGTH);
96
        s_gnet_md5_delete(md5);
97
98
        /*
99
         * perform outer MD5
100
         */
101
        md5 = s_gnet_md5_new_incremental();        /* init context for 2nd
102
                                                 * pass */
103
        s_gnet_md5_update(md5, k_opad, 64);        /* start with outer pad */
104
        s_gnet_md5_update(md5, digest, 16);        /* then results of 1st
105
                                                 * hash */
106
        s_gnet_md5_final(md5);                        /* finish up 2nd pass */
107
108
        return md5;
109
}
110
111
void
112
md5_hmac(guchar *digest,
113
         const guchar *text, gint text_len,
114
         const guchar *key, gint key_len)
115
{
116
        SMD5 *md5;
117
118
        md5 = md5_hmac_get(text, text_len, key, key_len);
119
        memcpy(digest, s_gnet_md5_get_digest(md5), S_GNET_MD5_HASH_LENGTH);
120
        s_gnet_md5_delete(md5);
121
}
122
123
void
124
md5_hex_hmac(gchar *hexdigest,
125
             const guchar *text, gint text_len,
126
             const guchar *key, gint key_len)
127
{
128
        SMD5 *md5;
129
130
        md5 = md5_hmac_get(text, text_len, key, key_len);
131
        s_gnet_md5_copy_string(md5, hexdigest);
132
        hexdigest[S_GNET_MD5_HASH_LENGTH * 2] = '\0';
133
        s_gnet_md5_delete(md5);
134
}