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 }