summaryrefslogtreecommitdiff
path: root/crypto/hash-gcrypt.c
diff options
context:
space:
mode:
authorDaniel P. Berrange <berrange@redhat.com>2016-03-11 18:09:22 +0000
committerDaniel P. Berrange <berrange@redhat.com>2016-07-04 10:47:09 +0100
commit0c16c056a4f9dec18fdd56feec82a5db9ff3c15e (patch)
treec670217045b5766136a86cb3612feda66fce64b1 /crypto/hash-gcrypt.c
parent8cbfc94269e37a001d501cca3f4e4cb4ba6dbe0a (diff)
downloadqemu-0c16c056a4f9dec18fdd56feec82a5db9ff3c15e.tar.gz
crypto: switch hash code to use nettle/gcrypt directly
Currently the internal hash code is using the gnutls hash APIs. GNUTLS in turn is wrapping either nettle or gcrypt. Not only were the GNUTLS hash APIs not added until GNUTLS 2.9.10, but they don't expose support for all the algorithms QEMU needs to use with LUKS. Address this by directly wrapping nettle/gcrypt in QEMU and avoiding GNUTLS's extra layer of indirection. This gives us support for hash functions on a much wider range of platforms and opens up ability to support more hash functions. It also avoids a GNUTLS bug which would not correctly handle hashing of large data blocks if int != size_t. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Diffstat (limited to 'crypto/hash-gcrypt.c')
-rw-r--r--crypto/hash-gcrypt.c106
1 files changed, 106 insertions, 0 deletions
diff --git a/crypto/hash-gcrypt.c b/crypto/hash-gcrypt.c
new file mode 100644
index 0000000000..e0456897ac
--- /dev/null
+++ b/crypto/hash-gcrypt.c
@@ -0,0 +1,106 @@
+/*
+ * QEMU Crypto hash algorithms
+ *
+ * Copyright (c) 2016 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "crypto/hash.h"
+#include "gcrypt.h"
+
+
+static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALG__MAX] = {
+ [QCRYPTO_HASH_ALG_MD5] = GCRY_MD_MD5,
+ [QCRYPTO_HASH_ALG_SHA1] = GCRY_MD_SHA1,
+ [QCRYPTO_HASH_ALG_SHA256] = GCRY_MD_SHA256,
+};
+
+gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
+{
+ if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map) &&
+ qcrypto_hash_alg_map[alg] != GCRY_MD_NONE) {
+ return true;
+ }
+ return false;
+}
+
+
+int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
+ const struct iovec *iov,
+ size_t niov,
+ uint8_t **result,
+ size_t *resultlen,
+ Error **errp)
+{
+ int i, ret;
+ gcry_md_hd_t md;
+ unsigned char *digest;
+
+ if (alg >= G_N_ELEMENTS(qcrypto_hash_alg_map) ||
+ qcrypto_hash_alg_map[alg] == GCRY_MD_NONE) {
+ error_setg(errp,
+ "Unknown hash algorithm %d",
+ alg);
+ return -1;
+ }
+
+ ret = gcry_md_open(&md, qcrypto_hash_alg_map[alg], 0);
+
+ if (ret < 0) {
+ error_setg(errp,
+ "Unable to initialize hash algorithm: %s",
+ gcry_strerror(ret));
+ return -1;
+ }
+
+ for (i = 0; i < niov; i++) {
+ gcry_md_write(md, iov[i].iov_base, iov[i].iov_len);
+ }
+
+ ret = gcry_md_get_algo_dlen(qcrypto_hash_alg_map[alg]);
+ if (ret <= 0) {
+ error_setg(errp,
+ "Unable to get hash length: %s",
+ gcry_strerror(ret));
+ goto error;
+ }
+ if (*resultlen == 0) {
+ *resultlen = ret;
+ *result = g_new0(uint8_t, *resultlen);
+ } else if (*resultlen != ret) {
+ error_setg(errp,
+ "Result buffer size %zu is smaller than hash %d",
+ *resultlen, ret);
+ goto error;
+ }
+
+ digest = gcry_md_read(md, 0);
+ if (!digest) {
+ error_setg(errp,
+ "No digest produced");
+ goto error;
+ }
+ memcpy(*result, digest, *resultlen);
+
+ gcry_md_close(md);
+ return 0;
+
+ error:
+ gcry_md_close(md);
+ return -1;
+}