User | Revision | Line number | New contents of line |
kevman |
0:38ceb79fef03
|
1
|
/*
|
kevman |
0:38ceb79fef03
|
2
|
* HKDF implementation -- RFC 5869
|
kevman |
0:38ceb79fef03
|
3
|
*
|
kevman |
0:38ceb79fef03
|
4
|
* Copyright (C) 2016-2018, ARM Limited, All Rights Reserved
|
kevman |
0:38ceb79fef03
|
5
|
* SPDX-License-Identifier: Apache-2.0
|
kevman |
0:38ceb79fef03
|
6
|
*
|
kevman |
0:38ceb79fef03
|
7
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
kevman |
0:38ceb79fef03
|
8
|
* not use this file except in compliance with the License.
|
kevman |
0:38ceb79fef03
|
9
|
* You may obtain a copy of the License at
|
kevman |
0:38ceb79fef03
|
10
|
*
|
kevman |
0:38ceb79fef03
|
11
|
* http://www.apache.org/licenses/LICENSE-2.0
|
kevman |
0:38ceb79fef03
|
12
|
*
|
kevman |
0:38ceb79fef03
|
13
|
* Unless required by applicable law or agreed to in writing, software
|
kevman |
0:38ceb79fef03
|
14
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
kevman |
0:38ceb79fef03
|
15
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
kevman |
0:38ceb79fef03
|
16
|
* See the License for the specific language governing permissions and
|
kevman |
0:38ceb79fef03
|
17
|
* limitations under the License.
|
kevman |
0:38ceb79fef03
|
18
|
*
|
kevman |
0:38ceb79fef03
|
19
|
* This file is part of mbed TLS (https://tls.mbed.org)
|
kevman |
0:38ceb79fef03
|
20
|
*/
|
kevman |
0:38ceb79fef03
|
21
|
#if !defined(MBEDTLS_CONFIG_FILE)
|
kevman |
0:38ceb79fef03
|
22
|
#include "mbedtls/config.h"
|
kevman |
0:38ceb79fef03
|
23
|
#else
|
kevman |
0:38ceb79fef03
|
24
|
#include MBEDTLS_CONFIG_FILE
|
kevman |
0:38ceb79fef03
|
25
|
#endif
|
kevman |
0:38ceb79fef03
|
26
|
|
kevman |
0:38ceb79fef03
|
27
|
#if defined(MBEDTLS_HKDF_C)
|
kevman |
0:38ceb79fef03
|
28
|
|
kevman |
0:38ceb79fef03
|
29
|
#include <string.h>
|
kevman |
0:38ceb79fef03
|
30
|
#include "mbedtls/hkdf.h"
|
kevman |
0:38ceb79fef03
|
31
|
#include "mbedtls/platform_util.h"
|
kevman |
0:38ceb79fef03
|
32
|
|
kevman |
0:38ceb79fef03
|
33
|
int mbedtls_hkdf( const mbedtls_md_info_t *md, const unsigned char *salt,
|
kevman |
0:38ceb79fef03
|
34
|
size_t salt_len, const unsigned char *ikm, size_t ikm_len,
|
kevman |
0:38ceb79fef03
|
35
|
const unsigned char *info, size_t info_len,
|
kevman |
0:38ceb79fef03
|
36
|
unsigned char *okm, size_t okm_len )
|
kevman |
0:38ceb79fef03
|
37
|
{
|
kevman |
0:38ceb79fef03
|
38
|
int ret;
|
kevman |
0:38ceb79fef03
|
39
|
unsigned char prk[MBEDTLS_MD_MAX_SIZE];
|
kevman |
0:38ceb79fef03
|
40
|
|
kevman |
0:38ceb79fef03
|
41
|
ret = mbedtls_hkdf_extract( md, salt, salt_len, ikm, ikm_len, prk );
|
kevman |
0:38ceb79fef03
|
42
|
|
kevman |
0:38ceb79fef03
|
43
|
if( ret == 0 )
|
kevman |
0:38ceb79fef03
|
44
|
{
|
kevman |
0:38ceb79fef03
|
45
|
ret = mbedtls_hkdf_expand( md, prk, mbedtls_md_get_size( md ),
|
kevman |
0:38ceb79fef03
|
46
|
info, info_len, okm, okm_len );
|
kevman |
0:38ceb79fef03
|
47
|
}
|
kevman |
0:38ceb79fef03
|
48
|
|
kevman |
0:38ceb79fef03
|
49
|
mbedtls_platform_zeroize( prk, sizeof( prk ) );
|
kevman |
0:38ceb79fef03
|
50
|
|
kevman |
0:38ceb79fef03
|
51
|
return( ret );
|
kevman |
0:38ceb79fef03
|
52
|
}
|
kevman |
0:38ceb79fef03
|
53
|
|
kevman |
0:38ceb79fef03
|
54
|
int mbedtls_hkdf_extract( const mbedtls_md_info_t *md,
|
kevman |
0:38ceb79fef03
|
55
|
const unsigned char *salt, size_t salt_len,
|
kevman |
0:38ceb79fef03
|
56
|
const unsigned char *ikm, size_t ikm_len,
|
kevman |
0:38ceb79fef03
|
57
|
unsigned char *prk )
|
kevman |
0:38ceb79fef03
|
58
|
{
|
kevman |
0:38ceb79fef03
|
59
|
unsigned char null_salt[MBEDTLS_MD_MAX_SIZE] = { '\0' };
|
kevman |
0:38ceb79fef03
|
60
|
|
kevman |
0:38ceb79fef03
|
61
|
if( salt == NULL )
|
kevman |
0:38ceb79fef03
|
62
|
{
|
kevman |
0:38ceb79fef03
|
63
|
size_t hash_len;
|
kevman |
0:38ceb79fef03
|
64
|
|
kevman |
0:38ceb79fef03
|
65
|
if( salt_len != 0 )
|
kevman |
0:38ceb79fef03
|
66
|
{
|
kevman |
0:38ceb79fef03
|
67
|
return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
|
kevman |
0:38ceb79fef03
|
68
|
}
|
kevman |
0:38ceb79fef03
|
69
|
|
kevman |
0:38ceb79fef03
|
70
|
hash_len = mbedtls_md_get_size( md );
|
kevman |
0:38ceb79fef03
|
71
|
|
kevman |
0:38ceb79fef03
|
72
|
if( hash_len == 0 )
|
kevman |
0:38ceb79fef03
|
73
|
{
|
kevman |
0:38ceb79fef03
|
74
|
return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
|
kevman |
0:38ceb79fef03
|
75
|
}
|
kevman |
0:38ceb79fef03
|
76
|
|
kevman |
0:38ceb79fef03
|
77
|
salt = null_salt;
|
kevman |
0:38ceb79fef03
|
78
|
salt_len = hash_len;
|
kevman |
0:38ceb79fef03
|
79
|
}
|
kevman |
0:38ceb79fef03
|
80
|
|
kevman |
0:38ceb79fef03
|
81
|
return( mbedtls_md_hmac( md, salt, salt_len, ikm, ikm_len, prk ) );
|
kevman |
0:38ceb79fef03
|
82
|
}
|
kevman |
0:38ceb79fef03
|
83
|
|
kevman |
0:38ceb79fef03
|
84
|
int mbedtls_hkdf_expand( const mbedtls_md_info_t *md, const unsigned char *prk,
|
kevman |
0:38ceb79fef03
|
85
|
size_t prk_len, const unsigned char *info,
|
kevman |
0:38ceb79fef03
|
86
|
size_t info_len, unsigned char *okm, size_t okm_len )
|
kevman |
0:38ceb79fef03
|
87
|
{
|
kevman |
0:38ceb79fef03
|
88
|
size_t hash_len;
|
kevman |
0:38ceb79fef03
|
89
|
size_t where = 0;
|
kevman |
0:38ceb79fef03
|
90
|
size_t n;
|
kevman |
0:38ceb79fef03
|
91
|
size_t t_len = 0;
|
kevman |
0:38ceb79fef03
|
92
|
size_t i;
|
kevman |
0:38ceb79fef03
|
93
|
int ret = 0;
|
kevman |
0:38ceb79fef03
|
94
|
mbedtls_md_context_t ctx;
|
kevman |
0:38ceb79fef03
|
95
|
unsigned char t[MBEDTLS_MD_MAX_SIZE];
|
kevman |
0:38ceb79fef03
|
96
|
|
kevman |
0:38ceb79fef03
|
97
|
if( okm == NULL )
|
kevman |
0:38ceb79fef03
|
98
|
{
|
kevman |
0:38ceb79fef03
|
99
|
return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA );
|
kevman |
0:38ceb79fef03
|
100
|
}
|
kevman |
0:38ceb79fef03
|
101
|
|
kevman |
0:38ceb79fef03
|
102
|
hash_len = mbedtls_md_get_size( md );
|
kevman |
0:38ceb79fef03
|
103
|
|
kevman |
0:38ceb79fef03
|
104
|
if( prk_len < hash_len || hash_len == 0 )
|
kevman |
0:38ceb79fef03
|
105
|
{
|
kevman |
0:38ceb79fef03
|
106
|
return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA );
|
kevman |
0:38ceb79fef03
|
107
|
}
|
kevman |
0:38ceb79fef03
|
108
|
|
kevman |
0:38ceb79fef03
|
109
|
if( info == NULL )
|
kevman |
0:38ceb79fef03
|
110
|
{
|
kevman |
0:38ceb79fef03
|
111
|
info = (const unsigned char *) "";
|
kevman |
0:38ceb79fef03
|
112
|
info_len = 0;
|
kevman |
0:38ceb79fef03
|
113
|
}
|
kevman |
0:38ceb79fef03
|
114
|
|
kevman |
0:38ceb79fef03
|
115
|
n = okm_len / hash_len;
|
kevman |
0:38ceb79fef03
|
116
|
|
kevman |
0:38ceb79fef03
|
117
|
if( (okm_len % hash_len) != 0 )
|
kevman |
0:38ceb79fef03
|
118
|
{
|
kevman |
0:38ceb79fef03
|
119
|
n++;
|
kevman |
0:38ceb79fef03
|
120
|
}
|
kevman |
0:38ceb79fef03
|
121
|
|
kevman |
0:38ceb79fef03
|
122
|
/*
|
kevman |
0:38ceb79fef03
|
123
|
* Per RFC 5869 Section 2.3, okm_len must not exceed
|
kevman |
0:38ceb79fef03
|
124
|
* 255 times the hash length
|
kevman |
0:38ceb79fef03
|
125
|
*/
|
kevman |
0:38ceb79fef03
|
126
|
if( n > 255 )
|
kevman |
0:38ceb79fef03
|
127
|
{
|
kevman |
0:38ceb79fef03
|
128
|
return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA );
|
kevman |
0:38ceb79fef03
|
129
|
}
|
kevman |
0:38ceb79fef03
|
130
|
|
kevman |
0:38ceb79fef03
|
131
|
mbedtls_md_init( &ctx );
|
kevman |
0:38ceb79fef03
|
132
|
|
kevman |
0:38ceb79fef03
|
133
|
if( (ret = mbedtls_md_setup( &ctx, md, 1) ) != 0 )
|
kevman |
0:38ceb79fef03
|
134
|
{
|
kevman |
0:38ceb79fef03
|
135
|
goto exit;
|
kevman |
0:38ceb79fef03
|
136
|
}
|
kevman |
0:38ceb79fef03
|
137
|
|
kevman |
0:38ceb79fef03
|
138
|
/*
|
kevman |
0:38ceb79fef03
|
139
|
* Compute T = T(1) | T(2) | T(3) | ... | T(N)
|
kevman |
0:38ceb79fef03
|
140
|
* Where T(N) is defined in RFC 5869 Section 2.3
|
kevman |
0:38ceb79fef03
|
141
|
*/
|
kevman |
0:38ceb79fef03
|
142
|
for( i = 1; i <= n; i++ )
|
kevman |
0:38ceb79fef03
|
143
|
{
|
kevman |
0:38ceb79fef03
|
144
|
size_t num_to_copy;
|
kevman |
0:38ceb79fef03
|
145
|
unsigned char c = i & 0xff;
|
kevman |
0:38ceb79fef03
|
146
|
|
kevman |
0:38ceb79fef03
|
147
|
ret = mbedtls_md_hmac_starts( &ctx, prk, prk_len );
|
kevman |
0:38ceb79fef03
|
148
|
if( ret != 0 )
|
kevman |
0:38ceb79fef03
|
149
|
{
|
kevman |
0:38ceb79fef03
|
150
|
goto exit;
|
kevman |
0:38ceb79fef03
|
151
|
}
|
kevman |
0:38ceb79fef03
|
152
|
|
kevman |
0:38ceb79fef03
|
153
|
ret = mbedtls_md_hmac_update( &ctx, t, t_len );
|
kevman |
0:38ceb79fef03
|
154
|
if( ret != 0 )
|
kevman |
0:38ceb79fef03
|
155
|
{
|
kevman |
0:38ceb79fef03
|
156
|
goto exit;
|
kevman |
0:38ceb79fef03
|
157
|
}
|
kevman |
0:38ceb79fef03
|
158
|
|
kevman |
0:38ceb79fef03
|
159
|
ret = mbedtls_md_hmac_update( &ctx, info, info_len );
|
kevman |
0:38ceb79fef03
|
160
|
if( ret != 0 )
|
kevman |
0:38ceb79fef03
|
161
|
{
|
kevman |
0:38ceb79fef03
|
162
|
goto exit;
|
kevman |
0:38ceb79fef03
|
163
|
}
|
kevman |
0:38ceb79fef03
|
164
|
|
kevman |
0:38ceb79fef03
|
165
|
/* The constant concatenated to the end of each T(n) is a single octet.
|
kevman |
0:38ceb79fef03
|
166
|
* */
|
kevman |
0:38ceb79fef03
|
167
|
ret = mbedtls_md_hmac_update( &ctx, &c, 1 );
|
kevman |
0:38ceb79fef03
|
168
|
if( ret != 0 )
|
kevman |
0:38ceb79fef03
|
169
|
{
|
kevman |
0:38ceb79fef03
|
170
|
goto exit;
|
kevman |
0:38ceb79fef03
|
171
|
}
|
kevman |
0:38ceb79fef03
|
172
|
|
kevman |
0:38ceb79fef03
|
173
|
ret = mbedtls_md_hmac_finish( &ctx, t );
|
kevman |
0:38ceb79fef03
|
174
|
if( ret != 0 )
|
kevman |
0:38ceb79fef03
|
175
|
{
|
kevman |
0:38ceb79fef03
|
176
|
goto exit;
|
kevman |
0:38ceb79fef03
|
177
|
}
|
kevman |
0:38ceb79fef03
|
178
|
|
kevman |
0:38ceb79fef03
|
179
|
num_to_copy = i != n ? hash_len : okm_len - where;
|
kevman |
0:38ceb79fef03
|
180
|
memcpy( okm + where, t, num_to_copy );
|
kevman |
0:38ceb79fef03
|
181
|
where += hash_len;
|
kevman |
0:38ceb79fef03
|
182
|
t_len = hash_len;
|
kevman |
0:38ceb79fef03
|
183
|
}
|
kevman |
0:38ceb79fef03
|
184
|
|
kevman |
0:38ceb79fef03
|
185
|
exit:
|
kevman |
0:38ceb79fef03
|
186
|
mbedtls_md_free( &ctx );
|
kevman |
0:38ceb79fef03
|
187
|
mbedtls_platform_zeroize( t, sizeof( t ) );
|
kevman |
0:38ceb79fef03
|
188
|
|
kevman |
0:38ceb79fef03
|
189
|
return( ret );
|
kevman |
0:38ceb79fef03
|
190
|
}
|
kevman |
0:38ceb79fef03
|
191
|
|
kevman |
0:38ceb79fef03
|
192
|
#endif /* MBEDTLS_HKDF_C */
|