Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
8774 rgimad 1
/*
2
 *  HKDF implementation -- RFC 5869
3
 *
4
 *  Copyright (C) 2016-2018, ARM Limited, All Rights Reserved
5
 *  SPDX-License-Identifier: GPL-2.0
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  (at your option) any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License along
18
 *  with this program; if not, write to the Free Software Foundation, Inc.,
19
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
 *
21
 *  This file is part of mbed TLS (https://tls.mbed.org)
22
 */
23
#if !defined(MBEDTLS_CONFIG_FILE)
24
#include "mbedtls/config.h"
25
#else
26
#include MBEDTLS_CONFIG_FILE
27
#endif
28
 
29
#if defined(MBEDTLS_HKDF_C)
30
 
31
#include 
32
#include "mbedtls/hkdf.h"
33
#include "mbedtls/platform_util.h"
34
 
35
int mbedtls_hkdf( const mbedtls_md_info_t *md, const unsigned char *salt,
36
                  size_t salt_len, const unsigned char *ikm, size_t ikm_len,
37
                  const unsigned char *info, size_t info_len,
38
                  unsigned char *okm, size_t okm_len )
39
{
40
    int ret;
41
    unsigned char prk[MBEDTLS_MD_MAX_SIZE];
42
 
43
    ret = mbedtls_hkdf_extract( md, salt, salt_len, ikm, ikm_len, prk );
44
 
45
    if( ret == 0 )
46
    {
47
        ret = mbedtls_hkdf_expand( md, prk, mbedtls_md_get_size( md ),
48
                                   info, info_len, okm, okm_len );
49
    }
50
 
51
    mbedtls_platform_zeroize( prk, sizeof( prk ) );
52
 
53
    return( ret );
54
}
55
 
56
int mbedtls_hkdf_extract( const mbedtls_md_info_t *md,
57
                          const unsigned char *salt, size_t salt_len,
58
                          const unsigned char *ikm, size_t ikm_len,
59
                          unsigned char *prk )
60
{
61
    unsigned char null_salt[MBEDTLS_MD_MAX_SIZE] = { '\0' };
62
 
63
    if( salt == NULL )
64
    {
65
        size_t hash_len;
66
 
67
        if( salt_len != 0 )
68
        {
69
            return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
70
        }
71
 
72
        hash_len = mbedtls_md_get_size( md );
73
 
74
        if( hash_len == 0 )
75
        {
76
            return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
77
        }
78
 
79
        salt = null_salt;
80
        salt_len = hash_len;
81
    }
82
 
83
    return( mbedtls_md_hmac( md, salt, salt_len, ikm, ikm_len, prk ) );
84
}
85
 
86
int mbedtls_hkdf_expand( const mbedtls_md_info_t *md, const unsigned char *prk,
87
                         size_t prk_len, const unsigned char *info,
88
                         size_t info_len, unsigned char *okm, size_t okm_len )
89
{
90
    size_t hash_len;
91
    size_t where = 0;
92
    size_t n;
93
    size_t t_len = 0;
94
    size_t i;
95
    int ret = 0;
96
    mbedtls_md_context_t ctx;
97
    unsigned char t[MBEDTLS_MD_MAX_SIZE];
98
 
99
    if( okm == NULL )
100
    {
101
        return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA );
102
    }
103
 
104
    hash_len = mbedtls_md_get_size( md );
105
 
106
    if( prk_len < hash_len || hash_len == 0 )
107
    {
108
        return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA );
109
    }
110
 
111
    if( info == NULL )
112
    {
113
        info = (const unsigned char *) "";
114
        info_len = 0;
115
    }
116
 
117
    n = okm_len / hash_len;
118
 
119
    if( (okm_len % hash_len) != 0 )
120
    {
121
        n++;
122
    }
123
 
124
    /*
125
     * Per RFC 5869 Section 2.3, okm_len must not exceed
126
     * 255 times the hash length
127
     */
128
    if( n > 255 )
129
    {
130
        return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA );
131
    }
132
 
133
    mbedtls_md_init( &ctx );
134
 
135
    if( (ret = mbedtls_md_setup( &ctx, md, 1) ) != 0 )
136
    {
137
        goto exit;
138
    }
139
 
140
    /*
141
     * Compute T = T(1) | T(2) | T(3) | ... | T(N)
142
     * Where T(N) is defined in RFC 5869 Section 2.3
143
     */
144
    for( i = 1; i <= n; i++ )
145
    {
146
        size_t num_to_copy;
147
        unsigned char c = i & 0xff;
148
 
149
        ret = mbedtls_md_hmac_starts( &ctx, prk, prk_len );
150
        if( ret != 0 )
151
        {
152
            goto exit;
153
        }
154
 
155
        ret = mbedtls_md_hmac_update( &ctx, t, t_len );
156
        if( ret != 0 )
157
        {
158
            goto exit;
159
        }
160
 
161
        ret = mbedtls_md_hmac_update( &ctx, info, info_len );
162
        if( ret != 0 )
163
        {
164
            goto exit;
165
        }
166
 
167
        /* The constant concatenated to the end of each T(n) is a single octet.
168
         * */
169
        ret = mbedtls_md_hmac_update( &ctx, &c, 1 );
170
        if( ret != 0 )
171
        {
172
            goto exit;
173
        }
174
 
175
        ret = mbedtls_md_hmac_finish( &ctx, t );
176
        if( ret != 0 )
177
        {
178
            goto exit;
179
        }
180
 
181
        num_to_copy = i != n ? hash_len : okm_len - where;
182
        memcpy( okm + where, t, num_to_copy );
183
        where += hash_len;
184
        t_len = hash_len;
185
    }
186
 
187
exit:
188
    mbedtls_md_free( &ctx );
189
    mbedtls_platform_zeroize( t, sizeof( t ) );
190
 
191
    return( ret );
192
}
193
 
194
#endif /* MBEDTLS_HKDF_C */