1 /* 2 * QEMU Crypto hash algorithms 3 * 4 * Copyright (c) 2016 Red Hat, Inc. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 #include "qemu/osdep.h" 22 #include "qapi/error.h" 23 #include "crypto/hash.h" 24 #include <nettle/md5.h> 25 #include <nettle/sha.h> 26 #include <nettle/ripemd160.h> 27 28 typedef void (*qcrypto_nettle_init)(void *ctx); 29 typedef void (*qcrypto_nettle_write)(void *ctx, 30 unsigned int len, 31 const uint8_t *buf); 32 typedef void (*qcrypto_nettle_result)(void *ctx, 33 unsigned int len, 34 uint8_t *buf); 35 36 union qcrypto_hash_ctx { 37 struct md5_ctx md5; 38 struct sha1_ctx sha1; 39 struct sha224_ctx sha224; 40 struct sha256_ctx sha256; 41 struct sha384_ctx sha384; 42 struct sha512_ctx sha512; 43 struct ripemd160_ctx ripemd160; 44 }; 45 46 struct qcrypto_hash_alg { 47 qcrypto_nettle_init init; 48 qcrypto_nettle_write write; 49 qcrypto_nettle_result result; 50 size_t len; 51 } qcrypto_hash_alg_map[] = { 52 [QCRYPTO_HASH_ALG_MD5] = { 53 .init = (qcrypto_nettle_init)md5_init, 54 .write = (qcrypto_nettle_write)md5_update, 55 .result = (qcrypto_nettle_result)md5_digest, 56 .len = MD5_DIGEST_SIZE, 57 }, 58 [QCRYPTO_HASH_ALG_SHA1] = { 59 .init = (qcrypto_nettle_init)sha1_init, 60 .write = (qcrypto_nettle_write)sha1_update, 61 .result = (qcrypto_nettle_result)sha1_digest, 62 .len = SHA1_DIGEST_SIZE, 63 }, 64 [QCRYPTO_HASH_ALG_SHA224] = { 65 .init = (qcrypto_nettle_init)sha224_init, 66 .write = (qcrypto_nettle_write)sha224_update, 67 .result = (qcrypto_nettle_result)sha224_digest, 68 .len = SHA224_DIGEST_SIZE, 69 }, 70 [QCRYPTO_HASH_ALG_SHA256] = { 71 .init = (qcrypto_nettle_init)sha256_init, 72 .write = (qcrypto_nettle_write)sha256_update, 73 .result = (qcrypto_nettle_result)sha256_digest, 74 .len = SHA256_DIGEST_SIZE, 75 }, 76 [QCRYPTO_HASH_ALG_SHA384] = { 77 .init = (qcrypto_nettle_init)sha384_init, 78 .write = (qcrypto_nettle_write)sha384_update, 79 .result = (qcrypto_nettle_result)sha384_digest, 80 .len = SHA384_DIGEST_SIZE, 81 }, 82 [QCRYPTO_HASH_ALG_SHA512] = { 83 .init = (qcrypto_nettle_init)sha512_init, 84 .write = (qcrypto_nettle_write)sha512_update, 85 .result = (qcrypto_nettle_result)sha512_digest, 86 .len = SHA512_DIGEST_SIZE, 87 }, 88 [QCRYPTO_HASH_ALG_RIPEMD160] = { 89 .init = (qcrypto_nettle_init)ripemd160_init, 90 .write = (qcrypto_nettle_write)ripemd160_update, 91 .result = (qcrypto_nettle_result)ripemd160_digest, 92 .len = RIPEMD160_DIGEST_SIZE, 93 }, 94 }; 95 96 gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg) 97 { 98 if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map) && 99 qcrypto_hash_alg_map[alg].init != NULL) { 100 return true; 101 } 102 return false; 103 } 104 105 106 int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg, 107 const struct iovec *iov, 108 size_t niov, 109 uint8_t **result, 110 size_t *resultlen, 111 Error **errp) 112 { 113 int i; 114 union qcrypto_hash_ctx ctx; 115 116 if (!qcrypto_hash_supports(alg)) { 117 error_setg(errp, 118 "Unknown hash algorithm %d", 119 alg); 120 return -1; 121 } 122 123 qcrypto_hash_alg_map[alg].init(&ctx); 124 125 for (i = 0; i < niov; i++) { 126 /* Some versions of nettle have functions 127 * declared with 'int' instead of 'size_t' 128 * so to be safe avoid writing more than 129 * UINT_MAX bytes at a time 130 */ 131 size_t len = iov[i].iov_len; 132 uint8_t *base = iov[i].iov_base; 133 while (len) { 134 size_t shortlen = MIN(len, UINT_MAX); 135 qcrypto_hash_alg_map[alg].write(&ctx, len, base); 136 len -= shortlen; 137 base += len; 138 } 139 } 140 141 if (*resultlen == 0) { 142 *resultlen = qcrypto_hash_alg_map[alg].len; 143 *result = g_new0(uint8_t, *resultlen); 144 } else if (*resultlen != qcrypto_hash_alg_map[alg].len) { 145 error_setg(errp, 146 "Result buffer size %zu is smaller than hash %zu", 147 *resultlen, qcrypto_hash_alg_map[alg].len); 148 return -1; 149 } 150 151 qcrypto_hash_alg_map[alg].result(&ctx, *resultlen, *result); 152 153 return 0; 154 } 155