r19604: This is a massive commit, and I appologise in advance for it's size.
[jelmer/samba4-debian.git] / source / heimdal / lib / des / hmac.c
1 #include <sys/types.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <hmac.h>
6
7 void
8 HMAC_CTX_init(HMAC_CTX *ctx)
9 {
10     memset(ctx, 0, sizeof(*ctx));
11 }
12
13 void
14 HMAC_CTX_cleanup(HMAC_CTX *ctx)
15 {
16     if (ctx->buf) {
17         memset(ctx->buf, 0, ctx->key_length);
18         free(ctx->buf);
19         ctx->buf = NULL;
20     }
21     if (ctx->opad) {
22         memset(ctx->ipad, 0, ctx->key_length);
23         free(ctx->opad);
24         ctx->opad = NULL;
25     }
26     if (ctx->ipad) {
27         memset(ctx->ipad, 0, ctx->key_length);
28         free(ctx->ipad);
29         ctx->ipad = NULL;
30     }
31     if (ctx->ctx) {
32         EVP_MD_CTX_destroy(ctx->ctx);
33         ctx->ctx = NULL;
34     }
35 }
36
37 size_t
38 HMAC_size(const HMAC_CTX *ctx)
39 {
40     return EVP_MD_size(ctx->md);
41 }
42
43 void
44 HMAC_Init_ex(HMAC_CTX *ctx,
45              const void *key,
46              size_t keylen,
47              const EVP_MD *md,
48              ENGINE *engine)
49 {
50     unsigned char *p;
51     size_t i;
52
53     if (ctx->md != md) {
54         ctx->md = md;
55         if (ctx->buf)
56             free (ctx->buf);
57         ctx->key_length = EVP_MD_size(ctx->md);
58         ctx->buf = malloc(ctx->key_length);
59     }
60 #if 0
61     ctx->engine = engine;
62 #endif
63
64     if (keylen > EVP_MD_block_size(ctx->md)) {
65         EVP_Digest(key, keylen, ctx->buf, NULL, ctx->md, engine);
66         key = ctx->buf;
67         keylen = EVP_MD_size(ctx->md);
68     }
69
70     if (ctx->opad)
71         free(ctx->opad);
72     if (ctx->ipad)
73         free(ctx->ipad);
74
75     ctx->opad = malloc(EVP_MD_block_size(ctx->md));
76     ctx->ipad = malloc(EVP_MD_block_size(ctx->md));
77     memset(ctx->ipad, 0x36, EVP_MD_block_size(ctx->md));
78     memset(ctx->opad, 0x5c, EVP_MD_block_size(ctx->md));
79
80     for (i = 0, p = ctx->ipad; i < keylen; i++)
81         p[i] ^= ((const unsigned char *)key)[i];
82     for (i = 0, p = ctx->opad; i < keylen; i++)
83         p[i] ^= ((const unsigned char *)key)[i];
84
85     ctx->ctx = EVP_MD_CTX_create();
86
87     EVP_DigestInit_ex(ctx->ctx, ctx->md, ctx->engine);
88     EVP_DigestUpdate(ctx->ctx, ctx->ipad, EVP_MD_block_size(ctx->md));
89 }
90
91 void
92 HMAC_Update(HMAC_CTX *ctx, const void *data, size_t len)
93 {
94     EVP_DigestUpdate(ctx->ctx, data, len);
95 }
96
97 void
98 HMAC_Final(HMAC_CTX *ctx, void *md, unsigned int *len)
99 {
100     EVP_DigestFinal_ex(ctx->ctx, ctx->buf, NULL);
101
102     EVP_DigestInit_ex(ctx->ctx, ctx->md, ctx->engine);
103     EVP_DigestUpdate(ctx->ctx, ctx->opad, EVP_MD_block_size(ctx->md));
104     EVP_DigestUpdate(ctx->ctx, ctx->buf, ctx->key_length);
105     EVP_DigestFinal_ex(ctx->ctx, md, len);
106 }
107
108 void *
109 HMAC(const EVP_MD *md,
110      const void *key, size_t key_size,
111      const void *data, size_t data_size, 
112      void *hash, unsigned int *hash_len)
113 {
114     HMAC_CTX ctx;
115
116     HMAC_CTX_init(&ctx);
117     HMAC_Init_ex(&ctx, key, key_size, md, NULL);
118     HMAC_Update(&ctx, data, data_size);
119     HMAC_Final(&ctx, hash, hash_len);
120     HMAC_CTX_cleanup(&ctx);
121     return hash;
122 }