19a059773SLongpeng(Mike) /* 242e7e15fSLongpeng(Mike) * QEMU Crypto af_alg-backend hash/hmac support 39a059773SLongpeng(Mike) * 490c3dc60SAlejandro Zeise * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates 59a059773SLongpeng(Mike) * Copyright (c) 2017 HUAWEI TECHNOLOGIES CO., LTD. 69a059773SLongpeng(Mike) * 79a059773SLongpeng(Mike) * Authors: 89a059773SLongpeng(Mike) * Longpeng(Mike) <longpeng2@huawei.com> 99a059773SLongpeng(Mike) * 109a059773SLongpeng(Mike) * This work is licensed under the terms of the GNU GPL, version 2 or 119a059773SLongpeng(Mike) * (at your option) any later version. See the COPYING file in the 129a059773SLongpeng(Mike) * top-level directory. 139a059773SLongpeng(Mike) */ 149a059773SLongpeng(Mike) #include "qemu/osdep.h" 159a059773SLongpeng(Mike) #include "qemu/iov.h" 169a059773SLongpeng(Mike) #include "qemu/sockets.h" 179a059773SLongpeng(Mike) #include "qapi/error.h" 189a059773SLongpeng(Mike) #include "crypto/hash.h" 1942e7e15fSLongpeng(Mike) #include "crypto/hmac.h" 209a059773SLongpeng(Mike) #include "hashpriv.h" 2142e7e15fSLongpeng(Mike) #include "hmacpriv.h" 229a059773SLongpeng(Mike) 239a059773SLongpeng(Mike) static char * 24ef834aa2SMarkus Armbruster qcrypto_afalg_hash_format_name(QCryptoHashAlgo alg, 2542e7e15fSLongpeng(Mike) bool is_hmac, 269a059773SLongpeng(Mike) Error **errp) 279a059773SLongpeng(Mike) { 289a059773SLongpeng(Mike) char *name; 299a059773SLongpeng(Mike) const char *alg_name; 309a059773SLongpeng(Mike) 319a059773SLongpeng(Mike) switch (alg) { 32ef834aa2SMarkus Armbruster case QCRYPTO_HASH_ALGO_MD5: 339a059773SLongpeng(Mike) alg_name = "md5"; 349a059773SLongpeng(Mike) break; 35ef834aa2SMarkus Armbruster case QCRYPTO_HASH_ALGO_SHA1: 369a059773SLongpeng(Mike) alg_name = "sha1"; 379a059773SLongpeng(Mike) break; 38ef834aa2SMarkus Armbruster case QCRYPTO_HASH_ALGO_SHA224: 399a059773SLongpeng(Mike) alg_name = "sha224"; 409a059773SLongpeng(Mike) break; 41ef834aa2SMarkus Armbruster case QCRYPTO_HASH_ALGO_SHA256: 429a059773SLongpeng(Mike) alg_name = "sha256"; 439a059773SLongpeng(Mike) break; 44ef834aa2SMarkus Armbruster case QCRYPTO_HASH_ALGO_SHA384: 459a059773SLongpeng(Mike) alg_name = "sha384"; 469a059773SLongpeng(Mike) break; 47ef834aa2SMarkus Armbruster case QCRYPTO_HASH_ALGO_SHA512: 489a059773SLongpeng(Mike) alg_name = "sha512"; 499a059773SLongpeng(Mike) break; 50ef834aa2SMarkus Armbruster case QCRYPTO_HASH_ALGO_RIPEMD160: 519a059773SLongpeng(Mike) alg_name = "rmd160"; 529a059773SLongpeng(Mike) break; 539a059773SLongpeng(Mike) 549a059773SLongpeng(Mike) default: 559a059773SLongpeng(Mike) error_setg(errp, "Unsupported hash algorithm %d", alg); 569a059773SLongpeng(Mike) return NULL; 579a059773SLongpeng(Mike) } 589a059773SLongpeng(Mike) 5942e7e15fSLongpeng(Mike) if (is_hmac) { 6042e7e15fSLongpeng(Mike) name = g_strdup_printf("hmac(%s)", alg_name); 6142e7e15fSLongpeng(Mike) } else { 629a059773SLongpeng(Mike) name = g_strdup_printf("%s", alg_name); 6342e7e15fSLongpeng(Mike) } 649a059773SLongpeng(Mike) 659a059773SLongpeng(Mike) return name; 669a059773SLongpeng(Mike) } 679a059773SLongpeng(Mike) 688f525028SMarkus Armbruster static QCryptoAFAlgo * 69ef834aa2SMarkus Armbruster qcrypto_afalg_hash_hmac_ctx_new(QCryptoHashAlgo alg, 7042e7e15fSLongpeng(Mike) const uint8_t *key, size_t nkey, 7142e7e15fSLongpeng(Mike) bool is_hmac, Error **errp) 729a059773SLongpeng(Mike) { 738f525028SMarkus Armbruster QCryptoAFAlgo *afalg; 749a059773SLongpeng(Mike) char *name; 759a059773SLongpeng(Mike) 7642e7e15fSLongpeng(Mike) name = qcrypto_afalg_hash_format_name(alg, is_hmac, errp); 779a059773SLongpeng(Mike) if (!name) { 789a059773SLongpeng(Mike) return NULL; 799a059773SLongpeng(Mike) } 809a059773SLongpeng(Mike) 819a059773SLongpeng(Mike) afalg = qcrypto_afalg_comm_alloc(AFALG_TYPE_HASH, name, errp); 829a059773SLongpeng(Mike) if (!afalg) { 839a059773SLongpeng(Mike) g_free(name); 849a059773SLongpeng(Mike) return NULL; 859a059773SLongpeng(Mike) } 869a059773SLongpeng(Mike) 879a059773SLongpeng(Mike) g_free(name); 889a059773SLongpeng(Mike) 8942e7e15fSLongpeng(Mike) /* HMAC needs setkey */ 9042e7e15fSLongpeng(Mike) if (is_hmac) { 91e7b79428SMarc-André Lureau if (setsockopt(afalg->tfmfd, SOL_ALG, ALG_SET_KEY, 9242e7e15fSLongpeng(Mike) key, nkey) != 0) { 9342e7e15fSLongpeng(Mike) error_setg_errno(errp, errno, "Set hmac key failed"); 9442e7e15fSLongpeng(Mike) qcrypto_afalg_comm_free(afalg); 9542e7e15fSLongpeng(Mike) return NULL; 9642e7e15fSLongpeng(Mike) } 9742e7e15fSLongpeng(Mike) } 9842e7e15fSLongpeng(Mike) 999a059773SLongpeng(Mike) return afalg; 1009a059773SLongpeng(Mike) } 1019a059773SLongpeng(Mike) 1028f525028SMarkus Armbruster static QCryptoAFAlgo * 103ef834aa2SMarkus Armbruster qcrypto_afalg_hash_ctx_new(QCryptoHashAlgo alg, 10442e7e15fSLongpeng(Mike) Error **errp) 10542e7e15fSLongpeng(Mike) { 10642e7e15fSLongpeng(Mike) return qcrypto_afalg_hash_hmac_ctx_new(alg, NULL, 0, false, errp); 10742e7e15fSLongpeng(Mike) } 10842e7e15fSLongpeng(Mike) 1098f525028SMarkus Armbruster QCryptoAFAlgo * 110ef834aa2SMarkus Armbruster qcrypto_afalg_hmac_ctx_new(QCryptoHashAlgo alg, 11142e7e15fSLongpeng(Mike) const uint8_t *key, size_t nkey, 11242e7e15fSLongpeng(Mike) Error **errp) 11342e7e15fSLongpeng(Mike) { 11442e7e15fSLongpeng(Mike) return qcrypto_afalg_hash_hmac_ctx_new(alg, key, nkey, true, errp); 11542e7e15fSLongpeng(Mike) } 11642e7e15fSLongpeng(Mike) 11790c3dc60SAlejandro Zeise static 11890c3dc60SAlejandro Zeise QCryptoHash *qcrypto_afalg_hash_new(QCryptoHashAlgo alg, Error **errp) 11990c3dc60SAlejandro Zeise { 12090c3dc60SAlejandro Zeise /* Check if hash algorithm is supported */ 12190c3dc60SAlejandro Zeise char *alg_name = qcrypto_afalg_hash_format_name(alg, false, NULL); 12290c3dc60SAlejandro Zeise QCryptoHash *hash; 12390c3dc60SAlejandro Zeise 12490c3dc60SAlejandro Zeise if (alg_name == NULL) { 12590c3dc60SAlejandro Zeise error_setg(errp, "Unknown hash algorithm %d", alg); 12690c3dc60SAlejandro Zeise return NULL; 12790c3dc60SAlejandro Zeise } 12890c3dc60SAlejandro Zeise 12990c3dc60SAlejandro Zeise g_free(alg_name); 13090c3dc60SAlejandro Zeise 13190c3dc60SAlejandro Zeise hash = g_new(QCryptoHash, 1); 13290c3dc60SAlejandro Zeise hash->alg = alg; 13390c3dc60SAlejandro Zeise hash->opaque = qcrypto_afalg_hash_ctx_new(alg, errp); 13490c3dc60SAlejandro Zeise if (!hash->opaque) { 13590c3dc60SAlejandro Zeise free(hash); 13690c3dc60SAlejandro Zeise return NULL; 13790c3dc60SAlejandro Zeise } 13890c3dc60SAlejandro Zeise 13990c3dc60SAlejandro Zeise return hash; 14090c3dc60SAlejandro Zeise } 14190c3dc60SAlejandro Zeise 14290c3dc60SAlejandro Zeise static 14390c3dc60SAlejandro Zeise void qcrypto_afalg_hash_free(QCryptoHash *hash) 14490c3dc60SAlejandro Zeise { 145*f8395ce8SMarkus Armbruster QCryptoAFAlgo *ctx = hash->opaque; 14690c3dc60SAlejandro Zeise 14790c3dc60SAlejandro Zeise if (ctx) { 14890c3dc60SAlejandro Zeise qcrypto_afalg_comm_free(ctx); 14990c3dc60SAlejandro Zeise } 15090c3dc60SAlejandro Zeise 15190c3dc60SAlejandro Zeise g_free(hash); 15290c3dc60SAlejandro Zeise } 15390c3dc60SAlejandro Zeise 15490c3dc60SAlejandro Zeise /** 15590c3dc60SAlejandro Zeise * Send data to the kernel's crypto core. 15690c3dc60SAlejandro Zeise * 15790c3dc60SAlejandro Zeise * The more_data parameter is used to notify the crypto engine 15890c3dc60SAlejandro Zeise * that this is an "update" operation, and that more data will 15990c3dc60SAlejandro Zeise * be provided to calculate the final hash. 16090c3dc60SAlejandro Zeise */ 16190c3dc60SAlejandro Zeise static 162*f8395ce8SMarkus Armbruster int qcrypto_afalg_send_to_kernel(QCryptoAFAlgo *afalg, 16390c3dc60SAlejandro Zeise const struct iovec *iov, 16490c3dc60SAlejandro Zeise size_t niov, 16590c3dc60SAlejandro Zeise bool more_data, 16690c3dc60SAlejandro Zeise Error **errp) 16790c3dc60SAlejandro Zeise { 16890c3dc60SAlejandro Zeise int ret = 0; 16990c3dc60SAlejandro Zeise int flags = (more_data ? MSG_MORE : 0); 17090c3dc60SAlejandro Zeise 17190c3dc60SAlejandro Zeise /* send data to kernel's crypto core */ 17290c3dc60SAlejandro Zeise ret = iov_send_recv_with_flags(afalg->opfd, flags, iov, niov, 17390c3dc60SAlejandro Zeise 0, iov_size(iov, niov), true); 17490c3dc60SAlejandro Zeise if (ret < 0) { 17590c3dc60SAlejandro Zeise error_setg_errno(errp, errno, "Send data to afalg-core failed"); 17690c3dc60SAlejandro Zeise ret = -1; 17790c3dc60SAlejandro Zeise } else { 17890c3dc60SAlejandro Zeise /* No error, so return 0 */ 17990c3dc60SAlejandro Zeise ret = 0; 18090c3dc60SAlejandro Zeise } 18190c3dc60SAlejandro Zeise 18290c3dc60SAlejandro Zeise return ret; 18390c3dc60SAlejandro Zeise } 18490c3dc60SAlejandro Zeise 18590c3dc60SAlejandro Zeise static 186*f8395ce8SMarkus Armbruster int qcrypto_afalg_recv_from_kernel(QCryptoAFAlgo *afalg, 18790c3dc60SAlejandro Zeise QCryptoHashAlgo alg, 18890c3dc60SAlejandro Zeise uint8_t **result, 18990c3dc60SAlejandro Zeise size_t *result_len, 19090c3dc60SAlejandro Zeise Error **errp) 19190c3dc60SAlejandro Zeise { 19290c3dc60SAlejandro Zeise struct iovec outv; 19390c3dc60SAlejandro Zeise int ret; 19490c3dc60SAlejandro Zeise const int expected_len = qcrypto_hash_digest_len(alg); 19590c3dc60SAlejandro Zeise 19690c3dc60SAlejandro Zeise if (*result_len == 0) { 19790c3dc60SAlejandro Zeise *result_len = expected_len; 19890c3dc60SAlejandro Zeise *result = g_new0(uint8_t, *result_len); 19990c3dc60SAlejandro Zeise } else if (*result_len != expected_len) { 20090c3dc60SAlejandro Zeise error_setg(errp, 20190c3dc60SAlejandro Zeise "Result buffer size %zu is not match hash %d", 20290c3dc60SAlejandro Zeise *result_len, expected_len); 20390c3dc60SAlejandro Zeise return -1; 20490c3dc60SAlejandro Zeise } 20590c3dc60SAlejandro Zeise 20690c3dc60SAlejandro Zeise /* hash && get result */ 20790c3dc60SAlejandro Zeise outv.iov_base = *result; 20890c3dc60SAlejandro Zeise outv.iov_len = *result_len; 20990c3dc60SAlejandro Zeise ret = iov_send_recv(afalg->opfd, &outv, 1, 21090c3dc60SAlejandro Zeise 0, iov_size(&outv, 1), false); 21190c3dc60SAlejandro Zeise if (ret < 0) { 21290c3dc60SAlejandro Zeise error_setg_errno(errp, errno, "Recv result from afalg-core failed"); 21390c3dc60SAlejandro Zeise return -1; 21490c3dc60SAlejandro Zeise } 21590c3dc60SAlejandro Zeise 21690c3dc60SAlejandro Zeise return 0; 21790c3dc60SAlejandro Zeise } 21890c3dc60SAlejandro Zeise 21990c3dc60SAlejandro Zeise static 22090c3dc60SAlejandro Zeise int qcrypto_afalg_hash_update(QCryptoHash *hash, 22190c3dc60SAlejandro Zeise const struct iovec *iov, 22290c3dc60SAlejandro Zeise size_t niov, 22390c3dc60SAlejandro Zeise Error **errp) 22490c3dc60SAlejandro Zeise { 225*f8395ce8SMarkus Armbruster return qcrypto_afalg_send_to_kernel((QCryptoAFAlgo *) hash->opaque, 22690c3dc60SAlejandro Zeise iov, niov, true, errp); 22790c3dc60SAlejandro Zeise } 22890c3dc60SAlejandro Zeise 22990c3dc60SAlejandro Zeise static 23090c3dc60SAlejandro Zeise int qcrypto_afalg_hash_finalize(QCryptoHash *hash, 23190c3dc60SAlejandro Zeise uint8_t **result, 23290c3dc60SAlejandro Zeise size_t *result_len, 23390c3dc60SAlejandro Zeise Error **errp) 23490c3dc60SAlejandro Zeise { 235*f8395ce8SMarkus Armbruster return qcrypto_afalg_recv_from_kernel((QCryptoAFAlgo *) hash->opaque, 23690c3dc60SAlejandro Zeise hash->alg, result, result_len, errp); 23790c3dc60SAlejandro Zeise } 23890c3dc60SAlejandro Zeise 2399a059773SLongpeng(Mike) static int 2408f525028SMarkus Armbruster qcrypto_afalg_hash_hmac_bytesv(QCryptoAFAlgo *hmac, 241ef834aa2SMarkus Armbruster QCryptoHashAlgo alg, 2429a059773SLongpeng(Mike) const struct iovec *iov, 2439a059773SLongpeng(Mike) size_t niov, uint8_t **result, 2449a059773SLongpeng(Mike) size_t *resultlen, 2459a059773SLongpeng(Mike) Error **errp) 2469a059773SLongpeng(Mike) { 2479a059773SLongpeng(Mike) int ret = 0; 2489a059773SLongpeng(Mike) 2498a70903bSAlejandro Zeise ret = qcrypto_afalg_send_to_kernel(hmac, iov, niov, false, errp); 2508a70903bSAlejandro Zeise if (ret == 0) { 2518a70903bSAlejandro Zeise ret = qcrypto_afalg_recv_from_kernel(hmac, alg, result, 25242e7e15fSLongpeng(Mike) resultlen, errp); 25342e7e15fSLongpeng(Mike) } 25442e7e15fSLongpeng(Mike) 2558a70903bSAlejandro Zeise return ret; 2568a70903bSAlejandro Zeise } 2578a70903bSAlejandro Zeise 25842e7e15fSLongpeng(Mike) static int 25942e7e15fSLongpeng(Mike) qcrypto_afalg_hmac_bytesv(QCryptoHmac *hmac, 26042e7e15fSLongpeng(Mike) const struct iovec *iov, 26142e7e15fSLongpeng(Mike) size_t niov, uint8_t **result, 26242e7e15fSLongpeng(Mike) size_t *resultlen, 26342e7e15fSLongpeng(Mike) Error **errp) 26442e7e15fSLongpeng(Mike) { 26542e7e15fSLongpeng(Mike) return qcrypto_afalg_hash_hmac_bytesv(hmac->opaque, hmac->alg, 26642e7e15fSLongpeng(Mike) iov, niov, result, resultlen, 26742e7e15fSLongpeng(Mike) errp); 26842e7e15fSLongpeng(Mike) } 26942e7e15fSLongpeng(Mike) 27042e7e15fSLongpeng(Mike) static void qcrypto_afalg_hmac_ctx_free(QCryptoHmac *hmac) 27142e7e15fSLongpeng(Mike) { 2728f525028SMarkus Armbruster QCryptoAFAlgo *afalg; 27342e7e15fSLongpeng(Mike) 27442e7e15fSLongpeng(Mike) afalg = hmac->opaque; 27542e7e15fSLongpeng(Mike) qcrypto_afalg_comm_free(afalg); 27642e7e15fSLongpeng(Mike) } 27742e7e15fSLongpeng(Mike) 2789a059773SLongpeng(Mike) QCryptoHashDriver qcrypto_hash_afalg_driver = { 27990c3dc60SAlejandro Zeise .hash_new = qcrypto_afalg_hash_new, 28090c3dc60SAlejandro Zeise .hash_free = qcrypto_afalg_hash_free, 28190c3dc60SAlejandro Zeise .hash_update = qcrypto_afalg_hash_update, 28290c3dc60SAlejandro Zeise .hash_finalize = qcrypto_afalg_hash_finalize 2839a059773SLongpeng(Mike) }; 28442e7e15fSLongpeng(Mike) 28542e7e15fSLongpeng(Mike) QCryptoHmacDriver qcrypto_hmac_afalg_driver = { 28642e7e15fSLongpeng(Mike) .hmac_bytesv = qcrypto_afalg_hmac_bytesv, 28742e7e15fSLongpeng(Mike) .hmac_free = qcrypto_afalg_hmac_ctx_free, 28842e7e15fSLongpeng(Mike) }; 289