blob: 2dfbbd382c2e5fb95b6e0f000c243a983794f6ff [file] [log] [blame]
Daniel P. Berrangé8c1d3dc2021-06-25 18:32:14 +01001/*
2 * QEMU Crypto PBKDF support (Password-Based Key Derivation Function)
3 *
4 * Copyright (c) 2021 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 <gnutls/crypto.h>
23#include "qapi/error.h"
24#include "crypto/pbkdf.h"
25
26bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
27{
28 switch (hash) {
29 case QCRYPTO_HASH_ALG_MD5:
30 case QCRYPTO_HASH_ALG_SHA1:
31 case QCRYPTO_HASH_ALG_SHA224:
32 case QCRYPTO_HASH_ALG_SHA256:
33 case QCRYPTO_HASH_ALG_SHA384:
34 case QCRYPTO_HASH_ALG_SHA512:
35 case QCRYPTO_HASH_ALG_RIPEMD160:
36 return true;
37 default:
38 return false;
39 }
40}
41
42int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
43 const uint8_t *key, size_t nkey,
44 const uint8_t *salt, size_t nsalt,
45 uint64_t iterations,
46 uint8_t *out, size_t nout,
47 Error **errp)
48{
49 static const int hash_map[QCRYPTO_HASH_ALG__MAX] = {
50 [QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5,
51 [QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1,
52 [QCRYPTO_HASH_ALG_SHA224] = GNUTLS_DIG_SHA224,
53 [QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256,
54 [QCRYPTO_HASH_ALG_SHA384] = GNUTLS_DIG_SHA384,
55 [QCRYPTO_HASH_ALG_SHA512] = GNUTLS_DIG_SHA512,
56 [QCRYPTO_HASH_ALG_RIPEMD160] = GNUTLS_DIG_RMD160,
57 };
58 int ret;
59 const gnutls_datum_t gkey = { (unsigned char *)key, nkey };
60 const gnutls_datum_t gsalt = { (unsigned char *)salt, nsalt };
61
62 if (iterations > ULONG_MAX) {
63 error_setg_errno(errp, ERANGE,
64 "PBKDF iterations %llu must be less than %lu",
65 (long long unsigned)iterations, ULONG_MAX);
66 return -1;
67 }
68
69 if (hash >= G_N_ELEMENTS(hash_map) ||
70 hash_map[hash] == GNUTLS_DIG_UNKNOWN) {
71 error_setg_errno(errp, ENOSYS,
72 "PBKDF does not support hash algorithm %s",
73 QCryptoHashAlgorithm_str(hash));
74 return -1;
75 }
76
77 ret = gnutls_pbkdf2(hash_map[hash],
78 &gkey,
79 &gsalt,
80 iterations,
81 out,
82 nout);
83 if (ret != 0) {
84 error_setg(errp, "Cannot derive password: %s",
85 gnutls_strerror(ret));
86 return -1;
87 }
88
89 return 0;
90}