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