1 /* 2 * QEMU Crypto af_alg-backend hash/hmac support 3 * 4 * Copyright (c) 2017 HUAWEI TECHNOLOGIES CO., LTD. 5 * 6 * Authors: 7 * Longpeng(Mike) <longpeng2@huawei.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2 or 10 * (at your option) any later version. See the COPYING file in the 11 * top-level directory. 12 */ 13 #include "qemu/osdep.h" 14 #include "qemu/iov.h" 15 #include "qemu/sockets.h" 16 #include "qemu-common.h" 17 #include "qapi/error.h" 18 #include "crypto/hash.h" 19 #include "crypto/hmac.h" 20 #include "hashpriv.h" 21 #include "hmacpriv.h" 22 23 static char * 24 qcrypto_afalg_hash_format_name(QCryptoHashAlgorithm alg, 25 bool is_hmac, 26 Error **errp) 27 { 28 char *name; 29 const char *alg_name; 30 31 switch (alg) { 32 case QCRYPTO_HASH_ALG_MD5: 33 alg_name = "md5"; 34 break; 35 case QCRYPTO_HASH_ALG_SHA1: 36 alg_name = "sha1"; 37 break; 38 case QCRYPTO_HASH_ALG_SHA224: 39 alg_name = "sha224"; 40 break; 41 case QCRYPTO_HASH_ALG_SHA256: 42 alg_name = "sha256"; 43 break; 44 case QCRYPTO_HASH_ALG_SHA384: 45 alg_name = "sha384"; 46 break; 47 case QCRYPTO_HASH_ALG_SHA512: 48 alg_name = "sha512"; 49 break; 50 case QCRYPTO_HASH_ALG_RIPEMD160: 51 alg_name = "rmd160"; 52 break; 53 54 default: 55 error_setg(errp, "Unsupported hash algorithm %d", alg); 56 return NULL; 57 } 58 59 if (is_hmac) { 60 name = g_strdup_printf("hmac(%s)", alg_name); 61 } else { 62 name = g_strdup_printf("%s", alg_name); 63 } 64 65 return name; 66 } 67 68 static QCryptoAFAlg * 69 qcrypto_afalg_hash_hmac_ctx_new(QCryptoHashAlgorithm alg, 70 const uint8_t *key, size_t nkey, 71 bool is_hmac, Error **errp) 72 { 73 QCryptoAFAlg *afalg; 74 char *name; 75 76 name = qcrypto_afalg_hash_format_name(alg, is_hmac, errp); 77 if (!name) { 78 return NULL; 79 } 80 81 afalg = qcrypto_afalg_comm_alloc(AFALG_TYPE_HASH, name, errp); 82 if (!afalg) { 83 g_free(name); 84 return NULL; 85 } 86 87 g_free(name); 88 89 /* HMAC needs setkey */ 90 if (is_hmac) { 91 if (qemu_setsockopt(afalg->tfmfd, SOL_ALG, ALG_SET_KEY, 92 key, nkey) != 0) { 93 error_setg_errno(errp, errno, "Set hmac key failed"); 94 qcrypto_afalg_comm_free(afalg); 95 return NULL; 96 } 97 } 98 99 return afalg; 100 } 101 102 static QCryptoAFAlg * 103 qcrypto_afalg_hash_ctx_new(QCryptoHashAlgorithm alg, 104 Error **errp) 105 { 106 return qcrypto_afalg_hash_hmac_ctx_new(alg, NULL, 0, false, errp); 107 } 108 109 QCryptoAFAlg * 110 qcrypto_afalg_hmac_ctx_new(QCryptoHashAlgorithm alg, 111 const uint8_t *key, size_t nkey, 112 Error **errp) 113 { 114 return qcrypto_afalg_hash_hmac_ctx_new(alg, key, nkey, true, errp); 115 } 116 117 static int 118 qcrypto_afalg_hash_hmac_bytesv(QCryptoAFAlg *hmac, 119 QCryptoHashAlgorithm alg, 120 const struct iovec *iov, 121 size_t niov, uint8_t **result, 122 size_t *resultlen, 123 Error **errp) 124 { 125 QCryptoAFAlg *afalg; 126 struct iovec outv; 127 int ret = 0; 128 bool is_hmac = (hmac != NULL) ? true : false; 129 const int expect_len = qcrypto_hash_digest_len(alg); 130 131 if (*resultlen == 0) { 132 *resultlen = expect_len; 133 *result = g_new0(uint8_t, *resultlen); 134 } else if (*resultlen != expect_len) { 135 error_setg(errp, 136 "Result buffer size %zu is not match hash %d", 137 *resultlen, expect_len); 138 return -1; 139 } 140 141 if (is_hmac) { 142 afalg = hmac; 143 } else { 144 afalg = qcrypto_afalg_hash_ctx_new(alg, errp); 145 if (!afalg) { 146 return -1; 147 } 148 } 149 150 /* send data to kernel's crypto core */ 151 ret = iov_send_recv(afalg->opfd, iov, niov, 152 0, iov_size(iov, niov), true); 153 if (ret < 0) { 154 error_setg_errno(errp, errno, "Send data to afalg-core failed"); 155 goto out; 156 } 157 158 /* hash && get result */ 159 outv.iov_base = *result; 160 outv.iov_len = *resultlen; 161 ret = iov_send_recv(afalg->opfd, &outv, 1, 162 0, iov_size(&outv, 1), false); 163 if (ret < 0) { 164 error_setg_errno(errp, errno, "Recv result from afalg-core failed"); 165 } else { 166 ret = 0; 167 } 168 169 out: 170 if (!is_hmac) { 171 qcrypto_afalg_comm_free(afalg); 172 } 173 return ret; 174 } 175 176 static int 177 qcrypto_afalg_hash_bytesv(QCryptoHashAlgorithm alg, 178 const struct iovec *iov, 179 size_t niov, uint8_t **result, 180 size_t *resultlen, 181 Error **errp) 182 { 183 return qcrypto_afalg_hash_hmac_bytesv(NULL, alg, iov, niov, result, 184 resultlen, errp); 185 } 186 187 static int 188 qcrypto_afalg_hmac_bytesv(QCryptoHmac *hmac, 189 const struct iovec *iov, 190 size_t niov, uint8_t **result, 191 size_t *resultlen, 192 Error **errp) 193 { 194 return qcrypto_afalg_hash_hmac_bytesv(hmac->opaque, hmac->alg, 195 iov, niov, result, resultlen, 196 errp); 197 } 198 199 static void qcrypto_afalg_hmac_ctx_free(QCryptoHmac *hmac) 200 { 201 QCryptoAFAlg *afalg; 202 203 afalg = hmac->opaque; 204 qcrypto_afalg_comm_free(afalg); 205 } 206 207 QCryptoHashDriver qcrypto_hash_afalg_driver = { 208 .hash_bytesv = qcrypto_afalg_hash_bytesv, 209 }; 210 211 QCryptoHmacDriver qcrypto_hmac_afalg_driver = { 212 .hmac_bytesv = qcrypto_afalg_hmac_bytesv, 213 .hmac_free = qcrypto_afalg_hmac_ctx_free, 214 }; 215