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