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