1 /* 2 * QEMU Crypto hash algorithms 3 * 4 * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates 5 * Copyright (c) 2016 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 "crypto/hash.h" 25 #include "hashpriv.h" 26 #include <nettle/md5.h> 27 #include <nettle/sha.h> 28 #include <nettle/ripemd160.h> 29 30 typedef void (*qcrypto_nettle_init)(void *ctx); 31 typedef void (*qcrypto_nettle_write)(void *ctx, 32 size_t len, 33 const uint8_t *buf); 34 typedef void (*qcrypto_nettle_result)(void *ctx, 35 size_t len, 36 uint8_t *buf); 37 38 union qcrypto_hash_ctx { 39 struct md5_ctx md5; 40 struct sha1_ctx sha1; 41 struct sha224_ctx sha224; 42 struct sha256_ctx sha256; 43 struct sha384_ctx sha384; 44 struct sha512_ctx sha512; 45 struct ripemd160_ctx ripemd160; 46 }; 47 48 struct qcrypto_hash_alg { 49 qcrypto_nettle_init init; 50 qcrypto_nettle_write write; 51 qcrypto_nettle_result result; 52 size_t len; 53 } qcrypto_hash_alg_map[] = { 54 [QCRYPTO_HASH_ALGO_MD5] = { 55 .init = (qcrypto_nettle_init)md5_init, 56 .write = (qcrypto_nettle_write)md5_update, 57 .result = (qcrypto_nettle_result)md5_digest, 58 .len = MD5_DIGEST_SIZE, 59 }, 60 [QCRYPTO_HASH_ALGO_SHA1] = { 61 .init = (qcrypto_nettle_init)sha1_init, 62 .write = (qcrypto_nettle_write)sha1_update, 63 .result = (qcrypto_nettle_result)sha1_digest, 64 .len = SHA1_DIGEST_SIZE, 65 }, 66 [QCRYPTO_HASH_ALGO_SHA224] = { 67 .init = (qcrypto_nettle_init)sha224_init, 68 .write = (qcrypto_nettle_write)sha224_update, 69 .result = (qcrypto_nettle_result)sha224_digest, 70 .len = SHA224_DIGEST_SIZE, 71 }, 72 [QCRYPTO_HASH_ALGO_SHA256] = { 73 .init = (qcrypto_nettle_init)sha256_init, 74 .write = (qcrypto_nettle_write)sha256_update, 75 .result = (qcrypto_nettle_result)sha256_digest, 76 .len = SHA256_DIGEST_SIZE, 77 }, 78 [QCRYPTO_HASH_ALGO_SHA384] = { 79 .init = (qcrypto_nettle_init)sha384_init, 80 .write = (qcrypto_nettle_write)sha384_update, 81 .result = (qcrypto_nettle_result)sha384_digest, 82 .len = SHA384_DIGEST_SIZE, 83 }, 84 [QCRYPTO_HASH_ALGO_SHA512] = { 85 .init = (qcrypto_nettle_init)sha512_init, 86 .write = (qcrypto_nettle_write)sha512_update, 87 .result = (qcrypto_nettle_result)sha512_digest, 88 .len = SHA512_DIGEST_SIZE, 89 }, 90 [QCRYPTO_HASH_ALGO_RIPEMD160] = { 91 .init = (qcrypto_nettle_init)ripemd160_init, 92 .write = (qcrypto_nettle_write)ripemd160_update, 93 .result = (qcrypto_nettle_result)ripemd160_digest, 94 .len = RIPEMD160_DIGEST_SIZE, 95 }, 96 }; 97 98 gboolean qcrypto_hash_supports(QCryptoHashAlgo alg) 99 { 100 if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map) && 101 qcrypto_hash_alg_map[alg].init != NULL) { 102 return true; 103 } 104 return false; 105 } 106 107 static 108 QCryptoHash *qcrypto_nettle_hash_new(QCryptoHashAlgo alg, Error **errp) 109 { 110 QCryptoHash *hash; 111 112 hash = g_new(QCryptoHash, 1); 113 hash->alg = alg; 114 hash->opaque = g_new(union qcrypto_hash_ctx, 1); 115 116 qcrypto_hash_alg_map[alg].init(hash->opaque); 117 return hash; 118 } 119 120 static 121 void qcrypto_nettle_hash_free(QCryptoHash *hash) 122 { 123 union qcrypto_hash_ctx *ctx = hash->opaque; 124 125 g_free(ctx); 126 g_free(hash); 127 } 128 129 static 130 int qcrypto_nettle_hash_update(QCryptoHash *hash, 131 const struct iovec *iov, 132 size_t niov, 133 Error **errp) 134 { 135 union qcrypto_hash_ctx *ctx = hash->opaque; 136 137 for (int i = 0; i < niov; i++) { 138 qcrypto_hash_alg_map[hash->alg].write(ctx, 139 iov[i].iov_len, 140 iov[i].iov_base); 141 } 142 143 return 0; 144 } 145 146 static 147 int qcrypto_nettle_hash_finalize(QCryptoHash *hash, 148 uint8_t **result, 149 size_t *result_len, 150 Error **errp) 151 { 152 union qcrypto_hash_ctx *ctx = hash->opaque; 153 int ret = qcrypto_hash_alg_map[hash->alg].len; 154 155 if (*result_len == 0) { 156 *result_len = ret; 157 *result = g_new(uint8_t, *result_len); 158 } else if (*result_len != ret) { 159 error_setg(errp, 160 "Result buffer size %zu is smaller than hash %d", 161 *result_len, ret); 162 return -1; 163 } 164 165 qcrypto_hash_alg_map[hash->alg].result(ctx, *result_len, *result); 166 167 return 0; 168 } 169 170 QCryptoHashDriver qcrypto_hash_lib_driver = { 171 .hash_new = qcrypto_nettle_hash_new, 172 .hash_update = qcrypto_nettle_hash_update, 173 .hash_finalize = qcrypto_nettle_hash_finalize, 174 .hash_free = qcrypto_nettle_hash_free, 175 }; 176