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.1 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 "hashpriv.h" 25 #include <nettle/md5.h> 26 #include <nettle/sha.h> 27 #include <nettle/ripemd160.h> 28 29 typedef void (*qcrypto_nettle_init)(void *ctx); 30 typedef void (*qcrypto_nettle_write)(void *ctx, 31 size_t len, 32 const uint8_t *buf); 33 typedef void (*qcrypto_nettle_result)(void *ctx, 34 size_t len, 35 uint8_t *buf); 36 37 union qcrypto_hash_ctx { 38 struct md5_ctx md5; 39 struct sha1_ctx sha1; 40 struct sha224_ctx sha224; 41 struct sha256_ctx sha256; 42 struct sha384_ctx sha384; 43 struct sha512_ctx sha512; 44 struct ripemd160_ctx ripemd160; 45 }; 46 47 struct qcrypto_hash_alg { 48 qcrypto_nettle_init init; 49 qcrypto_nettle_write write; 50 qcrypto_nettle_result result; 51 size_t len; 52 } qcrypto_hash_alg_map[] = { 53 [QCRYPTO_HASH_ALGO_MD5] = { 54 .init = (qcrypto_nettle_init)md5_init, 55 .write = (qcrypto_nettle_write)md5_update, 56 .result = (qcrypto_nettle_result)md5_digest, 57 .len = MD5_DIGEST_SIZE, 58 }, 59 [QCRYPTO_HASH_ALGO_SHA1] = { 60 .init = (qcrypto_nettle_init)sha1_init, 61 .write = (qcrypto_nettle_write)sha1_update, 62 .result = (qcrypto_nettle_result)sha1_digest, 63 .len = SHA1_DIGEST_SIZE, 64 }, 65 [QCRYPTO_HASH_ALGO_SHA224] = { 66 .init = (qcrypto_nettle_init)sha224_init, 67 .write = (qcrypto_nettle_write)sha224_update, 68 .result = (qcrypto_nettle_result)sha224_digest, 69 .len = SHA224_DIGEST_SIZE, 70 }, 71 [QCRYPTO_HASH_ALGO_SHA256] = { 72 .init = (qcrypto_nettle_init)sha256_init, 73 .write = (qcrypto_nettle_write)sha256_update, 74 .result = (qcrypto_nettle_result)sha256_digest, 75 .len = SHA256_DIGEST_SIZE, 76 }, 77 [QCRYPTO_HASH_ALGO_SHA384] = { 78 .init = (qcrypto_nettle_init)sha384_init, 79 .write = (qcrypto_nettle_write)sha384_update, 80 .result = (qcrypto_nettle_result)sha384_digest, 81 .len = SHA384_DIGEST_SIZE, 82 }, 83 [QCRYPTO_HASH_ALGO_SHA512] = { 84 .init = (qcrypto_nettle_init)sha512_init, 85 .write = (qcrypto_nettle_write)sha512_update, 86 .result = (qcrypto_nettle_result)sha512_digest, 87 .len = SHA512_DIGEST_SIZE, 88 }, 89 [QCRYPTO_HASH_ALGO_RIPEMD160] = { 90 .init = (qcrypto_nettle_init)ripemd160_init, 91 .write = (qcrypto_nettle_write)ripemd160_update, 92 .result = (qcrypto_nettle_result)ripemd160_digest, 93 .len = RIPEMD160_DIGEST_SIZE, 94 }, 95 }; 96 97 gboolean qcrypto_hash_supports(QCryptoHashAlgo alg) 98 { 99 if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map) && 100 qcrypto_hash_alg_map[alg].init != NULL) { 101 return true; 102 } 103 return false; 104 } 105 106 107 static int 108 qcrypto_nettle_hash_bytesv(QCryptoHashAlgo alg, 109 const struct iovec *iov, 110 size_t niov, 111 uint8_t **result, 112 size_t *resultlen, 113 Error **errp) 114 { 115 size_t i; 116 union qcrypto_hash_ctx ctx; 117 118 if (!qcrypto_hash_supports(alg)) { 119 error_setg(errp, 120 "Unknown hash algorithm %d", 121 alg); 122 return -1; 123 } 124 125 qcrypto_hash_alg_map[alg].init(&ctx); 126 127 for (i = 0; i < niov; i++) { 128 /* Some versions of nettle have functions 129 * declared with 'int' instead of 'size_t' 130 * so to be safe avoid writing more than 131 * UINT_MAX bytes at a time 132 */ 133 size_t len = iov[i].iov_len; 134 uint8_t *base = iov[i].iov_base; 135 while (len) { 136 size_t shortlen = MIN(len, UINT_MAX); 137 qcrypto_hash_alg_map[alg].write(&ctx, len, base); 138 len -= shortlen; 139 base += len; 140 } 141 } 142 143 if (*resultlen == 0) { 144 *resultlen = qcrypto_hash_alg_map[alg].len; 145 *result = g_new0(uint8_t, *resultlen); 146 } else if (*resultlen != qcrypto_hash_alg_map[alg].len) { 147 error_setg(errp, 148 "Result buffer size %zu is smaller than hash %zu", 149 *resultlen, qcrypto_hash_alg_map[alg].len); 150 return -1; 151 } 152 153 qcrypto_hash_alg_map[alg].result(&ctx, *resultlen, *result); 154 155 return 0; 156 } 157 158 159 QCryptoHashDriver qcrypto_hash_lib_driver = { 160 .hash_bytesv = qcrypto_nettle_hash_bytesv, 161 }; 162