xref: /openbmc/qemu/crypto/hmac-glib.c (revision d73c04e3ca3d4a1ac73da7f7952f769824417b47)
112a4f216SLongpeng(Mike) /*
212a4f216SLongpeng(Mike)  * QEMU Crypto hmac algorithms (based on glib)
312a4f216SLongpeng(Mike)  *
412a4f216SLongpeng(Mike)  * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
512a4f216SLongpeng(Mike)  *
612a4f216SLongpeng(Mike)  * Authors:
712a4f216SLongpeng(Mike)  *    Longpeng(Mike) <longpeng2@huawei.com>
812a4f216SLongpeng(Mike)  *
912a4f216SLongpeng(Mike)  * This work is licensed under the terms of the GNU GPL, version 2 or
1012a4f216SLongpeng(Mike)  * (at your option) any later version.  See the COPYING file in the
1112a4f216SLongpeng(Mike)  * top-level directory.
1212a4f216SLongpeng(Mike)  *
1312a4f216SLongpeng(Mike)  */
1412a4f216SLongpeng(Mike) 
1512a4f216SLongpeng(Mike) #include "qemu/osdep.h"
1612a4f216SLongpeng(Mike) #include "qapi/error.h"
1712a4f216SLongpeng(Mike) #include "crypto/hmac.h"
1812a4f216SLongpeng(Mike) 
19e1168052SLongpeng(Mike) /* Support for HMAC Algos has been added in GLib 2.30 */
20e1168052SLongpeng(Mike) #if GLIB_CHECK_VERSION(2, 30, 0)
21e1168052SLongpeng(Mike) 
22e1168052SLongpeng(Mike) static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = {
23e1168052SLongpeng(Mike)     [QCRYPTO_HASH_ALG_MD5] = G_CHECKSUM_MD5,
24e1168052SLongpeng(Mike)     [QCRYPTO_HASH_ALG_SHA1] = G_CHECKSUM_SHA1,
25e1168052SLongpeng(Mike)     [QCRYPTO_HASH_ALG_SHA256] = G_CHECKSUM_SHA256,
26e1168052SLongpeng(Mike) /* Support for HMAC SHA-512 in GLib 2.42 */
27e1168052SLongpeng(Mike) #if GLIB_CHECK_VERSION(2, 42, 0)
28e1168052SLongpeng(Mike)     [QCRYPTO_HASH_ALG_SHA512] = G_CHECKSUM_SHA512,
29e1168052SLongpeng(Mike) #else
30e1168052SLongpeng(Mike)     [QCRYPTO_HASH_ALG_SHA512] = -1,
31e1168052SLongpeng(Mike) #endif
32e1168052SLongpeng(Mike)     [QCRYPTO_HASH_ALG_SHA224] = -1,
33e1168052SLongpeng(Mike)     [QCRYPTO_HASH_ALG_SHA384] = -1,
34e1168052SLongpeng(Mike)     [QCRYPTO_HASH_ALG_RIPEMD160] = -1,
35e1168052SLongpeng(Mike) };
36e1168052SLongpeng(Mike) 
37e1168052SLongpeng(Mike) typedef struct QCryptoHmacGlib QCryptoHmacGlib;
38e1168052SLongpeng(Mike) struct QCryptoHmacGlib {
39e1168052SLongpeng(Mike)     GHmac *ghmac;
40e1168052SLongpeng(Mike) };
41e1168052SLongpeng(Mike) 
42e1168052SLongpeng(Mike) bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
43e1168052SLongpeng(Mike) {
44e1168052SLongpeng(Mike)     if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) &&
45e1168052SLongpeng(Mike)         qcrypto_hmac_alg_map[alg] != -1) {
46e1168052SLongpeng(Mike)         return true;
47e1168052SLongpeng(Mike)     }
48e1168052SLongpeng(Mike) 
49e1168052SLongpeng(Mike)     return false;
50e1168052SLongpeng(Mike) }
51e1168052SLongpeng(Mike) 
52*d73c04e3SLongpeng(Mike) static QCryptoHmacGlib *
53*d73c04e3SLongpeng(Mike) qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg,
54e1168052SLongpeng(Mike)                      const uint8_t *key, size_t nkey,
55e1168052SLongpeng(Mike)                      Error **errp)
56e1168052SLongpeng(Mike) {
57e1168052SLongpeng(Mike)     QCryptoHmacGlib *ctx;
58e1168052SLongpeng(Mike) 
59e1168052SLongpeng(Mike)     if (!qcrypto_hmac_supports(alg)) {
60e1168052SLongpeng(Mike)         error_setg(errp, "Unsupported hmac algorithm %s",
61e1168052SLongpeng(Mike)                    QCryptoHashAlgorithm_lookup[alg]);
62e1168052SLongpeng(Mike)         return NULL;
63e1168052SLongpeng(Mike)     }
64e1168052SLongpeng(Mike) 
65e1168052SLongpeng(Mike)     ctx = g_new0(QCryptoHmacGlib, 1);
66e1168052SLongpeng(Mike) 
67e1168052SLongpeng(Mike)     ctx->ghmac = g_hmac_new(qcrypto_hmac_alg_map[alg],
68e1168052SLongpeng(Mike)                             (const uint8_t *)key, nkey);
69e1168052SLongpeng(Mike)     if (!ctx->ghmac) {
70e1168052SLongpeng(Mike)         error_setg(errp, "Cannot initialize hmac and set key");
71e1168052SLongpeng(Mike)         goto error;
72e1168052SLongpeng(Mike)     }
73e1168052SLongpeng(Mike) 
74*d73c04e3SLongpeng(Mike)     return ctx;
75e1168052SLongpeng(Mike) 
76e1168052SLongpeng(Mike) error:
77e1168052SLongpeng(Mike)     g_free(ctx);
78e1168052SLongpeng(Mike)     return NULL;
79e1168052SLongpeng(Mike) }
80e1168052SLongpeng(Mike) 
81e1168052SLongpeng(Mike) void qcrypto_hmac_free(QCryptoHmac *hmac)
82e1168052SLongpeng(Mike) {
83e1168052SLongpeng(Mike)     QCryptoHmacGlib *ctx;
84e1168052SLongpeng(Mike) 
85e1168052SLongpeng(Mike)     if (!hmac) {
86e1168052SLongpeng(Mike)         return;
87e1168052SLongpeng(Mike)     }
88e1168052SLongpeng(Mike) 
89e1168052SLongpeng(Mike)     ctx = hmac->opaque;
90e1168052SLongpeng(Mike)     g_hmac_unref(ctx->ghmac);
91e1168052SLongpeng(Mike) 
92e1168052SLongpeng(Mike)     g_free(ctx);
93e1168052SLongpeng(Mike)     g_free(hmac);
94e1168052SLongpeng(Mike) }
95e1168052SLongpeng(Mike) 
96e1168052SLongpeng(Mike) int qcrypto_hmac_bytesv(QCryptoHmac *hmac,
97e1168052SLongpeng(Mike)                         const struct iovec *iov,
98e1168052SLongpeng(Mike)                         size_t niov,
99e1168052SLongpeng(Mike)                         uint8_t **result,
100e1168052SLongpeng(Mike)                         size_t *resultlen,
101e1168052SLongpeng(Mike)                         Error **errp)
102e1168052SLongpeng(Mike) {
103e1168052SLongpeng(Mike)     QCryptoHmacGlib *ctx;
104e1168052SLongpeng(Mike)     int i, ret;
105e1168052SLongpeng(Mike) 
106e1168052SLongpeng(Mike)     ctx = hmac->opaque;
107e1168052SLongpeng(Mike) 
108e1168052SLongpeng(Mike)     for (i = 0; i < niov; i++) {
109e1168052SLongpeng(Mike)         g_hmac_update(ctx->ghmac, iov[i].iov_base, iov[i].iov_len);
110e1168052SLongpeng(Mike)     }
111e1168052SLongpeng(Mike) 
112e1168052SLongpeng(Mike)     ret = g_checksum_type_get_length(qcrypto_hmac_alg_map[hmac->alg]);
113e1168052SLongpeng(Mike)     if (ret < 0) {
114e1168052SLongpeng(Mike)         error_setg(errp, "Unable to get hmac length");
115e1168052SLongpeng(Mike)         return -1;
116e1168052SLongpeng(Mike)     }
117e1168052SLongpeng(Mike) 
118e1168052SLongpeng(Mike)     if (*resultlen == 0) {
119e1168052SLongpeng(Mike)         *resultlen = ret;
120e1168052SLongpeng(Mike)         *result = g_new0(uint8_t, *resultlen);
121e1168052SLongpeng(Mike)     } else if (*resultlen != ret) {
122e1168052SLongpeng(Mike)         error_setg(errp, "Result buffer size %zu is smaller than hmac %d",
123e1168052SLongpeng(Mike)                    *resultlen, ret);
124e1168052SLongpeng(Mike)         return -1;
125e1168052SLongpeng(Mike)     }
126e1168052SLongpeng(Mike) 
127e1168052SLongpeng(Mike)     g_hmac_get_digest(ctx->ghmac, *result, resultlen);
128e1168052SLongpeng(Mike) 
129e1168052SLongpeng(Mike)     return 0;
130e1168052SLongpeng(Mike) }
131e1168052SLongpeng(Mike) 
132*d73c04e3SLongpeng(Mike) QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg,
133*d73c04e3SLongpeng(Mike)                               const uint8_t *key, size_t nkey,
134*d73c04e3SLongpeng(Mike)                               Error **errp)
135*d73c04e3SLongpeng(Mike) {
136*d73c04e3SLongpeng(Mike)     QCryptoHmac *hmac;
137*d73c04e3SLongpeng(Mike)     QCryptoHmacGlib *ctx;
138*d73c04e3SLongpeng(Mike) 
139*d73c04e3SLongpeng(Mike)     ctx = qcrypto_hmac_ctx_new(alg, key, nkey, errp);
140*d73c04e3SLongpeng(Mike)     if (!ctx) {
141*d73c04e3SLongpeng(Mike)         return NULL;
142*d73c04e3SLongpeng(Mike)     }
143*d73c04e3SLongpeng(Mike) 
144*d73c04e3SLongpeng(Mike)     hmac = g_new0(QCryptoHmac, 1);
145*d73c04e3SLongpeng(Mike)     hmac->alg = alg;
146*d73c04e3SLongpeng(Mike)     hmac->opaque = ctx;
147*d73c04e3SLongpeng(Mike) 
148*d73c04e3SLongpeng(Mike)     return hmac;
149*d73c04e3SLongpeng(Mike) }
150*d73c04e3SLongpeng(Mike) 
151e1168052SLongpeng(Mike) #else
152e1168052SLongpeng(Mike) 
15312a4f216SLongpeng(Mike) bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
15412a4f216SLongpeng(Mike) {
15512a4f216SLongpeng(Mike)     return false;
15612a4f216SLongpeng(Mike) }
15712a4f216SLongpeng(Mike) 
15812a4f216SLongpeng(Mike) QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg,
15912a4f216SLongpeng(Mike)                               const uint8_t *key, size_t nkey,
16012a4f216SLongpeng(Mike)                               Error **errp)
16112a4f216SLongpeng(Mike) {
16212a4f216SLongpeng(Mike)     return NULL;
16312a4f216SLongpeng(Mike) }
16412a4f216SLongpeng(Mike) 
16512a4f216SLongpeng(Mike) void qcrypto_hmac_free(QCryptoHmac *hmac)
16612a4f216SLongpeng(Mike) {
16712a4f216SLongpeng(Mike)     return;
16812a4f216SLongpeng(Mike) }
16912a4f216SLongpeng(Mike) 
17012a4f216SLongpeng(Mike) int qcrypto_hmac_bytesv(QCryptoHmac *hmac,
17112a4f216SLongpeng(Mike)                         const struct iovec *iov,
17212a4f216SLongpeng(Mike)                         size_t niov,
17312a4f216SLongpeng(Mike)                         uint8_t **result,
17412a4f216SLongpeng(Mike)                         size_t *resultlen,
17512a4f216SLongpeng(Mike)                         Error **errp)
17612a4f216SLongpeng(Mike) {
17712a4f216SLongpeng(Mike)     return -1;
17812a4f216SLongpeng(Mike) }
179e1168052SLongpeng(Mike) 
180e1168052SLongpeng(Mike) #endif
181