File indexing completed on 2024-04-28 04:43:43

0001 /*
0002  * Copyright (C) 2011 Collabora Ltd.
0003  * Copyright (C) 2018 Alexander Volkov <a.volkov@rusbitech.ru>
0004  *
0005  * This program is free software; you can redistribute it and/or modify
0006  * it under the terms of the GNU Lesser General Public License as
0007  * published by the Free Software Foundation; either version 2.1 of
0008  * the License, or (at your option) any later version.
0009  *
0010  * This program is distributed in the hope that it will be useful, but
0011  * WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013  * Lesser General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU Lesser General Public
0016  * License along with this program; if not, write to the Free Software
0017  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
0018  * MA 02110-1301 USA
0019  *
0020  * Author: Stef Walter <stefw@collabora.co.uk>
0021  */
0022 
0023 #include <gcrypt.h>
0024 
0025 static gcry_error_t gcry_hkdf(int         algo,
0026                               const char *input,
0027                               size_t      n_input,
0028                               const char *salt,
0029                               size_t      n_salt,
0030                               const char *info,
0031                               size_t      n_info,
0032                               char       *output,
0033                               size_t      n_output)
0034 {
0035     void        *alloc  = nullptr;
0036     void        *buffer = nullptr;
0037     gcry_md_hd_t md1, md2;
0038     unsigned int hash_len;
0039     int          i;
0040     size_t       step, n_buffer;
0041     char        *at;
0042     gcry_error_t gcry;
0043 
0044     hash_len = gcry_md_get_algo_dlen(algo);
0045     if (hash_len == 0) {
0046         return GPG_ERR_UNSUPPORTED_ALGORITHM;
0047     }
0048 
0049     if (n_output > 255 * hash_len) {
0050         return GPG_ERR_TOO_LARGE;
0051     }
0052 
0053     /* Buffer we need to for intermediate stuff */
0054     buffer = gcry_malloc_secure(hash_len);
0055     if (!buffer) {
0056         return GPG_ERR_ENOMEM;
0057     }
0058     n_buffer = 0;
0059 
0060     /* Salt defaults to hash_len zeros */
0061     if (!salt) {
0062         alloc = gcry_calloc_secure(hash_len, 1);
0063         if (!alloc) {
0064             return GPG_ERR_ENOMEM;
0065         }
0066         salt   = (const char *)alloc;
0067         n_salt = hash_len;
0068     }
0069 
0070     /* Step 1: Extract */
0071     gcry = gcry_md_open(&md1, algo, GCRY_MD_FLAG_HMAC | GCRY_MD_FLAG_SECURE);
0072     if (gcry != GPG_ERR_NO_ERROR) {
0073         goto done;
0074     }
0075     gcry = gcry_md_setkey(md1, salt, n_salt);
0076     if (gcry != GPG_ERR_NO_ERROR) {
0077         gcry_md_close(md1);
0078         goto done;
0079     }
0080     gcry_md_write(md1, input, n_input);
0081 
0082     /* Step 2: Expand */
0083     gcry = gcry_md_open(&md2, algo, GCRY_MD_FLAG_HMAC | GCRY_MD_FLAG_SECURE);
0084     if (gcry != GPG_ERR_NO_ERROR) {
0085         gcry_md_close(md1);
0086         goto done;
0087     }
0088     gcry = gcry_md_setkey(md2, gcry_md_read(md1, algo), hash_len);
0089     if (gcry != GPG_ERR_NO_ERROR) {
0090         gcry_md_close(md2);
0091         gcry_md_close(md1);
0092         goto done;
0093     }
0094     gcry_md_close(md1);
0095 
0096     at = output;
0097     for (i = 1; i < 256; ++i) {
0098         gcry_md_reset(md2);
0099         gcry_md_write(md2, buffer, n_buffer);
0100         gcry_md_write(md2, info, n_info);
0101         gcry_md_putc(md2, i);
0102 
0103         n_buffer = hash_len;
0104         memcpy(buffer, gcry_md_read(md2, algo), n_buffer);
0105 
0106         step = n_buffer < n_output ? n_buffer : n_output;
0107         memcpy(at, buffer, step);
0108         n_output -= step;
0109         at += step;
0110 
0111         if (!n_output)
0112             break;
0113     }
0114     gcry_md_close(md2);
0115 
0116 done:
0117     gcry_free(alloc);
0118     gcry_free(buffer);
0119     return gcry;
0120 }