1 /* $NetBSD: hmacmd5.c,v 1.8 2015/07/08 17:28:59 christos Exp $ */
4 * Copyright (C) 2004-2007, 2009, 2013, 2014 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000, 2001 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: hmacmd5.c,v 1.16 2009/02/06 23:47:42 tbox Exp */
23 * This code implements the HMAC-MD5 keyed hash algorithm
24 * described in RFC2104.
29 #include <isc/assertions.h>
30 #include <isc/hmacmd5.h>
32 #include <isc/platform.h>
34 #include <isc/string.h>
35 #include <isc/types.h>
38 #if PKCS11CRYPTO || PKCS11CRYPTOWITHHMAC
39 #include <pk11/internal.h>
40 #include <pk11/pk11.h>
43 #ifdef ISC_PLATFORM_OPENSSLHASH
46 isc_hmacmd5_init(isc_hmacmd5_t
*ctx
, const unsigned char *key
,
49 #ifdef HMAC_RETURN_INT
50 RUNTIME_CHECK(HMAC_Init(ctx
, (const void *) key
,
51 (int) len
, EVP_md5()) == 1);
53 HMAC_Init(ctx
, (const void *) key
, (int) len
, EVP_md5());
58 isc_hmacmd5_invalidate(isc_hmacmd5_t
*ctx
) {
59 HMAC_CTX_cleanup(ctx
);
63 isc_hmacmd5_update(isc_hmacmd5_t
*ctx
, const unsigned char *buf
,
66 #ifdef HMAC_RETURN_INT
67 RUNTIME_CHECK(HMAC_Update(ctx
, buf
, (int) len
) == 1);
69 HMAC_Update(ctx
, buf
, (int) len
);
74 isc_hmacmd5_sign(isc_hmacmd5_t
*ctx
, unsigned char *digest
) {
75 #ifdef HMAC_RETURN_INT
76 RUNTIME_CHECK(HMAC_Final(ctx
, digest
, NULL
) == 1);
78 HMAC_Final(ctx
, digest
, NULL
);
80 HMAC_CTX_cleanup(ctx
);
83 #elif PKCS11CRYPTOWITHHMAC
85 static CK_BBOOL truevalue
= TRUE
;
86 static CK_BBOOL falsevalue
= FALSE
;
89 isc_hmacmd5_init(isc_hmacmd5_t
*ctx
, const unsigned char *key
,
93 CK_MECHANISM mech
= { CKM_MD5_HMAC
, NULL
, 0 };
94 CK_OBJECT_CLASS keyClass
= CKO_SECRET_KEY
;
95 CK_KEY_TYPE keyType
= CKK_MD5_HMAC
;
96 CK_ATTRIBUTE keyTemplate
[] =
98 { CKA_CLASS
, &keyClass
, (CK_ULONG
) sizeof(keyClass
) },
99 { CKA_KEY_TYPE
, &keyType
, (CK_ULONG
) sizeof(keyType
) },
100 { CKA_TOKEN
, &falsevalue
, (CK_ULONG
) sizeof(falsevalue
) },
101 { CKA_PRIVATE
, &falsevalue
, (CK_ULONG
) sizeof(falsevalue
) },
102 { CKA_SIGN
, &truevalue
, (CK_ULONG
) sizeof(truevalue
) },
103 { CKA_VALUE
, NULL
, (CK_ULONG
) len
}
106 DE_CONST(key
, keyTemplate
[5].pValue
);
107 RUNTIME_CHECK(pk11_get_session(ctx
, OP_DIGEST
, ISC_TRUE
, ISC_FALSE
,
108 ISC_FALSE
, NULL
, 0) == ISC_R_SUCCESS
);
109 ctx
->object
= CK_INVALID_HANDLE
;
110 PK11_FATALCHECK(pkcs_C_CreateObject
,
111 (ctx
->session
, keyTemplate
,
112 (CK_ULONG
) 6, &ctx
->object
));
113 INSIST(ctx
->object
!= CK_INVALID_HANDLE
);
114 PK11_FATALCHECK(pkcs_C_SignInit
, (ctx
->session
, &mech
, ctx
->object
));
118 isc_hmacmd5_invalidate(isc_hmacmd5_t
*ctx
) {
119 CK_BYTE garbage
[ISC_MD5_DIGESTLENGTH
];
120 CK_ULONG len
= ISC_MD5_DIGESTLENGTH
;
122 if (ctx
->handle
== NULL
)
124 (void) pkcs_C_SignFinal(ctx
->session
, garbage
, &len
);
125 memset(garbage
, 0, sizeof(garbage
));
126 if (ctx
->object
!= CK_INVALID_HANDLE
)
127 (void) pkcs_C_DestroyObject(ctx
->session
, ctx
->object
);
128 ctx
->object
= CK_INVALID_HANDLE
;
129 pk11_return_session(ctx
);
133 isc_hmacmd5_update(isc_hmacmd5_t
*ctx
, const unsigned char *buf
,
139 DE_CONST(buf
, pPart
);
140 PK11_FATALCHECK(pkcs_C_SignUpdate
,
141 (ctx
->session
, pPart
, (CK_ULONG
) len
));
145 isc_hmacmd5_sign(isc_hmacmd5_t
*ctx
, unsigned char *digest
) {
147 CK_ULONG len
= ISC_MD5_DIGESTLENGTH
;
149 PK11_FATALCHECK(pkcs_C_SignFinal
,
150 (ctx
->session
, (CK_BYTE_PTR
) digest
, &len
));
151 if (ctx
->object
!= CK_INVALID_HANDLE
)
152 (void) pkcs_C_DestroyObject(ctx
->session
, ctx
->object
);
153 ctx
->object
= CK_INVALID_HANDLE
;
154 pk11_return_session(ctx
);
164 isc_hmacmd5_init(isc_hmacmd5_t
*ctx
, const unsigned char *key
,
168 CK_MECHANISM mech
= { CKM_MD5
, NULL
, 0 };
169 unsigned char ipad
[PADLEN
];
172 RUNTIME_CHECK(pk11_get_session(ctx
, OP_DIGEST
, ISC_TRUE
, ISC_FALSE
,
173 ISC_FALSE
, NULL
, 0) == ISC_R_SUCCESS
);
174 RUNTIME_CHECK((ctx
->key
= pk11_mem_get(PADLEN
)) != NULL
);
179 PK11_FATALCHECK(pkcs_C_DigestInit
, (ctx
->session
, &mech
));
180 DE_CONST(key
, kPart
);
181 PK11_FATALCHECK(pkcs_C_DigestUpdate
,
182 (ctx
->session
, kPart
, (CK_ULONG
) len
));
183 kl
= ISC_MD5_DIGESTLENGTH
;
184 PK11_FATALCHECK(pkcs_C_DigestFinal
,
185 (ctx
->session
, (CK_BYTE_PTR
) ctx
->key
, &kl
));
187 memmove(ctx
->key
, key
, len
);
188 PK11_FATALCHECK(pkcs_C_DigestInit
, (ctx
->session
, &mech
));
189 memset(ipad
, IPAD
, PADLEN
);
190 for (i
= 0; i
< PADLEN
; i
++)
191 ipad
[i
] ^= ctx
->key
[i
];
192 PK11_FATALCHECK(pkcs_C_DigestUpdate
,
193 (ctx
->session
, ipad
, (CK_ULONG
) PADLEN
));
197 isc_hmacmd5_invalidate(isc_hmacmd5_t
*ctx
) {
198 if (ctx
->key
!= NULL
)
199 pk11_mem_put(ctx
->key
, PADLEN
);
201 isc_md5_invalidate(ctx
);
205 isc_hmacmd5_update(isc_hmacmd5_t
*ctx
, const unsigned char *buf
,
211 DE_CONST(buf
, pPart
);
212 PK11_FATALCHECK(pkcs_C_DigestUpdate
,
213 (ctx
->session
, pPart
, (CK_ULONG
) len
));
217 isc_hmacmd5_sign(isc_hmacmd5_t
*ctx
, unsigned char *digest
) {
219 CK_MECHANISM mech
= { CKM_MD5
, NULL
, 0 };
220 CK_ULONG len
= ISC_MD5_DIGESTLENGTH
;
221 CK_BYTE opad
[PADLEN
];
224 PK11_FATALCHECK(pkcs_C_DigestFinal
,
225 (ctx
->session
, (CK_BYTE_PTR
) digest
,
226 (CK_ULONG_PTR
) &len
));
227 memset(opad
, OPAD
, PADLEN
);
228 for (i
= 0; i
< PADLEN
; i
++)
229 opad
[i
] ^= ctx
->key
[i
];
230 pk11_mem_put(ctx
->key
, PADLEN
);
232 PK11_FATALCHECK(pkcs_C_DigestInit
, (ctx
->session
, &mech
));
233 PK11_FATALCHECK(pkcs_C_DigestUpdate
,
234 (ctx
->session
, opad
, (CK_ULONG
) PADLEN
));
235 PK11_FATALCHECK(pkcs_C_DigestUpdate
,
236 (ctx
->session
, (CK_BYTE_PTR
) digest
, len
));
237 PK11_FATALCHECK(pkcs_C_DigestFinal
,
239 (CK_BYTE_PTR
) digest
,
240 (CK_ULONG_PTR
) &len
));
241 pk11_return_session(ctx
);
251 * Start HMAC-MD5 process. Initialize an md5 context and digest the key.
254 isc_hmacmd5_init(isc_hmacmd5_t
*ctx
, const unsigned char *key
,
257 unsigned char ipad
[PADLEN
];
260 memset(ctx
->key
, 0, sizeof(ctx
->key
));
261 if (len
> sizeof(ctx
->key
)) {
263 isc_md5_init(&md5ctx
);
264 isc_md5_update(&md5ctx
, key
, len
);
265 isc_md5_final(&md5ctx
, ctx
->key
);
267 memmove(ctx
->key
, key
, len
);
269 isc_md5_init(&ctx
->md5ctx
);
270 memset(ipad
, IPAD
, sizeof(ipad
));
271 for (i
= 0; i
< PADLEN
; i
++)
272 ipad
[i
] ^= ctx
->key
[i
];
273 isc_md5_update(&ctx
->md5ctx
, ipad
, sizeof(ipad
));
277 isc_hmacmd5_invalidate(isc_hmacmd5_t
*ctx
) {
278 isc_md5_invalidate(&ctx
->md5ctx
);
279 memset(ctx
->key
, 0, sizeof(ctx
->key
));
283 * Update context to reflect the concatenation of another buffer full
287 isc_hmacmd5_update(isc_hmacmd5_t
*ctx
, const unsigned char *buf
,
290 isc_md5_update(&ctx
->md5ctx
, buf
, len
);
294 * Compute signature - finalize MD5 operation and reapply MD5.
297 isc_hmacmd5_sign(isc_hmacmd5_t
*ctx
, unsigned char *digest
) {
298 unsigned char opad
[PADLEN
];
301 isc_md5_final(&ctx
->md5ctx
, digest
);
303 memset(opad
, OPAD
, sizeof(opad
));
304 for (i
= 0; i
< PADLEN
; i
++)
305 opad
[i
] ^= ctx
->key
[i
];
307 isc_md5_init(&ctx
->md5ctx
);
308 isc_md5_update(&ctx
->md5ctx
, opad
, sizeof(opad
));
309 isc_md5_update(&ctx
->md5ctx
, digest
, ISC_MD5_DIGESTLENGTH
);
310 isc_md5_final(&ctx
->md5ctx
, digest
);
311 isc_hmacmd5_invalidate(ctx
);
314 #endif /* !ISC_PLATFORM_OPENSSLHASH */
317 * Verify signature - finalize MD5 operation and reapply MD5, then
318 * compare to the supplied digest.
321 isc_hmacmd5_verify(isc_hmacmd5_t
*ctx
, unsigned char *digest
) {
322 return (isc_hmacmd5_verify2(ctx
, digest
, ISC_MD5_DIGESTLENGTH
));
326 isc_hmacmd5_verify2(isc_hmacmd5_t
*ctx
, unsigned char *digest
, size_t len
) {
327 unsigned char newdigest
[ISC_MD5_DIGESTLENGTH
];
329 REQUIRE(len
<= ISC_MD5_DIGESTLENGTH
);
330 isc_hmacmd5_sign(ctx
, newdigest
);
331 return (isc_safe_memcmp(digest
, newdigest
, len
));