diff options
author | Daniel P. Berrangé <berrange@redhat.com> | 2021-06-25 18:32:14 +0100 |
---|---|---|
committer | Daniel P. Berrangé <berrange@redhat.com> | 2021-07-14 14:15:52 +0100 |
commit | 8c1d3dc772352284e7f8757131f2ed3f483dd922 (patch) | |
tree | 847dc84f47059a4c29e7663a4da0f4b625c0a403 /crypto/pbkdf-gnutls.c | |
parent | 678307b605da9ebbda3a6269b5a6ab2d3002e241 (diff) |
crypto: add gnutls pbkdf provider
This adds support for using gnutls as a provider of the crypto
pbkdf APIs.
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Diffstat (limited to 'crypto/pbkdf-gnutls.c')
-rw-r--r-- | crypto/pbkdf-gnutls.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/crypto/pbkdf-gnutls.c b/crypto/pbkdf-gnutls.c new file mode 100644 index 0000000000..2dfbbd382c --- /dev/null +++ b/crypto/pbkdf-gnutls.c @@ -0,0 +1,90 @@ +/* + * QEMU Crypto PBKDF support (Password-Based Key Derivation Function) + * + * Copyright (c) 2021 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.1 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 <gnutls/crypto.h> +#include "qapi/error.h" +#include "crypto/pbkdf.h" + +bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash) +{ + switch (hash) { + case QCRYPTO_HASH_ALG_MD5: + case QCRYPTO_HASH_ALG_SHA1: + case QCRYPTO_HASH_ALG_SHA224: + case QCRYPTO_HASH_ALG_SHA256: + case QCRYPTO_HASH_ALG_SHA384: + case QCRYPTO_HASH_ALG_SHA512: + case QCRYPTO_HASH_ALG_RIPEMD160: + return true; + default: + return false; + } +} + +int qcrypto_pbkdf2(QCryptoHashAlgorithm hash, + const uint8_t *key, size_t nkey, + const uint8_t *salt, size_t nsalt, + uint64_t iterations, + uint8_t *out, size_t nout, + Error **errp) +{ + static const int hash_map[QCRYPTO_HASH_ALG__MAX] = { + [QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5, + [QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1, + [QCRYPTO_HASH_ALG_SHA224] = GNUTLS_DIG_SHA224, + [QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256, + [QCRYPTO_HASH_ALG_SHA384] = GNUTLS_DIG_SHA384, + [QCRYPTO_HASH_ALG_SHA512] = GNUTLS_DIG_SHA512, + [QCRYPTO_HASH_ALG_RIPEMD160] = GNUTLS_DIG_RMD160, + }; + int ret; + const gnutls_datum_t gkey = { (unsigned char *)key, nkey }; + const gnutls_datum_t gsalt = { (unsigned char *)salt, nsalt }; + + if (iterations > ULONG_MAX) { + error_setg_errno(errp, ERANGE, + "PBKDF iterations %llu must be less than %lu", + (long long unsigned)iterations, ULONG_MAX); + return -1; + } + + if (hash >= G_N_ELEMENTS(hash_map) || + hash_map[hash] == GNUTLS_DIG_UNKNOWN) { + error_setg_errno(errp, ENOSYS, + "PBKDF does not support hash algorithm %s", + QCryptoHashAlgorithm_str(hash)); + return -1; + } + + ret = gnutls_pbkdf2(hash_map[hash], + &gkey, + &gsalt, + iterations, + out, + nout); + if (ret != 0) { + error_setg(errp, "Cannot derive password: %s", + gnutls_strerror(ret)); + return -1; + } + + return 0; +} |