summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@kernel.org>2026-03-02 10:59:45 +0300
committerKeith Busch <kbusch@kernel.org>2026-03-27 17:35:01 +0300
commit4263ca1cae5cebc09ba95375c4a8927bf4b39d49 (patch)
treef1f118f61556c4a21329fae5fce7d608431ab559
parent4454820b4ee59154d0c271722bbe48bb4f554e3e (diff)
downloadlinux-4263ca1cae5cebc09ba95375c4a8927bf4b39d49.tar.xz
nvme-auth: common: add HMAC helper functions
Add some helper functions for computing HMAC-SHA256, HMAC-SHA384, or HMAC-SHA512 values using the crypto library instead of crypto_shash. These will enable some significant simplifications and performance improvements in nvme-auth. Acked-by: Ard Biesheuvel <ardb@kernel.org> Acked-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Eric Biggers <ebiggers@kernel.org> Signed-off-by: Keith Busch <kbusch@kernel.org>
-rw-r--r--drivers/nvme/common/Kconfig2
-rw-r--r--drivers/nvme/common/auth.c66
-rw-r--r--include/linux/nvme-auth.h14
3 files changed, 82 insertions, 0 deletions
diff --git a/drivers/nvme/common/Kconfig b/drivers/nvme/common/Kconfig
index d19988c13af5..1ec507d1f9b5 100644
--- a/drivers/nvme/common/Kconfig
+++ b/drivers/nvme/common/Kconfig
@@ -13,6 +13,8 @@ config NVME_AUTH
select CRYPTO_DH
select CRYPTO_DH_RFC7919_GROUPS
select CRYPTO_HKDF
+ select CRYPTO_LIB_SHA256
+ select CRYPTO_LIB_SHA512
config NVME_AUTH_KUNIT_TEST
tristate "KUnit tests for NVMe authentication" if !KUNIT_ALL_TESTS
diff --git a/drivers/nvme/common/auth.c b/drivers/nvme/common/auth.c
index 9e33fc02cf51..00f21176181f 100644
--- a/drivers/nvme/common/auth.c
+++ b/drivers/nvme/common/auth.c
@@ -12,6 +12,7 @@
#include <crypto/hash.h>
#include <crypto/dh.h>
#include <crypto/hkdf.h>
+#include <crypto/sha2.h>
#include <linux/nvme.h>
#include <linux/nvme-auth.h>
@@ -234,6 +235,71 @@ void nvme_auth_free_key(struct nvme_dhchap_key *key)
}
EXPORT_SYMBOL_GPL(nvme_auth_free_key);
+/*
+ * Start computing an HMAC value, given the algorithm ID and raw key.
+ *
+ * The context should be zeroized at the end of its lifetime. The caller can do
+ * that implicitly by calling nvme_auth_hmac_final(), or explicitly (needed when
+ * a context is abandoned without finalizing it) by calling memzero_explicit().
+ */
+int nvme_auth_hmac_init(struct nvme_auth_hmac_ctx *hmac, u8 hmac_id,
+ const u8 *key, size_t key_len)
+{
+ hmac->hmac_id = hmac_id;
+ switch (hmac_id) {
+ case NVME_AUTH_HASH_SHA256:
+ hmac_sha256_init_usingrawkey(&hmac->sha256, key, key_len);
+ return 0;
+ case NVME_AUTH_HASH_SHA384:
+ hmac_sha384_init_usingrawkey(&hmac->sha384, key, key_len);
+ return 0;
+ case NVME_AUTH_HASH_SHA512:
+ hmac_sha512_init_usingrawkey(&hmac->sha512, key, key_len);
+ return 0;
+ }
+ pr_warn("%s: invalid hash algorithm %d\n", __func__, hmac_id);
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(nvme_auth_hmac_init);
+
+void nvme_auth_hmac_update(struct nvme_auth_hmac_ctx *hmac, const u8 *data,
+ size_t data_len)
+{
+ switch (hmac->hmac_id) {
+ case NVME_AUTH_HASH_SHA256:
+ hmac_sha256_update(&hmac->sha256, data, data_len);
+ return;
+ case NVME_AUTH_HASH_SHA384:
+ hmac_sha384_update(&hmac->sha384, data, data_len);
+ return;
+ case NVME_AUTH_HASH_SHA512:
+ hmac_sha512_update(&hmac->sha512, data, data_len);
+ return;
+ }
+ /* Unreachable because nvme_auth_hmac_init() validated hmac_id */
+ WARN_ON_ONCE(1);
+}
+EXPORT_SYMBOL_GPL(nvme_auth_hmac_update);
+
+/* Finish computing an HMAC value. Note that this zeroizes the HMAC context. */
+void nvme_auth_hmac_final(struct nvme_auth_hmac_ctx *hmac, u8 *out)
+{
+ switch (hmac->hmac_id) {
+ case NVME_AUTH_HASH_SHA256:
+ hmac_sha256_final(&hmac->sha256, out);
+ return;
+ case NVME_AUTH_HASH_SHA384:
+ hmac_sha384_final(&hmac->sha384, out);
+ return;
+ case NVME_AUTH_HASH_SHA512:
+ hmac_sha512_final(&hmac->sha512, out);
+ return;
+ }
+ /* Unreachable because nvme_auth_hmac_init() validated hmac_id */
+ WARN_ON_ONCE(1);
+}
+EXPORT_SYMBOL_GPL(nvme_auth_hmac_final);
+
struct nvme_dhchap_key *nvme_auth_transform_key(
const struct nvme_dhchap_key *key, const char *nqn)
{
diff --git a/include/linux/nvme-auth.h b/include/linux/nvme-auth.h
index 02ca9a716256..940d0703eb1d 100644
--- a/include/linux/nvme-auth.h
+++ b/include/linux/nvme-auth.h
@@ -7,6 +7,7 @@
#define _NVME_AUTH_H
#include <crypto/kpp.h>
+#include <crypto/sha2.h>
struct nvme_dhchap_key {
size_t len;
@@ -23,6 +24,19 @@ const char *nvme_auth_hmac_name(u8 hmac_id);
const char *nvme_auth_digest_name(u8 hmac_id);
size_t nvme_auth_hmac_hash_len(u8 hmac_id);
u8 nvme_auth_hmac_id(const char *hmac_name);
+struct nvme_auth_hmac_ctx {
+ u8 hmac_id;
+ union {
+ struct hmac_sha256_ctx sha256;
+ struct hmac_sha384_ctx sha384;
+ struct hmac_sha512_ctx sha512;
+ };
+};
+int nvme_auth_hmac_init(struct nvme_auth_hmac_ctx *hmac, u8 hmac_id,
+ const u8 *key, size_t key_len);
+void nvme_auth_hmac_update(struct nvme_auth_hmac_ctx *hmac, const u8 *data,
+ size_t data_len);
+void nvme_auth_hmac_final(struct nvme_auth_hmac_ctx *hmac, u8 *out);
u32 nvme_auth_key_struct_size(u32 key_len);
struct nvme_dhchap_key *nvme_auth_extract_key(const char *secret, u8 key_hash);