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 <gcrypt.h> 23 #include "qapi/error.h" 24 #include "crypto/hash.h" 25 #include "hashpriv.h" 26 27 28 static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALGO__MAX] = { 29 [QCRYPTO_HASH_ALGO_MD5] = GCRY_MD_MD5, 30 [QCRYPTO_HASH_ALGO_SHA1] = GCRY_MD_SHA1, 31 [QCRYPTO_HASH_ALGO_SHA224] = GCRY_MD_SHA224, 32 [QCRYPTO_HASH_ALGO_SHA256] = GCRY_MD_SHA256, 33 [QCRYPTO_HASH_ALGO_SHA384] = GCRY_MD_SHA384, 34 [QCRYPTO_HASH_ALGO_SHA512] = GCRY_MD_SHA512, 35 [QCRYPTO_HASH_ALGO_RIPEMD160] = GCRY_MD_RMD160, 36 }; 37 38 gboolean qcrypto_hash_supports(QCryptoHashAlgo alg) 39 { 40 if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map) && 41 qcrypto_hash_alg_map[alg] != GCRY_MD_NONE) { 42 return true; 43 } 44 return false; 45 } 46 47 48 static int 49 qcrypto_gcrypt_hash_bytesv(QCryptoHashAlgo alg, 50 const struct iovec *iov, 51 size_t niov, 52 uint8_t **result, 53 size_t *resultlen, 54 Error **errp) 55 { 56 int i, ret; 57 gcry_md_hd_t md; 58 unsigned char *digest; 59 60 if (!qcrypto_hash_supports(alg)) { 61 error_setg(errp, 62 "Unknown hash algorithm %d", 63 alg); 64 return -1; 65 } 66 67 ret = gcry_md_open(&md, qcrypto_hash_alg_map[alg], 0); 68 69 if (ret < 0) { 70 error_setg(errp, 71 "Unable to initialize hash algorithm: %s", 72 gcry_strerror(ret)); 73 return -1; 74 } 75 76 for (i = 0; i < niov; i++) { 77 gcry_md_write(md, iov[i].iov_base, iov[i].iov_len); 78 } 79 80 ret = gcry_md_get_algo_dlen(qcrypto_hash_alg_map[alg]); 81 if (ret <= 0) { 82 error_setg(errp, 83 "Unable to get hash length: %s", 84 gcry_strerror(ret)); 85 goto error; 86 } 87 if (*resultlen == 0) { 88 *resultlen = ret; 89 *result = g_new0(uint8_t, *resultlen); 90 } else if (*resultlen != ret) { 91 error_setg(errp, 92 "Result buffer size %zu is smaller than hash %d", 93 *resultlen, ret); 94 goto error; 95 } 96 97 digest = gcry_md_read(md, 0); 98 if (!digest) { 99 error_setg(errp, 100 "No digest produced"); 101 goto error; 102 } 103 memcpy(*result, digest, *resultlen); 104 105 gcry_md_close(md); 106 return 0; 107 108 error: 109 gcry_md_close(md); 110 return -1; 111 } 112 113 114 QCryptoHashDriver qcrypto_hash_lib_driver = { 115 .hash_bytesv = qcrypto_gcrypt_hash_bytesv, 116 }; 117