summaryrefslogtreecommitdiff
path: root/libs/libsodium/src/crypto_kdf/hkdf/kdf_hkdf_sha512.c
blob: a4144e2d7717d867489688dc24e2867779bc58b3 (plain)
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
121
122
123
#include <errno.h>
#include <string.h>

#include "crypto_auth_hmacsha512.h"
#include "crypto_kdf.h"
#include "crypto_kdf_hkdf_sha512.h"
#include "randombytes.h"
#include "utils.h"

int
crypto_kdf_hkdf_sha512_extract_init(crypto_kdf_hkdf_sha512_state *state,
                                    const unsigned char *salt, size_t salt_len)
{
    return crypto_auth_hmacsha512_init(&state->st, salt, salt_len);
}

int
crypto_kdf_hkdf_sha512_extract_update(crypto_kdf_hkdf_sha512_state *state,
                                      const unsigned char *ikm, size_t ikm_len)
{
    return crypto_auth_hmacsha512_update(&state->st, ikm, ikm_len);
}

int
crypto_kdf_hkdf_sha512_extract_final(crypto_kdf_hkdf_sha512_state *state,
                                     unsigned char prk[crypto_kdf_hkdf_sha512_KEYBYTES])
{
    crypto_auth_hmacsha512_final(&state->st, prk);
    sodium_memzero(state, sizeof *state);

    return 0;
}

int
crypto_kdf_hkdf_sha512_extract(
    unsigned char prk[crypto_kdf_hkdf_sha512_KEYBYTES],
    const unsigned char *salt, size_t salt_len, const unsigned char *ikm,
    size_t ikm_len)
{
    crypto_kdf_hkdf_sha512_state state;

    crypto_kdf_hkdf_sha512_extract_init(&state, salt, salt_len);
    crypto_kdf_hkdf_sha512_extract_update(&state, ikm, ikm_len);

    return crypto_kdf_hkdf_sha512_extract_final(&state, prk);
}

void
crypto_kdf_hkdf_sha512_keygen(unsigned char prk[crypto_kdf_hkdf_sha512_KEYBYTES])
{
    randombytes_buf(prk, crypto_kdf_hkdf_sha512_KEYBYTES);
}

int
crypto_kdf_hkdf_sha512_expand(unsigned char *out, size_t out_len,
                              const char *ctx, size_t ctx_len,
                              const unsigned char prk[crypto_kdf_hkdf_sha512_KEYBYTES])
{
    crypto_auth_hmacsha512_state st;
    unsigned char                tmp[crypto_auth_hmacsha512_BYTES];
    size_t                       i;
    size_t                       left;
    unsigned char                counter = 1U;

    if (out_len > crypto_kdf_hkdf_sha512_BYTES_MAX) {
        errno = EINVAL;
        return -1;
    }
    for (i = (size_t) 0U; i + crypto_auth_hmacsha512_BYTES <= out_len;
         i += crypto_auth_hmacsha512_BYTES) {
        crypto_auth_hmacsha512_init(&st, prk, crypto_kdf_hkdf_sha512_KEYBYTES);
        if (i != (size_t) 0U) {
            crypto_auth_hmacsha512_update(&st,
                                          &out[i - crypto_auth_hmacsha512_BYTES],
                                          crypto_auth_hmacsha512_BYTES);
        }
        crypto_auth_hmacsha512_update(&st,
                                      (const unsigned char *) ctx, ctx_len);
        crypto_auth_hmacsha512_update(&st, &counter, (size_t) 1U);
        crypto_auth_hmacsha512_final(&st, &out[i]);
        counter++;
    }
    if ((left = out_len & (crypto_auth_hmacsha512_BYTES - 1U)) != (size_t) 0U) {
        crypto_auth_hmacsha512_init(&st, prk, crypto_kdf_hkdf_sha512_KEYBYTES);
        if (i != (size_t) 0U) {
            crypto_auth_hmacsha512_update(&st,
                                          &out[i - crypto_auth_hmacsha512_BYTES],
                                          crypto_auth_hmacsha512_BYTES);
        }
        crypto_auth_hmacsha512_update(&st,
                                      (const unsigned char *) ctx, ctx_len);
        crypto_auth_hmacsha512_update(&st, &counter, (size_t) 1U);
        crypto_auth_hmacsha512_final(&st, tmp);
        memcpy(&out[i], tmp, left);
        sodium_memzero(tmp, sizeof tmp);
    }
    sodium_memzero(&st, sizeof st);

    return 0;
}

size_t
crypto_kdf_hkdf_sha512_keybytes(void)
{
    return crypto_kdf_hkdf_sha512_KEYBYTES;
}

size_t
crypto_kdf_hkdf_sha512_bytes_min(void)
{
    return crypto_kdf_hkdf_sha512_BYTES_MIN;
}

size_t
crypto_kdf_hkdf_sha512_bytes_max(void)
{
    return crypto_kdf_hkdf_sha512_BYTES_MAX;
}

size_t crypto_kdf_hkdf_sha512_statebytes(void)
{
    return sizeof(crypto_kdf_hkdf_sha512_state);
}