1 /* 2 * QEMU Crypto hash algorithms 3 * 4 * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates 5 * Copyright (c) 2015 Red Hat, Inc. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19 * 20 */ 21 22 #include "qemu/osdep.h" 23 #include "qapi/error.h" 24 #include "qapi-types-crypto.h" 25 #include "crypto/hash.h" 26 #include "hashpriv.h" 27 28 static size_t qcrypto_hash_alg_size[QCRYPTO_HASH_ALGO__MAX] = { 29 [QCRYPTO_HASH_ALGO_MD5] = QCRYPTO_HASH_DIGEST_LEN_MD5, 30 [QCRYPTO_HASH_ALGO_SHA1] = QCRYPTO_HASH_DIGEST_LEN_SHA1, 31 [QCRYPTO_HASH_ALGO_SHA224] = QCRYPTO_HASH_DIGEST_LEN_SHA224, 32 [QCRYPTO_HASH_ALGO_SHA256] = QCRYPTO_HASH_DIGEST_LEN_SHA256, 33 [QCRYPTO_HASH_ALGO_SHA384] = QCRYPTO_HASH_DIGEST_LEN_SHA384, 34 [QCRYPTO_HASH_ALGO_SHA512] = QCRYPTO_HASH_DIGEST_LEN_SHA512, 35 [QCRYPTO_HASH_ALGO_RIPEMD160] = QCRYPTO_HASH_DIGEST_LEN_RIPEMD160, 36 #ifdef CONFIG_CRYPTO_SM3 37 [QCRYPTO_HASH_ALGO_SM3] = QCRYPTO_HASH_DIGEST_LEN_SM3, 38 #endif 39 }; 40 41 size_t qcrypto_hash_digest_len(QCryptoHashAlgo alg) 42 { 43 assert(alg < G_N_ELEMENTS(qcrypto_hash_alg_size)); 44 return qcrypto_hash_alg_size[alg]; 45 } 46 47 int qcrypto_hash_bytesv(QCryptoHashAlgo alg, 48 const struct iovec *iov, 49 size_t niov, 50 uint8_t **result, 51 size_t *resultlen, 52 Error **errp) 53 { 54 g_autoptr(QCryptoHash) ctx = qcrypto_hash_new(alg, errp); 55 56 if (!ctx) { 57 return -1; 58 } 59 60 if (qcrypto_hash_updatev(ctx, iov, niov, errp) < 0 || 61 qcrypto_hash_finalize_bytes(ctx, result, resultlen, errp) < 0) { 62 return -1; 63 } 64 65 return 0; 66 } 67 68 69 int qcrypto_hash_bytes(QCryptoHashAlgo alg, 70 const char *buf, 71 size_t len, 72 uint8_t **result, 73 size_t *resultlen, 74 Error **errp) 75 { 76 struct iovec iov = { .iov_base = (char *)buf, 77 .iov_len = len }; 78 return qcrypto_hash_bytesv(alg, &iov, 1, result, resultlen, errp); 79 } 80 81 int qcrypto_hash_updatev(QCryptoHash *hash, 82 const struct iovec *iov, 83 size_t niov, 84 Error **errp) 85 { 86 QCryptoHashDriver *drv = hash->driver; 87 88 return drv->hash_update(hash, iov, niov, errp); 89 } 90 91 int qcrypto_hash_update(QCryptoHash *hash, 92 const char *buf, 93 size_t len, 94 Error **errp) 95 { 96 struct iovec iov = { .iov_base = (char *)buf, .iov_len = len }; 97 98 return qcrypto_hash_updatev(hash, &iov, 1, errp); 99 } 100 101 QCryptoHash *qcrypto_hash_new(QCryptoHashAlgo alg, Error **errp) 102 { 103 QCryptoHash *hash = NULL; 104 105 if (!qcrypto_hash_supports(alg)) { 106 error_setg(errp, "Unsupported hash algorithm %s", 107 QCryptoHashAlgo_str(alg)); 108 return NULL; 109 } 110 111 #ifdef CONFIG_AF_ALG 112 hash = qcrypto_hash_afalg_driver.hash_new(alg, NULL); 113 if (hash) { 114 hash->driver = &qcrypto_hash_afalg_driver; 115 return hash; 116 } 117 #endif 118 119 hash = qcrypto_hash_lib_driver.hash_new(alg, errp); 120 if (!hash) { 121 return NULL; 122 } 123 124 hash->driver = &qcrypto_hash_lib_driver; 125 return hash; 126 } 127 128 void qcrypto_hash_free(QCryptoHash *hash) 129 { 130 QCryptoHashDriver *drv; 131 132 if (hash) { 133 drv = hash->driver; 134 drv->hash_free(hash); 135 } 136 } 137 138 int qcrypto_hash_finalize_bytes(QCryptoHash *hash, 139 uint8_t **result, 140 size_t *result_len, 141 Error **errp) 142 { 143 QCryptoHashDriver *drv = hash->driver; 144 145 return drv->hash_finalize(hash, result, result_len, errp); 146 } 147 148 static const char hex[] = "0123456789abcdef"; 149 150 int qcrypto_hash_finalize_digest(QCryptoHash *hash, 151 char **digest, 152 Error **errp) 153 { 154 int ret; 155 g_autofree uint8_t *result = NULL; 156 size_t resultlen = 0; 157 size_t i; 158 159 ret = qcrypto_hash_finalize_bytes(hash, &result, &resultlen, errp); 160 if (ret == 0) { 161 *digest = g_new0(char, (resultlen * 2) + 1); 162 for (i = 0 ; i < resultlen ; i++) { 163 (*digest)[(i * 2)] = hex[(result[i] >> 4) & 0xf]; 164 (*digest)[(i * 2) + 1] = hex[result[i] & 0xf]; 165 } 166 (*digest)[resultlen * 2] = '\0'; 167 } 168 169 return ret; 170 } 171 172 int qcrypto_hash_finalize_base64(QCryptoHash *hash, 173 char **base64, 174 Error **errp) 175 { 176 int ret; 177 g_autofree uint8_t *result = NULL; 178 size_t resultlen = 0; 179 180 ret = qcrypto_hash_finalize_bytes(hash, &result, &resultlen, errp); 181 if (ret == 0) { 182 *base64 = g_base64_encode(result, resultlen); 183 } 184 185 return ret; 186 } 187 188 int qcrypto_hash_digestv(QCryptoHashAlgo alg, 189 const struct iovec *iov, 190 size_t niov, 191 char **digest, 192 Error **errp) 193 { 194 g_autoptr(QCryptoHash) ctx = qcrypto_hash_new(alg, errp); 195 196 if (!ctx) { 197 return -1; 198 } 199 200 if (qcrypto_hash_updatev(ctx, iov, niov, errp) < 0 || 201 qcrypto_hash_finalize_digest(ctx, digest, errp) < 0) { 202 return -1; 203 } 204 205 return 0; 206 } 207 208 int qcrypto_hash_digest(QCryptoHashAlgo alg, 209 const char *buf, 210 size_t len, 211 char **digest, 212 Error **errp) 213 { 214 struct iovec iov = { .iov_base = (char *)buf, .iov_len = len }; 215 216 return qcrypto_hash_digestv(alg, &iov, 1, digest, errp); 217 } 218 219 int qcrypto_hash_base64v(QCryptoHashAlgo alg, 220 const struct iovec *iov, 221 size_t niov, 222 char **base64, 223 Error **errp) 224 { 225 g_autoptr(QCryptoHash) ctx = qcrypto_hash_new(alg, errp); 226 227 if (!ctx) { 228 return -1; 229 } 230 231 if (qcrypto_hash_updatev(ctx, iov, niov, errp) < 0 || 232 qcrypto_hash_finalize_base64(ctx, base64, errp) < 0) { 233 return -1; 234 } 235 236 return 0; 237 } 238 239 int qcrypto_hash_base64(QCryptoHashAlgo alg, 240 const char *buf, 241 size_t len, 242 char **base64, 243 Error **errp) 244 { 245 struct iovec iov = { .iov_base = (char *)buf, .iov_len = len }; 246 247 return qcrypto_hash_base64v(alg, &iov, 1, base64, errp); 248 } 249