1 /* 2 * QEMU Crypto hash algorithms 3 * 4 * Copyright (c) 2015 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 "crypto/hash.h" 22 23 #ifdef CONFIG_GNUTLS_HASH 24 #include <gnutls/gnutls.h> 25 #include <gnutls/crypto.h> 26 27 static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALG_LAST] = { 28 [QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5, 29 [QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1, 30 [QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256, 31 }; 32 33 gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg) 34 { 35 if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map)) { 36 return true; 37 } 38 return false; 39 } 40 41 int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg, 42 const struct iovec *iov, 43 size_t niov, 44 uint8_t **result, 45 size_t *resultlen, 46 Error **errp) 47 { 48 int i, ret; 49 gnutls_hash_hd_t dig; 50 51 if (alg >= G_N_ELEMENTS(qcrypto_hash_alg_map)) { 52 error_setg(errp, 53 "Unknown hash algorithm %d", 54 alg); 55 return -1; 56 } 57 58 ret = gnutls_hash_init(&dig, qcrypto_hash_alg_map[alg]); 59 60 if (ret < 0) { 61 error_setg(errp, 62 "Unable to initialize hash algorithm: %s", 63 gnutls_strerror(ret)); 64 return -1; 65 } 66 67 for (i = 0; i < niov; i++) { 68 ret = gnutls_hash(dig, iov[i].iov_base, iov[i].iov_len); 69 if (ret < 0) { 70 error_setg(errp, 71 "Unable process hash data: %s", 72 gnutls_strerror(ret)); 73 goto error; 74 } 75 } 76 77 ret = gnutls_hash_get_len(qcrypto_hash_alg_map[alg]); 78 if (ret <= 0) { 79 error_setg(errp, 80 "Unable to get hash length: %s", 81 gnutls_strerror(ret)); 82 goto error; 83 } 84 if (*resultlen == 0) { 85 *resultlen = ret; 86 *result = g_new0(uint8_t, *resultlen); 87 } else if (*resultlen != ret) { 88 error_setg(errp, 89 "Result buffer size %zu is smaller than hash %d", 90 *resultlen, ret); 91 goto error; 92 } 93 94 gnutls_hash_deinit(dig, *result); 95 return 0; 96 97 error: 98 gnutls_hash_deinit(dig, NULL); 99 return -1; 100 } 101 102 #else /* ! CONFIG_GNUTLS_HASH */ 103 104 gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg G_GNUC_UNUSED) 105 { 106 return false; 107 } 108 109 int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg, 110 const struct iovec *iov G_GNUC_UNUSED, 111 size_t niov G_GNUC_UNUSED, 112 uint8_t **result G_GNUC_UNUSED, 113 size_t *resultlen G_GNUC_UNUSED, 114 Error **errp) 115 { 116 error_setg(errp, 117 "Hash algorithm %d not supported without GNUTLS", 118 alg); 119 return -1; 120 } 121 122 #endif /* ! CONFIG_GNUTLS_HASH */ 123 124 int qcrypto_hash_bytes(QCryptoHashAlgorithm alg, 125 const char *buf, 126 size_t len, 127 uint8_t **result, 128 size_t *resultlen, 129 Error **errp) 130 { 131 struct iovec iov = { .iov_base = (char *)buf, 132 .iov_len = len }; 133 return qcrypto_hash_bytesv(alg, &iov, 1, result, resultlen, errp); 134 } 135 136 static const char hex[] = "0123456789abcdef"; 137 138 int qcrypto_hash_digestv(QCryptoHashAlgorithm alg, 139 const struct iovec *iov, 140 size_t niov, 141 char **digest, 142 Error **errp) 143 { 144 uint8_t *result = NULL; 145 size_t resultlen = 0; 146 size_t i; 147 148 if (qcrypto_hash_bytesv(alg, iov, niov, &result, &resultlen, errp) < 0) { 149 return -1; 150 } 151 152 *digest = g_new0(char, (resultlen * 2) + 1); 153 for (i = 0 ; i < resultlen ; i++) { 154 (*digest)[(i * 2)] = hex[(result[i] >> 4) & 0xf]; 155 (*digest)[(i * 2) + 1] = hex[result[i] & 0xf]; 156 } 157 (*digest)[resultlen * 2] = '\0'; 158 g_free(result); 159 return 0; 160 } 161 162 int qcrypto_hash_digest(QCryptoHashAlgorithm alg, 163 const char *buf, 164 size_t len, 165 char **digest, 166 Error **errp) 167 { 168 struct iovec iov = { .iov_base = (char *)buf, .iov_len = len }; 169 170 return qcrypto_hash_digestv(alg, &iov, 1, digest, errp); 171 } 172 173 int qcrypto_hash_base64v(QCryptoHashAlgorithm alg, 174 const struct iovec *iov, 175 size_t niov, 176 char **base64, 177 Error **errp) 178 { 179 uint8_t *result = NULL; 180 size_t resultlen = 0; 181 182 if (qcrypto_hash_bytesv(alg, iov, niov, &result, &resultlen, errp) < 0) { 183 return -1; 184 } 185 186 *base64 = g_base64_encode(result, resultlen); 187 g_free(result); 188 return 0; 189 } 190 191 int qcrypto_hash_base64(QCryptoHashAlgorithm alg, 192 const char *buf, 193 size_t len, 194 char **base64, 195 Error **errp) 196 { 197 struct iovec iov = { .iov_base = (char *)buf, .iov_len = len }; 198 199 return qcrypto_hash_base64v(alg, &iov, 1, base64, errp); 200 } 201