1 /*-
2 * Copyright (c) 2017-2019 Ribose Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 /*-
28 * Copyright (c) 2009 The NetBSD Foundation, Inc.
29 * All rights reserved.
30 *
31 * This code is derived from software contributed to The NetBSD Foundation
32 * by Alistair Crooks (agc@NetBSD.org)
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
44 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
45 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
46 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
47 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
48 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
49 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
50 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
51 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
52 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
53 * POSSIBILITY OF SUCH DAMAGE.
54 */
55 /*
56 * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
57 * All rights reserved.
58 * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
59 * their moral rights under the UK Copyright Design and Patents Act 1988 to
60 * be recorded as the authors of this copyright work.
61 *
62 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
63 * use this file except in compliance with the License.
64 *
65 * You may obtain a copy of the License at
66 * http://www.apache.org/licenses/LICENSE-2.0
67 *
68 * Unless required by applicable law or agreed to in writing, software
69 * distributed under the License is distributed on an "AS IS" BASIS,
70 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
71 *
72 * See the License for the specific language governing permissions and
73 * limitations under the License.
74 */
75
76 #include <stdio.h>
77 #include <memory>
78 #include <botan/hash.h>
79 #include "hash.h"
80 #include "types.h"
81 #include "utils.h"
82 #include "defaults.h"
83
84 static const struct hash_alg_map_t {
85 pgp_hash_alg_t type;
86 const char * name;
87 const char * botan_name;
88 size_t digest_size;
89 } hash_alg_map[] = {{PGP_HASH_MD5, "MD5", "MD5", 16},
90 {PGP_HASH_SHA1, "SHA1", "SHA-1", 20},
91 {PGP_HASH_RIPEMD, "RIPEMD160", "RIPEMD-160", 20},
92 {PGP_HASH_SHA256, "SHA256", "SHA-256", 32},
93 {PGP_HASH_SHA384, "SHA384", "SHA-384", 48},
94 {PGP_HASH_SHA512, "SHA512", "SHA-512", 64},
95 {PGP_HASH_SHA224, "SHA224", "SHA-224", 28},
96 {PGP_HASH_SM3, "SM3", "SM3", 32},
97 {PGP_HASH_SHA3_256, "SHA3-256", "SHA-3(256)", 32},
98 {PGP_HASH_SHA3_512, "SHA3-512", "SHA-3(512)", 64}};
99 /**
100 * \ingroup Core_Print
101 *
102 * returns description of the Hash Algorithm type
103 * \param hash Hash Algorithm type
104 * \return string or "Unknown"
105 */
106 const char *
pgp_show_hash_alg(uint8_t hash)107 pgp_show_hash_alg(uint8_t hash)
108 {
109 const char *ret = NULL;
110 ARRAY_LOOKUP_BY_ID(hash_alg_map, type, name, hash, ret);
111 return ret;
112 }
113
114 const char *
pgp_hash_name_botan(pgp_hash_alg_t hash)115 pgp_hash_name_botan(pgp_hash_alg_t hash)
116 {
117 const char *ret = NULL;
118 ARRAY_LOOKUP_BY_ID(hash_alg_map, type, botan_name, hash, ret);
119 return ret;
120 }
121
122 const char *
pgp_hash_name(const pgp_hash_t * hash)123 pgp_hash_name(const pgp_hash_t *hash)
124 {
125 return pgp_show_hash_alg(hash->_alg);
126 }
127
128 /**
129 \ingroup Core_Hashes
130 \brief Returns hash enum corresponding to given string
131 \param hash Text name of hash algorithm i.e. "SHA1"
132 \returns Corresponding enum i.e. PGP_HASH_SHA1
133 */
134 pgp_hash_alg_t
pgp_str_to_hash_alg(const char * hash)135 pgp_str_to_hash_alg(const char *hash)
136 {
137 if (hash == NULL) {
138 return DEFAULT_PGP_HASH_ALG;
139 }
140 for (size_t i = 0; i < ARRAY_SIZE(hash_alg_map); i++) {
141 if (!rnp_strcasecmp(hash, hash_alg_map[i].name)) {
142 return hash_alg_map[i].type;
143 }
144 }
145 return PGP_HASH_UNKNOWN;
146 }
147
148 static bool
botan_hash_create(pgp_hash_t * hash,const char * hash_name)149 botan_hash_create(pgp_hash_t *hash, const char *hash_name)
150 {
151 if (!hash_name) {
152 return false;
153 }
154
155 std::unique_ptr<Botan::HashFunction> hash_fn;
156 try {
157 hash_fn = Botan::HashFunction::create(hash_name);
158 } catch (std::exception &ex) {
159 RNP_LOG("Error creating HashFunction ('%s')", ex.what());
160 }
161 if (!hash_fn) {
162 RNP_LOG("Error creating hash object for '%s'", hash_name);
163 return false;
164 }
165
166 hash->_output_len = hash_fn->output_length();
167 if (hash->_output_len == 0) {
168 RNP_LOG("In pgp_hash_create, botan_hash_output_length failed");
169 return false;
170 }
171
172 hash->handle = hash_fn.release();
173 return true;
174 }
175
176 /**
177 \ingroup Core_Hashes
178 \brief Setup hash for given hash algorithm
179 \param hash Hash to set up
180 \param alg Hash algorithm to use
181 */
182 bool
pgp_hash_create(pgp_hash_t * hash,pgp_hash_alg_t alg)183 pgp_hash_create(pgp_hash_t *hash, pgp_hash_alg_t alg)
184 {
185 if (!botan_hash_create(hash, pgp_hash_name_botan(alg))) {
186 return false;
187 }
188
189 hash->_alg = alg;
190 return true;
191 }
192
193 bool
pgp_hash_create_crc24(pgp_hash_t * hash)194 pgp_hash_create_crc24(pgp_hash_t *hash)
195 {
196 if (!botan_hash_create(hash, "CRC24")) {
197 return false;
198 }
199
200 hash->_alg = PGP_HASH_UNKNOWN;
201 return true;
202 }
203
204 bool
pgp_hash_copy(pgp_hash_t * dst,const pgp_hash_t * src)205 pgp_hash_copy(pgp_hash_t *dst, const pgp_hash_t *src)
206 {
207 if (!src || !dst) {
208 return false;
209 }
210
211 Botan::HashFunction *hash_fn = static_cast<Botan::HashFunction *>(src->handle);
212 if (!hash_fn) {
213 return false;
214 }
215
216 std::unique_ptr<Botan::HashFunction> handle;
217 try {
218 handle = hash_fn->copy_state();
219 } catch (std::exception &ex) {
220 RNP_LOG("Error copying HashFunction ('%s')", ex.what());
221 }
222 if (!handle) {
223 return false;
224 }
225
226 dst->_output_len = src->_output_len;
227 dst->_alg = src->_alg;
228 dst->handle = handle.release();
229 return true;
230 }
231
232 int
pgp_hash_add(pgp_hash_t * hash,const void * buf,size_t len)233 pgp_hash_add(pgp_hash_t *hash, const void *buf, size_t len)
234 {
235 if (!hash->handle) {
236 return -1;
237 }
238
239 try {
240 static_cast<Botan::HashFunction *>(hash->handle)
241 ->update(static_cast<const uint8_t *>(buf), len);
242 } catch (std::exception &ex) {
243 RNP_LOG("Error adding to HashFunction ('%s')", ex.what());
244 return -2;
245 }
246 return 0;
247 }
248
249 size_t
pgp_hash_finish(pgp_hash_t * hash,uint8_t * out)250 pgp_hash_finish(pgp_hash_t *hash, uint8_t *out)
251 {
252 if (!hash || !hash->handle) {
253 return 0;
254 }
255
256 Botan::HashFunction *hash_fn = static_cast<Botan::HashFunction *>(hash->handle);
257 if (!hash_fn) {
258 RNP_LOG("Hash finalization failed");
259 return 0;
260 }
261
262 size_t outlen = hash->_output_len;
263 hash->handle = NULL;
264 try {
265 if (out) {
266 hash_fn->final(out);
267 }
268 delete hash_fn;
269 } catch (std::exception &ex) {
270 RNP_LOG("Error finishing HashFunction ('%s')", ex.what());
271 outlen = 0;
272 }
273 hash->_output_len = 0;
274 return outlen;
275 }
276
277 pgp_hash_alg_t
pgp_hash_alg_type(const pgp_hash_t * hash)278 pgp_hash_alg_type(const pgp_hash_t *hash)
279 {
280 return hash->_alg;
281 }
282
283 size_t
pgp_digest_length(pgp_hash_alg_t alg)284 pgp_digest_length(pgp_hash_alg_t alg)
285 {
286 size_t val = 0;
287 ARRAY_LOOKUP_BY_ID(hash_alg_map, type, digest_size, alg, val);
288 return val;
289 }
290
291 bool
pgp_hash_list_add(std::vector<pgp_hash_t> & hashes,pgp_hash_alg_t alg)292 pgp_hash_list_add(std::vector<pgp_hash_t> &hashes, pgp_hash_alg_t alg)
293 {
294 pgp_hash_t hash = {0};
295 if (!pgp_hash_list_get(hashes, alg)) {
296 if (!pgp_hash_create(&hash, alg)) {
297 RNP_LOG("failed to initialize hash algorithm %d", (int) alg);
298 return false;
299 }
300 try {
301 hashes.push_back(hash);
302 } catch (const std::exception &e) {
303 RNP_LOG("%s", e.what());
304 pgp_hash_finish(&hash, NULL);
305 return false;
306 }
307 }
308 return true;
309 }
310
311 const pgp_hash_t *
pgp_hash_list_get(std::vector<pgp_hash_t> & hashes,pgp_hash_alg_t alg)312 pgp_hash_list_get(std::vector<pgp_hash_t> &hashes, pgp_hash_alg_t alg)
313 {
314 for (auto &hash : hashes) {
315 if (pgp_hash_alg_type(&hash) == alg) {
316 return &hash;
317 }
318 }
319 return NULL;
320 }
321
322 void
pgp_hash_list_update(std::vector<pgp_hash_t> & hashes,const void * buf,size_t len)323 pgp_hash_list_update(std::vector<pgp_hash_t> &hashes, const void *buf, size_t len)
324 {
325 for (auto &hash : hashes) {
326 pgp_hash_add(&hash, buf, len);
327 }
328 }
329
330 bool
pgp_hash_uint32(pgp_hash_t * hash,uint32_t n)331 pgp_hash_uint32(pgp_hash_t *hash, uint32_t n)
332 {
333 uint8_t ibuf[4];
334 STORE32BE(ibuf, n);
335 return !pgp_hash_add(hash, ibuf, sizeof(ibuf));
336 }
337