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 <gcrypt.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] = GCRY_MD_MD5, 31 [QCRYPTO_HASH_ALGO_SHA1] = GCRY_MD_SHA1, 32 [QCRYPTO_HASH_ALGO_SHA224] = GCRY_MD_SHA224, 33 [QCRYPTO_HASH_ALGO_SHA256] = GCRY_MD_SHA256, 34 [QCRYPTO_HASH_ALGO_SHA384] = GCRY_MD_SHA384, 35 [QCRYPTO_HASH_ALGO_SHA512] = GCRY_MD_SHA512, 36 [QCRYPTO_HASH_ALGO_RIPEMD160] = GCRY_MD_RMD160, 37 }; 38 39 gboolean qcrypto_hash_supports(QCryptoHashAlgo alg) 40 { 41 if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map) && 42 qcrypto_hash_alg_map[alg] != GCRY_MD_NONE) { 43 return true; 44 } 45 return false; 46 } 47 48 static 49 QCryptoHash *qcrypto_gcrypt_hash_new(QCryptoHashAlgo alg, Error **errp) 50 { 51 QCryptoHash *hash; 52 int ret; 53 54 hash = g_new(QCryptoHash, 1); 55 hash->alg = alg; 56 hash->opaque = g_new(gcry_md_hd_t, 1); 57 58 ret = gcry_md_open((gcry_md_hd_t *) hash->opaque, 59 qcrypto_hash_alg_map[alg], 0); 60 if (ret < 0) { 61 error_setg(errp, 62 "Unable to initialize hash algorithm: %s", 63 gcry_strerror(ret)); 64 g_free(hash->opaque); 65 g_free(hash); 66 return NULL; 67 } 68 return hash; 69 } 70 71 static 72 void qcrypto_gcrypt_hash_free(QCryptoHash *hash) 73 { 74 gcry_md_hd_t *ctx = hash->opaque; 75 76 if (ctx) { 77 gcry_md_close(*ctx); 78 g_free(ctx); 79 } 80 81 g_free(hash); 82 } 83 84 85 static 86 int qcrypto_gcrypt_hash_update(QCryptoHash *hash, 87 const struct iovec *iov, 88 size_t niov, 89 Error **errp) 90 { 91 gcry_md_hd_t *ctx = hash->opaque; 92 93 for (int i = 0; i < niov; i++) { 94 gcry_md_write(*ctx, iov[i].iov_base, iov[i].iov_len); 95 } 96 97 return 0; 98 } 99 100 static 101 int qcrypto_gcrypt_hash_finalize(QCryptoHash *hash, 102 uint8_t **result, 103 size_t *result_len, 104 Error **errp) 105 { 106 int ret; 107 unsigned char *digest; 108 gcry_md_hd_t *ctx = hash->opaque; 109 110 ret = gcry_md_get_algo_dlen(qcrypto_hash_alg_map[hash->alg]); 111 if (ret == 0) { 112 error_setg(errp, "Unable to get hash length"); 113 return -1; 114 } 115 116 if (*result_len == 0) { 117 *result_len = ret; 118 *result = g_new(uint8_t, *result_len); 119 } else if (*result_len != ret) { 120 error_setg(errp, 121 "Result buffer size %zu is smaller than hash %d", 122 *result_len, ret); 123 return -1; 124 } 125 126 /* Digest is freed by gcry_md_close(), copy it */ 127 digest = gcry_md_read(*ctx, 0); 128 memcpy(*result, digest, *result_len); 129 return 0; 130 } 131 132 QCryptoHashDriver qcrypto_hash_lib_driver = { 133 .hash_new = qcrypto_gcrypt_hash_new, 134 .hash_update = qcrypto_gcrypt_hash_update, 135 .hash_finalize = qcrypto_gcrypt_hash_finalize, 136 .hash_free = qcrypto_gcrypt_hash_free, 137 }; 138