]> pd.if.org Git - zpackage/blob - libtomcrypt/src/misc/hkdf/hkdf.c
commit files needed for zpm-fetchurl
[zpackage] / libtomcrypt / src / misc / hkdf / hkdf.c
1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
2  *
3  * LibTomCrypt is a library that provides various cryptographic
4  * algorithms in a highly modular and flexible manner.
5  *
6  * The library is free for all purposes without any express
7  * guarantee it works.
8  */
9
10 #include <assert.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13
14 #include "tomcrypt.h"
15
16 #ifdef LTC_HKDF
17
18 /* This is mostly just a wrapper around hmac_memory */
19 int hkdf_extract(int hash_idx, const unsigned char *salt, unsigned long  saltlen,
20                                const unsigned char *in,   unsigned long  inlen,
21                                      unsigned char *out,  unsigned long *outlen)
22 {
23    /* libtomcrypt chokes on a zero length HMAC key, so we need to check for
24       that.  HMAC specifies that keys shorter than the hash's blocksize are
25       0 padded to the block size.  HKDF specifies that a NULL salt is to be
26       substituted with a salt comprised of hashLen 0 bytes.  HMAC's padding
27       means that in either case the HMAC is actually using a blocksize long
28       zero filled key.  Unless blocksize < hashLen (which wouldn't make any
29       sense), we can use a single 0 byte as the HMAC key and still generate
30       valid results for HKDF. */
31    if (salt == NULL || saltlen == 0) {
32       return hmac_memory(hash_idx, (const unsigned char *)"",   1,       in, inlen, out, outlen);
33    } else {
34       return hmac_memory(hash_idx, salt, saltlen, in, inlen, out, outlen);
35    }
36 }
37
38 int hkdf_expand(int hash_idx, const unsigned char *info, unsigned long infolen,
39                               const unsigned char *in,   unsigned long inlen,
40                                     unsigned char *out,  unsigned long outlen)
41 {
42    unsigned long hashsize;
43    int err;
44    unsigned char N;
45    unsigned long Noutlen, outoff;
46
47    unsigned char *T,  *dat;
48    unsigned long Tlen, datlen;
49
50    /* make sure hash descriptor is valid */
51    if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
52       return err;
53    }
54
55    hashsize = hash_descriptor[hash_idx].hashsize;
56
57    /* RFC5869 parameter restrictions */
58    if (inlen < hashsize || outlen > hashsize * 255)
59       return CRYPT_INVALID_ARG;
60    if (info == NULL && infolen != 0)
61       return CRYPT_INVALID_ARG;
62    LTC_ARGCHK(out != NULL);
63
64    Tlen = hashsize + infolen + 1;
65    T = XMALLOC(Tlen); /* Replace with static buffer? */
66    if (T == NULL) {
67       return CRYPT_MEM;
68    }
69    if (info != NULL) {
70       XMEMCPY(T + hashsize, info, infolen);
71    }
72
73    /* HMAC data T(1) doesn't include a previous hash value */
74    dat    = T    + hashsize;
75    datlen = Tlen - hashsize;
76
77    N = 0;
78    outoff = 0; /* offset in out to write to */
79    while (1) { /* an exit condition breaks mid-loop */
80       Noutlen = MIN(hashsize, outlen - outoff);
81       T[Tlen - 1] = ++N;
82       if ((err = hmac_memory(hash_idx, in, inlen, dat, datlen,
83                              out + outoff, &Noutlen)) != CRYPT_OK) {
84          zeromem(T, Tlen);
85          XFREE(T);
86          return err;
87       }
88       outoff += Noutlen;
89
90       if (outoff >= outlen) /* loop exit condition */
91          break;
92
93       /* All subsequent HMAC data T(N) DOES include the previous hash value */
94       XMEMCPY(T, out + hashsize * (N-1), hashsize);
95       if (N == 1) {
96          dat = T;
97          datlen = Tlen;
98       }
99    }
100    zeromem(T, Tlen);
101    XFREE(T);
102    return CRYPT_OK;
103 }
104
105 /* all in one step */
106 int hkdf(int hash_idx, const unsigned char *salt, unsigned long saltlen,
107                        const unsigned char *info, unsigned long infolen,
108                        const unsigned char *in,   unsigned long inlen,
109                              unsigned char *out,  unsigned long outlen)
110 {
111    unsigned long hashsize;
112    int err;
113    unsigned char *extracted;
114
115    /* make sure hash descriptor is valid */
116    if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
117       return err;
118    }
119
120    hashsize = hash_descriptor[hash_idx].hashsize;
121
122    extracted = XMALLOC(hashsize); /* replace with static buffer? */
123    if (extracted == NULL) {
124       return CRYPT_MEM;
125    }
126    if ((err = hkdf_extract(hash_idx, salt, saltlen, in, inlen, extracted, &hashsize)) != 0) {
127       zeromem(extracted, hashsize);
128       XFREE(extracted);
129       return err;
130    }
131    err = hkdf_expand(hash_idx, info, infolen, extracted, hashsize, out, outlen);
132    zeromem(extracted, hashsize);
133    XFREE(extracted);
134    return err;
135 }
136 #endif /* LTC_HKDF */
137
138
139 /* vim: set ts=2 sw=2 et ai si: */
140
141 /* ref:         $Format:%D$ */
142 /* git commit:  $Format:%H$ */
143 /* commit time: $Format:%ai$ */