File: hkdf.c

package info (click to toggle)
qca2 2.3.10-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 5,884 kB
  • sloc: cpp: 59,224; ansic: 814; perl: 133; sh: 89; makefile: 34
file content (120 lines) | stat: -rw-r--r-- 3,519 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/*
 * Copyright (C) 2011 Collabora Ltd.
 * Copyright (C) 2018 Alexander Volkov <a.volkov@rusbitech.ru>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA
 *
 * Author: Stef Walter <stefw@collabora.co.uk>
 */

#include <gcrypt.h>

static gcry_error_t 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)
{
    void        *alloc  = nullptr;
    void        *buffer = nullptr;
    gcry_md_hd_t md1, md2;
    unsigned int hash_len;
    int          i;
    size_t       step, n_buffer;
    char        *at;
    gcry_error_t gcry;

    hash_len = gcry_md_get_algo_dlen(algo);
    if (hash_len == 0) {
        return GPG_ERR_UNSUPPORTED_ALGORITHM;
    }

    if (n_output > 255 * hash_len) {
        return GPG_ERR_TOO_LARGE;
    }

    /* Buffer we need to for intermediate stuff */
    buffer = gcry_malloc_secure(hash_len);
    if (!buffer) {
        return GPG_ERR_ENOMEM;
    }
    n_buffer = 0;

    /* Salt defaults to hash_len zeros */
    if (!salt) {
        alloc = gcry_calloc_secure(hash_len, 1);
        if (!alloc) {
            return GPG_ERR_ENOMEM;
        }
        salt   = (const char *)alloc;
        n_salt = hash_len;
    }

    /* Step 1: Extract */
    gcry = gcry_md_open(&md1, algo, GCRY_MD_FLAG_HMAC | GCRY_MD_FLAG_SECURE);
    if (gcry != GPG_ERR_NO_ERROR) {
        goto done;
    }
    gcry = gcry_md_setkey(md1, salt, n_salt);
    if (gcry != GPG_ERR_NO_ERROR) {
        gcry_md_close(md1);
        goto done;
    }
    gcry_md_write(md1, input, n_input);

    /* Step 2: Expand */
    gcry = gcry_md_open(&md2, algo, GCRY_MD_FLAG_HMAC | GCRY_MD_FLAG_SECURE);
    if (gcry != GPG_ERR_NO_ERROR) {
        gcry_md_close(md1);
        goto done;
    }
    gcry = gcry_md_setkey(md2, gcry_md_read(md1, algo), hash_len);
    if (gcry != GPG_ERR_NO_ERROR) {
        gcry_md_close(md2);
        gcry_md_close(md1);
        goto done;
    }
    gcry_md_close(md1);

    at = output;
    for (i = 1; i < 256; ++i) {
        gcry_md_reset(md2);
        gcry_md_write(md2, buffer, n_buffer);
        gcry_md_write(md2, info, n_info);
        gcry_md_putc(md2, i);

        n_buffer = hash_len;
        memcpy(buffer, gcry_md_read(md2, algo), n_buffer);

        step = n_buffer < n_output ? n_buffer : n_output;
        memcpy(at, buffer, step);
        n_output -= step;
        at += step;

        if (!n_output)
            break;
    }
    gcry_md_close(md2);

done:
    gcry_free(alloc);
    gcry_free(buffer);
    return gcry;
}