1 /*
2 * Copyright (c) 2021 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 #include <stdio.h>
28 #include <memory>
29 #include <cassert>
30 #include <openssl/evp.h>
31 #include <openssl/err.h>
32 #include "config.h"
33 #include "hash.h"
34 #include "types.h"
35 #include "utils.h"
36 #include "str-utils.h"
37 #include "defaults.h"
38 #include "sha1cd/hash_sha1cd.h"
39
40 static const id_str_pair openssl_alg_map[] = {
41 {PGP_HASH_MD5, "md5"},
42 {PGP_HASH_SHA1, "sha1"},
43 {PGP_HASH_RIPEMD, "ripemd160"},
44 {PGP_HASH_SHA256, "sha256"},
45 {PGP_HASH_SHA384, "sha384"},
46 {PGP_HASH_SHA512, "sha512"},
47 {PGP_HASH_SHA224, "sha224"},
48 {PGP_HASH_SM3, "sm3"},
49 {PGP_HASH_SHA3_256, "sha3-256"},
50 {PGP_HASH_SHA3_512, "sha3-512"},
51 {0, NULL},
52 };
53
54 namespace rnp {
Hash(pgp_hash_alg_t alg)55 Hash::Hash(pgp_hash_alg_t alg)
56 {
57 if (alg == PGP_HASH_SHA1) {
58 handle_ = hash_sha1cd_create();
59 if (!handle_) {
60 throw rnp_exception(RNP_ERROR_OUT_OF_MEMORY);
61 }
62 alg_ = alg;
63 size_ = rnp::Hash::size(alg);
64 return;
65 }
66 const char *hash_name = rnp::Hash::name_backend(alg);
67 if (!hash_name) {
68 throw rnp_exception(RNP_ERROR_BAD_PARAMETERS);
69 }
70 #if !defined(ENABLE_SM2)
71 if (alg == PGP_HASH_SM3) {
72 RNP_LOG("SM3 hash is not available.");
73 throw rnp_exception(RNP_ERROR_BAD_PARAMETERS);
74 }
75 #endif
76 const EVP_MD *hash_tp = EVP_get_digestbyname(hash_name);
77 if (!hash_tp) {
78 RNP_LOG("Error creating hash object for '%s'", hash_name);
79 throw rnp_exception(RNP_ERROR_BAD_STATE);
80 }
81 EVP_MD_CTX *hash_fn = EVP_MD_CTX_new();
82 if (!hash_fn) {
83 RNP_LOG("Allocation failure");
84 throw rnp_exception(RNP_ERROR_OUT_OF_MEMORY);
85 }
86 int res = EVP_DigestInit_ex(hash_fn, hash_tp, NULL);
87 if (res != 1) {
88 RNP_LOG("Digest initializataion error %d : %lu", res, ERR_peek_last_error());
89 EVP_MD_CTX_free(hash_fn);
90 throw rnp_exception(RNP_ERROR_BAD_STATE);
91 }
92
93 alg_ = alg;
94 size_ = EVP_MD_size(hash_tp);
95 handle_ = hash_fn;
96 }
97
98 void
add(const void * buf,size_t len)99 Hash::add(const void *buf, size_t len)
100 {
101 if (!handle_) {
102 throw rnp_exception(RNP_ERROR_NULL_POINTER);
103 }
104 if (alg_ == PGP_HASH_SHA1) {
105 hash_sha1cd_add(handle_, buf, len);
106 return;
107 }
108 assert(alg_ != PGP_HASH_UNKNOWN);
109
110 EVP_MD_CTX *hash_fn = static_cast<EVP_MD_CTX *>(handle_);
111 int res = EVP_DigestUpdate(hash_fn, buf, len);
112 if (res != 1) {
113 RNP_LOG("Digest updating error %d: %lu", res, ERR_peek_last_error());
114 throw rnp_exception(RNP_ERROR_GENERIC);
115 }
116 }
117
118 size_t
finish(uint8_t * digest)119 Hash::finish(uint8_t *digest)
120 {
121 if (!handle_) {
122 return 0;
123 }
124 if (alg_ == PGP_HASH_SHA1) {
125 int res = hash_sha1cd_finish(handle_, digest);
126 handle_ = NULL;
127 size_ = 0;
128 if (res) {
129 throw rnp_exception(RNP_ERROR_BAD_STATE);
130 }
131 return 20;
132 }
133 assert(alg_ != PGP_HASH_UNKNOWN);
134
135 EVP_MD_CTX *hash_fn = static_cast<EVP_MD_CTX *>(handle_);
136 int res = digest ? EVP_DigestFinal_ex(hash_fn, digest, NULL) : 1;
137 EVP_MD_CTX_free(hash_fn);
138 handle_ = NULL;
139 if (res != 1) {
140 RNP_LOG("Digest finalization error %d: %lu", res, ERR_peek_last_error());
141 return 0;
142 }
143
144 size_t outsz = size_;
145 size_ = 0;
146 alg_ = PGP_HASH_UNKNOWN;
147 return outsz;
148 }
149
150 void
clone(Hash & dst) const151 Hash::clone(Hash &dst) const
152 {
153 if (!handle_) {
154 throw rnp_exception(RNP_ERROR_BAD_PARAMETERS);
155 }
156
157 assert(alg_ != PGP_HASH_UNKNOWN);
158
159 if (dst.handle_) {
160 dst.finish();
161 }
162
163 if (alg_ == PGP_HASH_SHA1) {
164 dst.handle_ = hash_sha1cd_clone(handle_);
165 if (!dst.handle_) {
166 throw rnp_exception(RNP_ERROR_OUT_OF_MEMORY);
167 }
168 dst.size_ = size_;
169 dst.alg_ = alg_;
170 return;
171 }
172
173 EVP_MD_CTX *hash_fn = EVP_MD_CTX_new();
174 if (!hash_fn) {
175 RNP_LOG("Allocation failure");
176 throw rnp_exception(RNP_ERROR_OUT_OF_MEMORY);
177 }
178
179 int res = EVP_MD_CTX_copy(hash_fn, static_cast<EVP_MD_CTX *>(handle_));
180 if (res != 1) {
181 RNP_LOG("Digest copying error %d: %lu", res, ERR_peek_last_error());
182 EVP_MD_CTX_free(hash_fn);
183 throw rnp_exception(RNP_ERROR_BAD_STATE);
184 }
185
186 dst.size_ = size_;
187 dst.alg_ = alg_;
188 dst.handle_ = hash_fn;
189 }
190
~Hash()191 Hash::~Hash()
192 {
193 if (!handle_) {
194 return;
195 }
196 if (alg_ == PGP_HASH_SHA1) {
197 hash_sha1cd_finish(handle_, NULL);
198 } else {
199 EVP_MD_CTX_free(static_cast<EVP_MD_CTX *>(handle_));
200 }
201 }
202
203 const char *
name_backend(pgp_hash_alg_t alg)204 Hash::name_backend(pgp_hash_alg_t alg)
205 {
206 return id_str_pair::lookup(openssl_alg_map, alg);
207 }
208 } // namespace rnp
209