qemu/crypto/hash.c
<<
>>
Prefs
   1/*
   2 * QEMU Crypto hash algorithms
   3 *
   4 * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
   5 * Copyright (c) 2015 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 "qapi-types-crypto.h"
  25#include "crypto/hash.h"
  26#include "hashpriv.h"
  27
  28static size_t qcrypto_hash_alg_size[QCRYPTO_HASH_ALGO__MAX] = {
  29    [QCRYPTO_HASH_ALGO_MD5]       = QCRYPTO_HASH_DIGEST_LEN_MD5,
  30    [QCRYPTO_HASH_ALGO_SHA1]      = QCRYPTO_HASH_DIGEST_LEN_SHA1,
  31    [QCRYPTO_HASH_ALGO_SHA224]    = QCRYPTO_HASH_DIGEST_LEN_SHA224,
  32    [QCRYPTO_HASH_ALGO_SHA256]    = QCRYPTO_HASH_DIGEST_LEN_SHA256,
  33    [QCRYPTO_HASH_ALGO_SHA384]    = QCRYPTO_HASH_DIGEST_LEN_SHA384,
  34    [QCRYPTO_HASH_ALGO_SHA512]    = QCRYPTO_HASH_DIGEST_LEN_SHA512,
  35    [QCRYPTO_HASH_ALGO_RIPEMD160] = QCRYPTO_HASH_DIGEST_LEN_RIPEMD160,
  36#ifdef CONFIG_CRYPTO_SM3
  37    [QCRYPTO_HASH_ALGO_SM3] = QCRYPTO_HASH_DIGEST_LEN_SM3,
  38#endif
  39};
  40
  41size_t qcrypto_hash_digest_len(QCryptoHashAlgo alg)
  42{
  43    assert(alg < G_N_ELEMENTS(qcrypto_hash_alg_size));
  44    return qcrypto_hash_alg_size[alg];
  45}
  46
  47int qcrypto_hash_bytesv(QCryptoHashAlgo alg,
  48                        const struct iovec *iov,
  49                        size_t niov,
  50                        uint8_t **result,
  51                        size_t *resultlen,
  52                        Error **errp)
  53{
  54    g_autoptr(QCryptoHash) ctx = qcrypto_hash_new(alg, errp);
  55
  56    if (!ctx) {
  57        return -1;
  58    }
  59
  60    if (qcrypto_hash_updatev(ctx, iov, niov, errp) < 0 ||
  61        qcrypto_hash_finalize_bytes(ctx, result, resultlen, errp) < 0) {
  62        return -1;
  63    }
  64
  65    return 0;
  66}
  67
  68
  69int qcrypto_hash_bytes(QCryptoHashAlgo alg,
  70                       const char *buf,
  71                       size_t len,
  72                       uint8_t **result,
  73                       size_t *resultlen,
  74                       Error **errp)
  75{
  76    struct iovec iov = { .iov_base = (char *)buf,
  77                         .iov_len = len };
  78    return qcrypto_hash_bytesv(alg, &iov, 1, result, resultlen, errp);
  79}
  80
  81int qcrypto_hash_updatev(QCryptoHash *hash,
  82                         const struct iovec *iov,
  83                         size_t niov,
  84                         Error **errp)
  85{
  86    QCryptoHashDriver *drv = hash->driver;
  87
  88    return drv->hash_update(hash, iov, niov, errp);
  89}
  90
  91int qcrypto_hash_update(QCryptoHash *hash,
  92                        const char *buf,
  93                        size_t len,
  94                        Error **errp)
  95{
  96    struct iovec iov = { .iov_base = (char *)buf, .iov_len = len };
  97
  98    return qcrypto_hash_updatev(hash, &iov, 1, errp);
  99}
 100
 101QCryptoHash *qcrypto_hash_new(QCryptoHashAlgo alg, Error **errp)
 102{
 103    QCryptoHash *hash = NULL;
 104
 105    if (!qcrypto_hash_supports(alg)) {
 106        error_setg(errp, "Unsupported hash algorithm %s",
 107                   QCryptoHashAlgo_str(alg));
 108        return NULL;
 109   }
 110
 111#ifdef CONFIG_AF_ALG
 112    hash = qcrypto_hash_afalg_driver.hash_new(alg, NULL);
 113    if (hash) {
 114        hash->driver = &qcrypto_hash_afalg_driver;
 115        return hash;
 116    }
 117#endif
 118
 119    hash = qcrypto_hash_lib_driver.hash_new(alg, errp);
 120    if (!hash) {
 121        return NULL;
 122    }
 123
 124    hash->driver = &qcrypto_hash_lib_driver;
 125    return hash;
 126}
 127
 128void qcrypto_hash_free(QCryptoHash *hash)
 129{
 130   QCryptoHashDriver *drv;
 131
 132    if (hash) {
 133        drv = hash->driver;
 134        drv->hash_free(hash);
 135    }
 136}
 137
 138int qcrypto_hash_finalize_bytes(QCryptoHash *hash,
 139                                uint8_t **result,
 140                                size_t *result_len,
 141                                Error **errp)
 142{
 143    QCryptoHashDriver *drv = hash->driver;
 144
 145    return drv->hash_finalize(hash, result, result_len, errp);
 146}
 147
 148static const char hex[] = "0123456789abcdef";
 149
 150int qcrypto_hash_finalize_digest(QCryptoHash *hash,
 151                                 char **digest,
 152                                 Error **errp)
 153{
 154    int ret;
 155    g_autofree uint8_t *result = NULL;
 156    size_t resultlen = 0;
 157    size_t i;
 158
 159    ret = qcrypto_hash_finalize_bytes(hash, &result, &resultlen, errp);
 160    if (ret == 0) {
 161        *digest = g_new0(char, (resultlen * 2) + 1);
 162        for (i = 0 ; i < resultlen ; i++) {
 163            (*digest)[(i * 2)] = hex[(result[i] >> 4) & 0xf];
 164            (*digest)[(i * 2) + 1] = hex[result[i] & 0xf];
 165        }
 166        (*digest)[resultlen * 2] = '\0';
 167    }
 168
 169    return ret;
 170}
 171
 172int qcrypto_hash_finalize_base64(QCryptoHash *hash,
 173                                 char **base64,
 174                                 Error **errp)
 175{
 176    int ret;
 177    g_autofree uint8_t *result = NULL;
 178    size_t resultlen = 0;
 179
 180    ret = qcrypto_hash_finalize_bytes(hash, &result, &resultlen, errp);
 181    if (ret == 0) {
 182        *base64 = g_base64_encode(result, resultlen);
 183    }
 184
 185    return ret;
 186}
 187
 188int qcrypto_hash_digestv(QCryptoHashAlgo alg,
 189                         const struct iovec *iov,
 190                         size_t niov,
 191                         char **digest,
 192                         Error **errp)
 193{
 194    g_autoptr(QCryptoHash) ctx = qcrypto_hash_new(alg, errp);
 195
 196    if (!ctx) {
 197        return -1;
 198    }
 199
 200    if (qcrypto_hash_updatev(ctx, iov, niov, errp) < 0 ||
 201        qcrypto_hash_finalize_digest(ctx, digest, errp) < 0) {
 202        return -1;
 203    }
 204
 205    return 0;
 206}
 207
 208int qcrypto_hash_digest(QCryptoHashAlgo alg,
 209                        const char *buf,
 210                        size_t len,
 211                        char **digest,
 212                        Error **errp)
 213{
 214    struct iovec iov = { .iov_base = (char *)buf, .iov_len = len };
 215
 216    return qcrypto_hash_digestv(alg, &iov, 1, digest, errp);
 217}
 218
 219int qcrypto_hash_base64v(QCryptoHashAlgo alg,
 220                         const struct iovec *iov,
 221                         size_t niov,
 222                         char **base64,
 223                         Error **errp)
 224{
 225    g_autoptr(QCryptoHash) ctx = qcrypto_hash_new(alg, errp);
 226
 227    if (!ctx) {
 228        return -1;
 229    }
 230
 231    if (qcrypto_hash_updatev(ctx, iov, niov, errp) < 0 ||
 232        qcrypto_hash_finalize_base64(ctx, base64, errp) < 0) {
 233        return -1;
 234    }
 235
 236    return 0;
 237}
 238
 239int qcrypto_hash_base64(QCryptoHashAlgo alg,
 240                        const char *buf,
 241                        size_t len,
 242                        char **base64,
 243                        Error **errp)
 244{
 245    struct iovec iov = { .iov_base = (char *)buf, .iov_len = len };
 246
 247    return qcrypto_hash_base64v(alg, &iov, 1, base64, errp);
 248}
 249