1 /*
2 * Copyright (C) 2011 Collabora Ltd.
3 * Copyright (C) 2018 Alexander Volkov <a.volkov@rusbitech.ru>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as
7 * published by the Free Software Foundation; either version 2.1 of
8 * the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * 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 program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1301 USA
19 *
20 * Author: Stef Walter <stefw@collabora.co.uk>
21 */
22
23 #include <gcrypt.h>
24
gcry_hkdf(int algo,const char * input,size_t n_input,const char * salt,size_t n_salt,const char * info,size_t n_info,char * output,size_t n_output)25 static gcry_error_t gcry_hkdf(int algo,
26 const char *input,
27 size_t n_input,
28 const char *salt,
29 size_t n_salt,
30 const char *info,
31 size_t n_info,
32 char * output,
33 size_t n_output)
34 {
35 void * alloc = nullptr;
36 void * buffer = nullptr;
37 gcry_md_hd_t md1, md2;
38 unsigned int hash_len;
39 int i;
40 size_t step, n_buffer;
41 char * at;
42 gcry_error_t gcry;
43
44 hash_len = gcry_md_get_algo_dlen(algo);
45 if (hash_len == 0) {
46 return GPG_ERR_UNSUPPORTED_ALGORITHM;
47 }
48
49 if (n_output > 255 * hash_len) {
50 return GPG_ERR_TOO_LARGE;
51 }
52
53 /* Buffer we need to for intermediate stuff */
54 buffer = gcry_malloc_secure(hash_len);
55 if (!buffer) {
56 return GPG_ERR_ENOMEM;
57 }
58 n_buffer = 0;
59
60 /* Salt defaults to hash_len zeros */
61 if (!salt) {
62 alloc = gcry_calloc_secure(hash_len, 1);
63 if (!alloc) {
64 return GPG_ERR_ENOMEM;
65 }
66 salt = (const char *)alloc;
67 n_salt = hash_len;
68 }
69
70 /* Step 1: Extract */
71 gcry = gcry_md_open(&md1, algo, GCRY_MD_FLAG_HMAC | GCRY_MD_FLAG_SECURE);
72 if (gcry != GPG_ERR_NO_ERROR) {
73 goto done;
74 }
75 gcry = gcry_md_setkey(md1, salt, n_salt);
76 if (gcry != GPG_ERR_NO_ERROR) {
77 gcry_md_close(md1);
78 goto done;
79 }
80 gcry_md_write(md1, input, n_input);
81
82 /* Step 2: Expand */
83 gcry = gcry_md_open(&md2, algo, GCRY_MD_FLAG_HMAC | GCRY_MD_FLAG_SECURE);
84 if (gcry != GPG_ERR_NO_ERROR) {
85 gcry_md_close(md1);
86 goto done;
87 }
88 gcry = gcry_md_setkey(md2, gcry_md_read(md1, algo), hash_len);
89 if (gcry != GPG_ERR_NO_ERROR) {
90 gcry_md_close(md2);
91 gcry_md_close(md1);
92 goto done;
93 }
94 gcry_md_close(md1);
95
96 at = output;
97 for (i = 1; i < 256; ++i) {
98 gcry_md_reset(md2);
99 gcry_md_write(md2, buffer, n_buffer);
100 gcry_md_write(md2, info, n_info);
101 gcry_md_putc(md2, i);
102
103 n_buffer = hash_len;
104 memcpy(buffer, gcry_md_read(md2, algo), n_buffer);
105
106 step = n_buffer < n_output ? n_buffer : n_output;
107 memcpy(at, buffer, step);
108 n_output -= step;
109 at += step;
110
111 if (!n_output)
112 break;
113 }
114 gcry_md_close(md2);
115
116 done:
117 gcry_free(alloc);
118 gcry_free(buffer);
119 return gcry;
120 }
121