xref: /openbmc/qemu/crypto/hmac-glib.c (revision 14a5a2aef47e27b6afd1f8855eb41c75b69440dc)
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"
18*14a5a2aeSLongpeng(Mike) #include "hmacpriv.h"
1912a4f216SLongpeng(Mike) 
20e1168052SLongpeng(Mike) /* Support for HMAC Algos has been added in GLib 2.30 */
21e1168052SLongpeng(Mike) #if GLIB_CHECK_VERSION(2, 30, 0)
22e1168052SLongpeng(Mike) 
23e1168052SLongpeng(Mike) static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = {
24e1168052SLongpeng(Mike)     [QCRYPTO_HASH_ALG_MD5] = G_CHECKSUM_MD5,
25e1168052SLongpeng(Mike)     [QCRYPTO_HASH_ALG_SHA1] = G_CHECKSUM_SHA1,
26e1168052SLongpeng(Mike)     [QCRYPTO_HASH_ALG_SHA256] = G_CHECKSUM_SHA256,
27e1168052SLongpeng(Mike) /* Support for HMAC SHA-512 in GLib 2.42 */
28e1168052SLongpeng(Mike) #if GLIB_CHECK_VERSION(2, 42, 0)
29e1168052SLongpeng(Mike)     [QCRYPTO_HASH_ALG_SHA512] = G_CHECKSUM_SHA512,
30e1168052SLongpeng(Mike) #else
31e1168052SLongpeng(Mike)     [QCRYPTO_HASH_ALG_SHA512] = -1,
32e1168052SLongpeng(Mike) #endif
33e1168052SLongpeng(Mike)     [QCRYPTO_HASH_ALG_SHA224] = -1,
34e1168052SLongpeng(Mike)     [QCRYPTO_HASH_ALG_SHA384] = -1,
35e1168052SLongpeng(Mike)     [QCRYPTO_HASH_ALG_RIPEMD160] = -1,
36e1168052SLongpeng(Mike) };
37e1168052SLongpeng(Mike) 
38e1168052SLongpeng(Mike) typedef struct QCryptoHmacGlib QCryptoHmacGlib;
39e1168052SLongpeng(Mike) struct QCryptoHmacGlib {
40e1168052SLongpeng(Mike)     GHmac *ghmac;
41e1168052SLongpeng(Mike) };
42e1168052SLongpeng(Mike) 
43e1168052SLongpeng(Mike) bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
44e1168052SLongpeng(Mike) {
45e1168052SLongpeng(Mike)     if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) &&
46e1168052SLongpeng(Mike)         qcrypto_hmac_alg_map[alg] != -1) {
47e1168052SLongpeng(Mike)         return true;
48e1168052SLongpeng(Mike)     }
49e1168052SLongpeng(Mike) 
50e1168052SLongpeng(Mike)     return false;
51e1168052SLongpeng(Mike) }
52e1168052SLongpeng(Mike) 
53*14a5a2aeSLongpeng(Mike) void *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) 
74d73c04e3SLongpeng(Mike)     return ctx;
75e1168052SLongpeng(Mike) 
76e1168052SLongpeng(Mike) error:
77e1168052SLongpeng(Mike)     g_free(ctx);
78e1168052SLongpeng(Mike)     return NULL;
79e1168052SLongpeng(Mike) }
80e1168052SLongpeng(Mike) 
81*14a5a2aeSLongpeng(Mike) static void
82*14a5a2aeSLongpeng(Mike) qcrypto_glib_hmac_ctx_free(QCryptoHmac *hmac)
83e1168052SLongpeng(Mike) {
84e1168052SLongpeng(Mike)     QCryptoHmacGlib *ctx;
85e1168052SLongpeng(Mike) 
86e1168052SLongpeng(Mike)     ctx = hmac->opaque;
87e1168052SLongpeng(Mike)     g_hmac_unref(ctx->ghmac);
88e1168052SLongpeng(Mike) 
89e1168052SLongpeng(Mike)     g_free(ctx);
90e1168052SLongpeng(Mike) }
91e1168052SLongpeng(Mike) 
92*14a5a2aeSLongpeng(Mike) static int
93*14a5a2aeSLongpeng(Mike) qcrypto_glib_hmac_bytesv(QCryptoHmac *hmac,
94e1168052SLongpeng(Mike)                          const struct iovec *iov,
95e1168052SLongpeng(Mike)                          size_t niov,
96e1168052SLongpeng(Mike)                          uint8_t **result,
97e1168052SLongpeng(Mike)                          size_t *resultlen,
98e1168052SLongpeng(Mike)                          Error **errp)
99e1168052SLongpeng(Mike) {
100e1168052SLongpeng(Mike)     QCryptoHmacGlib *ctx;
101e1168052SLongpeng(Mike)     int i, ret;
102e1168052SLongpeng(Mike) 
103e1168052SLongpeng(Mike)     ctx = hmac->opaque;
104e1168052SLongpeng(Mike) 
105e1168052SLongpeng(Mike)     for (i = 0; i < niov; i++) {
106e1168052SLongpeng(Mike)         g_hmac_update(ctx->ghmac, iov[i].iov_base, iov[i].iov_len);
107e1168052SLongpeng(Mike)     }
108e1168052SLongpeng(Mike) 
109e1168052SLongpeng(Mike)     ret = g_checksum_type_get_length(qcrypto_hmac_alg_map[hmac->alg]);
110e1168052SLongpeng(Mike)     if (ret < 0) {
111e1168052SLongpeng(Mike)         error_setg(errp, "Unable to get hmac length");
112e1168052SLongpeng(Mike)         return -1;
113e1168052SLongpeng(Mike)     }
114e1168052SLongpeng(Mike) 
115e1168052SLongpeng(Mike)     if (*resultlen == 0) {
116e1168052SLongpeng(Mike)         *resultlen = ret;
117e1168052SLongpeng(Mike)         *result = g_new0(uint8_t, *resultlen);
118e1168052SLongpeng(Mike)     } else if (*resultlen != ret) {
119e1168052SLongpeng(Mike)         error_setg(errp, "Result buffer size %zu is smaller than hmac %d",
120e1168052SLongpeng(Mike)                    *resultlen, ret);
121e1168052SLongpeng(Mike)         return -1;
122e1168052SLongpeng(Mike)     }
123e1168052SLongpeng(Mike) 
124e1168052SLongpeng(Mike)     g_hmac_get_digest(ctx->ghmac, *result, resultlen);
125e1168052SLongpeng(Mike) 
126e1168052SLongpeng(Mike)     return 0;
127e1168052SLongpeng(Mike) }
128e1168052SLongpeng(Mike) 
129e1168052SLongpeng(Mike) #else
130e1168052SLongpeng(Mike) 
13112a4f216SLongpeng(Mike) bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
13212a4f216SLongpeng(Mike) {
13312a4f216SLongpeng(Mike)     return false;
13412a4f216SLongpeng(Mike) }
13512a4f216SLongpeng(Mike) 
136*14a5a2aeSLongpeng(Mike) void *qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg,
13712a4f216SLongpeng(Mike)                            const uint8_t *key, size_t nkey,
13812a4f216SLongpeng(Mike)                            Error **errp)
13912a4f216SLongpeng(Mike) {
14012a4f216SLongpeng(Mike)     return NULL;
14112a4f216SLongpeng(Mike) }
14212a4f216SLongpeng(Mike) 
143*14a5a2aeSLongpeng(Mike) static void
144*14a5a2aeSLongpeng(Mike) qcrypto_glib_hmac_ctx_free(QCryptoHmac *hmac)
14512a4f216SLongpeng(Mike) {
14612a4f216SLongpeng(Mike)     return;
14712a4f216SLongpeng(Mike) }
14812a4f216SLongpeng(Mike) 
149*14a5a2aeSLongpeng(Mike) static int
150*14a5a2aeSLongpeng(Mike) qcrypto_glib_hmac_bytesv(QCryptoHmac *hmac,
15112a4f216SLongpeng(Mike)                          const struct iovec *iov,
15212a4f216SLongpeng(Mike)                          size_t niov,
15312a4f216SLongpeng(Mike)                          uint8_t **result,
15412a4f216SLongpeng(Mike)                          size_t *resultlen,
15512a4f216SLongpeng(Mike)                          Error **errp)
15612a4f216SLongpeng(Mike) {
15712a4f216SLongpeng(Mike)     return -1;
15812a4f216SLongpeng(Mike) }
159e1168052SLongpeng(Mike) 
160e1168052SLongpeng(Mike) #endif
161*14a5a2aeSLongpeng(Mike) 
162*14a5a2aeSLongpeng(Mike) QCryptoHmacDriver qcrypto_hmac_lib_driver = {
163*14a5a2aeSLongpeng(Mike)     .hmac_bytesv = qcrypto_glib_hmac_bytesv,
164*14a5a2aeSLongpeng(Mike)     .hmac_free = qcrypto_glib_hmac_ctx_free,
165*14a5a2aeSLongpeng(Mike) };
166