12165477cSDaniel P. Berrange /* 22165477cSDaniel P. Berrange * QEMU Crypto hash algorithms 32165477cSDaniel P. Berrange * 4*c6ccd2afSAlejandro Zeise * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates 52165477cSDaniel P. Berrange * Copyright (c) 2016 Red Hat, Inc. 62165477cSDaniel P. Berrange * 72165477cSDaniel P. Berrange * This library is free software; you can redistribute it and/or 82165477cSDaniel P. Berrange * modify it under the terms of the GNU Lesser General Public 92165477cSDaniel P. Berrange * License as published by the Free Software Foundation; either 10b7cbb874SThomas Huth * version 2.1 of the License, or (at your option) any later version. 112165477cSDaniel P. Berrange * 122165477cSDaniel P. Berrange * This library is distributed in the hope that it will be useful, 132165477cSDaniel P. Berrange * but WITHOUT ANY WARRANTY; without even the implied warranty of 142165477cSDaniel P. Berrange * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 152165477cSDaniel P. Berrange * Lesser General Public License for more details. 162165477cSDaniel P. Berrange * 172165477cSDaniel P. Berrange * You should have received a copy of the GNU Lesser General Public 182165477cSDaniel P. Berrange * License along with this library; if not, see <http://www.gnu.org/licenses/>. 192165477cSDaniel P. Berrange * 202165477cSDaniel P. Berrange */ 212165477cSDaniel P. Berrange 222165477cSDaniel P. Berrange #include "qemu/osdep.h" 232165477cSDaniel P. Berrange #include "qapi/error.h" 242165477cSDaniel P. Berrange #include "crypto/hash.h" 25aa8efad9SLongpeng(Mike) #include "hashpriv.h" 262165477cSDaniel P. Berrange 272165477cSDaniel P. Berrange 28ef834aa2SMarkus Armbruster static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALGO__MAX] = { 29ef834aa2SMarkus Armbruster [QCRYPTO_HASH_ALGO_MD5] = G_CHECKSUM_MD5, 30ef834aa2SMarkus Armbruster [QCRYPTO_HASH_ALGO_SHA1] = G_CHECKSUM_SHA1, 31ef834aa2SMarkus Armbruster [QCRYPTO_HASH_ALGO_SHA224] = -1, 32ef834aa2SMarkus Armbruster [QCRYPTO_HASH_ALGO_SHA256] = G_CHECKSUM_SHA256, 33ef834aa2SMarkus Armbruster [QCRYPTO_HASH_ALGO_SHA384] = G_CHECKSUM_SHA384, 34ef834aa2SMarkus Armbruster [QCRYPTO_HASH_ALGO_SHA512] = G_CHECKSUM_SHA512, 35ef834aa2SMarkus Armbruster [QCRYPTO_HASH_ALGO_RIPEMD160] = -1, 362165477cSDaniel P. Berrange }; 372165477cSDaniel P. Berrange 38ef834aa2SMarkus Armbruster gboolean qcrypto_hash_supports(QCryptoHashAlgo alg) 392165477cSDaniel P. Berrange { 402165477cSDaniel P. Berrange if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map) && 412165477cSDaniel P. Berrange qcrypto_hash_alg_map[alg] != -1) { 422165477cSDaniel P. Berrange return true; 432165477cSDaniel P. Berrange } 442165477cSDaniel P. Berrange return false; 452165477cSDaniel P. Berrange } 462165477cSDaniel P. Berrange 472165477cSDaniel P. Berrange 48aa8efad9SLongpeng(Mike) static int 49ef834aa2SMarkus Armbruster qcrypto_glib_hash_bytesv(QCryptoHashAlgo alg, 502165477cSDaniel P. Berrange const struct iovec *iov, 512165477cSDaniel P. Berrange size_t niov, 522165477cSDaniel P. Berrange uint8_t **result, 532165477cSDaniel P. Berrange size_t *resultlen, 542165477cSDaniel P. Berrange Error **errp) 552165477cSDaniel P. Berrange { 562165477cSDaniel P. Berrange int i, ret; 572165477cSDaniel P. Berrange GChecksum *cs; 582165477cSDaniel P. Berrange 5976032897SDaniel P. Berrange if (!qcrypto_hash_supports(alg)) { 602165477cSDaniel P. Berrange error_setg(errp, 612165477cSDaniel P. Berrange "Unknown hash algorithm %d", 622165477cSDaniel P. Berrange alg); 632165477cSDaniel P. Berrange return -1; 642165477cSDaniel P. Berrange } 652165477cSDaniel P. Berrange 662165477cSDaniel P. Berrange cs = g_checksum_new(qcrypto_hash_alg_map[alg]); 672165477cSDaniel P. Berrange 682165477cSDaniel P. Berrange for (i = 0; i < niov; i++) { 692165477cSDaniel P. Berrange g_checksum_update(cs, iov[i].iov_base, iov[i].iov_len); 702165477cSDaniel P. Berrange } 712165477cSDaniel P. Berrange 722165477cSDaniel P. Berrange ret = g_checksum_type_get_length(qcrypto_hash_alg_map[alg]); 732165477cSDaniel P. Berrange if (ret < 0) { 742165477cSDaniel P. Berrange error_setg(errp, "%s", 752165477cSDaniel P. Berrange "Unable to get hash length"); 762165477cSDaniel P. Berrange goto error; 772165477cSDaniel P. Berrange } 782165477cSDaniel P. Berrange if (*resultlen == 0) { 792165477cSDaniel P. Berrange *resultlen = ret; 802165477cSDaniel P. Berrange *result = g_new0(uint8_t, *resultlen); 812165477cSDaniel P. Berrange } else if (*resultlen != ret) { 822165477cSDaniel P. Berrange error_setg(errp, 832165477cSDaniel P. Berrange "Result buffer size %zu is smaller than hash %d", 842165477cSDaniel P. Berrange *resultlen, ret); 852165477cSDaniel P. Berrange goto error; 862165477cSDaniel P. Berrange } 872165477cSDaniel P. Berrange 882165477cSDaniel P. Berrange g_checksum_get_digest(cs, *result, resultlen); 892165477cSDaniel P. Berrange 902165477cSDaniel P. Berrange g_checksum_free(cs); 912165477cSDaniel P. Berrange return 0; 922165477cSDaniel P. Berrange 932165477cSDaniel P. Berrange error: 942165477cSDaniel P. Berrange g_checksum_free(cs); 952165477cSDaniel P. Berrange return -1; 962165477cSDaniel P. Berrange } 97aa8efad9SLongpeng(Mike) 98aa8efad9SLongpeng(Mike) 99*c6ccd2afSAlejandro Zeise static 100*c6ccd2afSAlejandro Zeise QCryptoHash *qcrypto_glib_hash_new(QCryptoHashAlgo alg, 101*c6ccd2afSAlejandro Zeise Error **errp) 102*c6ccd2afSAlejandro Zeise { 103*c6ccd2afSAlejandro Zeise QCryptoHash *hash; 104*c6ccd2afSAlejandro Zeise 105*c6ccd2afSAlejandro Zeise hash = g_new(QCryptoHash, 1); 106*c6ccd2afSAlejandro Zeise hash->alg = alg; 107*c6ccd2afSAlejandro Zeise hash->opaque = g_checksum_new(qcrypto_hash_alg_map[alg]); 108*c6ccd2afSAlejandro Zeise 109*c6ccd2afSAlejandro Zeise return hash; 110*c6ccd2afSAlejandro Zeise } 111*c6ccd2afSAlejandro Zeise 112*c6ccd2afSAlejandro Zeise static 113*c6ccd2afSAlejandro Zeise void qcrypto_glib_hash_free(QCryptoHash *hash) 114*c6ccd2afSAlejandro Zeise { 115*c6ccd2afSAlejandro Zeise if (hash->opaque) { 116*c6ccd2afSAlejandro Zeise g_checksum_free(hash->opaque); 117*c6ccd2afSAlejandro Zeise } 118*c6ccd2afSAlejandro Zeise 119*c6ccd2afSAlejandro Zeise g_free(hash); 120*c6ccd2afSAlejandro Zeise } 121*c6ccd2afSAlejandro Zeise 122*c6ccd2afSAlejandro Zeise 123*c6ccd2afSAlejandro Zeise static 124*c6ccd2afSAlejandro Zeise int qcrypto_glib_hash_update(QCryptoHash *hash, 125*c6ccd2afSAlejandro Zeise const struct iovec *iov, 126*c6ccd2afSAlejandro Zeise size_t niov, 127*c6ccd2afSAlejandro Zeise Error **errp) 128*c6ccd2afSAlejandro Zeise { 129*c6ccd2afSAlejandro Zeise GChecksum *ctx = hash->opaque; 130*c6ccd2afSAlejandro Zeise 131*c6ccd2afSAlejandro Zeise for (int i = 0; i < niov; i++) { 132*c6ccd2afSAlejandro Zeise g_checksum_update(ctx, iov[i].iov_base, iov[i].iov_len); 133*c6ccd2afSAlejandro Zeise } 134*c6ccd2afSAlejandro Zeise 135*c6ccd2afSAlejandro Zeise return 0; 136*c6ccd2afSAlejandro Zeise } 137*c6ccd2afSAlejandro Zeise 138*c6ccd2afSAlejandro Zeise static 139*c6ccd2afSAlejandro Zeise int qcrypto_glib_hash_finalize(QCryptoHash *hash, 140*c6ccd2afSAlejandro Zeise uint8_t **result, 141*c6ccd2afSAlejandro Zeise size_t *result_len, 142*c6ccd2afSAlejandro Zeise Error **errp) 143*c6ccd2afSAlejandro Zeise { 144*c6ccd2afSAlejandro Zeise int ret; 145*c6ccd2afSAlejandro Zeise GChecksum *ctx = hash->opaque; 146*c6ccd2afSAlejandro Zeise 147*c6ccd2afSAlejandro Zeise ret = g_checksum_type_get_length(qcrypto_hash_alg_map[hash->alg]); 148*c6ccd2afSAlejandro Zeise if (ret < 0) { 149*c6ccd2afSAlejandro Zeise error_setg(errp, "Unable to get hash length"); 150*c6ccd2afSAlejandro Zeise *result_len = 0; 151*c6ccd2afSAlejandro Zeise return -1; 152*c6ccd2afSAlejandro Zeise } 153*c6ccd2afSAlejandro Zeise 154*c6ccd2afSAlejandro Zeise *result_len = ret; 155*c6ccd2afSAlejandro Zeise *result = g_new(uint8_t, *result_len); 156*c6ccd2afSAlejandro Zeise 157*c6ccd2afSAlejandro Zeise g_checksum_get_digest(ctx, *result, result_len); 158*c6ccd2afSAlejandro Zeise return 0; 159*c6ccd2afSAlejandro Zeise } 160*c6ccd2afSAlejandro Zeise 161aa8efad9SLongpeng(Mike) QCryptoHashDriver qcrypto_hash_lib_driver = { 162aa8efad9SLongpeng(Mike) .hash_bytesv = qcrypto_glib_hash_bytesv, 163*c6ccd2afSAlejandro Zeise .hash_new = qcrypto_glib_hash_new, 164*c6ccd2afSAlejandro Zeise .hash_update = qcrypto_glib_hash_update, 165*c6ccd2afSAlejandro Zeise .hash_finalize = qcrypto_glib_hash_finalize, 166*c6ccd2afSAlejandro Zeise .hash_free = qcrypto_glib_hash_free, 167aa8efad9SLongpeng(Mike) }; 168