1 /* 2 * QEMU Crypto hash algorithms 3 * 4 * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates 5 * Copyright (c) 2021 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 <gnutls/crypto.h> 24 #include "qapi/error.h" 25 #include "crypto/hash.h" 26 #include "hashpriv.h" 27 28 29 static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALGO__MAX] = { 30 [QCRYPTO_HASH_ALGO_MD5] = GNUTLS_DIG_MD5, 31 [QCRYPTO_HASH_ALGO_SHA1] = GNUTLS_DIG_SHA1, 32 [QCRYPTO_HASH_ALGO_SHA224] = GNUTLS_DIG_SHA224, 33 [QCRYPTO_HASH_ALGO_SHA256] = GNUTLS_DIG_SHA256, 34 [QCRYPTO_HASH_ALGO_SHA384] = GNUTLS_DIG_SHA384, 35 [QCRYPTO_HASH_ALGO_SHA512] = GNUTLS_DIG_SHA512, 36 [QCRYPTO_HASH_ALGO_RIPEMD160] = GNUTLS_DIG_RMD160, 37 }; 38 39 gboolean qcrypto_hash_supports(QCryptoHashAlgo alg) 40 { 41 size_t i; 42 const gnutls_digest_algorithm_t *algs; 43 if (alg >= G_N_ELEMENTS(qcrypto_hash_alg_map) || 44 qcrypto_hash_alg_map[alg] == GNUTLS_DIG_UNKNOWN) { 45 return false; 46 } 47 algs = gnutls_digest_list(); 48 for (i = 0; algs[i] != GNUTLS_DIG_UNKNOWN; i++) { 49 if (algs[i] == qcrypto_hash_alg_map[alg]) { 50 return true; 51 } 52 } 53 return false; 54 } 55 56 static 57 QCryptoHash *qcrypto_gnutls_hash_new(QCryptoHashAlgo alg, Error **errp) 58 { 59 QCryptoHash *hash; 60 int ret; 61 62 hash = g_new(QCryptoHash, 1); 63 hash->alg = alg; 64 hash->opaque = g_new(gnutls_hash_hd_t, 1); 65 66 ret = gnutls_hash_init(hash->opaque, qcrypto_hash_alg_map[alg]); 67 if (ret < 0) { 68 error_setg(errp, 69 "Unable to initialize hash algorithm: %s", 70 gnutls_strerror(ret)); 71 g_free(hash->opaque); 72 g_free(hash); 73 return NULL; 74 } 75 76 return hash; 77 } 78 79 static 80 void qcrypto_gnutls_hash_free(QCryptoHash *hash) 81 { 82 gnutls_hash_hd_t *ctx = hash->opaque; 83 84 gnutls_hash_deinit(*ctx, NULL); 85 g_free(ctx); 86 g_free(hash); 87 } 88 89 90 static 91 int qcrypto_gnutls_hash_update(QCryptoHash *hash, 92 const struct iovec *iov, 93 size_t niov, 94 Error **errp) 95 { 96 int ret = 0; 97 gnutls_hash_hd_t *ctx = hash->opaque; 98 99 for (int i = 0; i < niov; i++) { 100 ret = gnutls_hash(*ctx, iov[i].iov_base, iov[i].iov_len); 101 if (ret != 0) { 102 error_setg(errp, "Failed to hash data: %s", 103 gnutls_strerror(ret)); 104 return -1; 105 } 106 } 107 108 return 0; 109 } 110 111 static 112 int qcrypto_gnutls_hash_finalize(QCryptoHash *hash, 113 uint8_t **result, 114 size_t *result_len, 115 Error **errp) 116 { 117 gnutls_hash_hd_t *ctx = hash->opaque; 118 119 *result_len = gnutls_hash_get_len(qcrypto_hash_alg_map[hash->alg]); 120 if (*result_len == 0) { 121 error_setg(errp, "Unable to get hash length"); 122 return -1; 123 } 124 125 *result = g_new(uint8_t, *result_len); 126 gnutls_hash_output(*ctx, *result); 127 return 0; 128 } 129 130 QCryptoHashDriver qcrypto_hash_lib_driver = { 131 .hash_new = qcrypto_gnutls_hash_new, 132 .hash_update = qcrypto_gnutls_hash_update, 133 .hash_finalize = qcrypto_gnutls_hash_finalize, 134 .hash_free = qcrypto_gnutls_hash_free, 135 }; 136