Subject: [RFC PATCH 1/7] crypto: xctr - Add XCTR support

From: Nathan Huckleberry <[email-masked]>
Date: Mon, 24 Jan 2022 19:44:16 -0600

Add a generic implementation of XCTR mode as a template.  XCTR is a
blockcipher mode similar to CTR mode.  XCTR uses XORs and little-endian
addition rather than big-endian arithmetic which makes it slightly
faster on little-endian CPUs.  It is used as a component to implement
HCTR2.

More information on XCTR mode can be found in the HCTR2 paper:
https://eprint.iacr.org/2021/1441.pdf

Signed-off-by: Nathan Huckleberry <[email-masked]>
---
 crypto/Kconfig        |   9 +
 crypto/Makefile       |   1 +
 crypto/tcrypt.c       |   1 +
 crypto/testmgr.c      |   6 +
 crypto/testmgr.h      | 546 ++++++++++++++++++++++++++++++++++++++++++
 crypto/xctr.c         | 202 ++++++++++++++++
 include/crypto/xctr.h |  19 ++
 7 files changed, 784 insertions(+)
 create mode 100644 crypto/xctr.c
 create mode 100644 include/crypto/xctr.h

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 94bfa32cc6a1..b00de5f22eaf 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -452,6 +452,15 @@ config CRYPTO_PCBC
 	  PCBC: Propagating Cipher Block Chaining mode
 	  This block cipher algorithm is required for RxRPC.
 
+config CRYPTO_XCTR
+	tristate
+	select CRYPTO_SKCIPHER
+	select CRYPTO_MANAGER
+	help
+	  XCTR: XOR Counter mode. This blockcipher mode is a variant of CTR mode
+	  using XORs and little-endian addition rather than big-endian arithmetic.
+	  XCTR mode is used to implement HCTR2.
+
 config CRYPTO_XTS
 	tristate "XTS support"
 	select CRYPTO_SKCIPHER
diff --git a/crypto/Makefile b/crypto/Makefile
index d76bff8d0ffd..6b3fe3df1489 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -93,6 +93,7 @@ obj-$(CONFIG_CRYPTO_CTS) += cts.o
 obj-$(CONFIG_CRYPTO_LRW) += lrw.o
 obj-$(CONFIG_CRYPTO_XTS) += xts.o
 obj-$(CONFIG_CRYPTO_CTR) += ctr.o
+obj-$(CONFIG_CRYPTO_XCTR) += xctr.o
 obj-$(CONFIG_CRYPTO_KEYWRAP) += keywrap.o
 obj-$(CONFIG_CRYPTO_ADIANTUM) += adiantum.o
 obj-$(CONFIG_CRYPTO_NHPOLY1305) += nhpoly1305.o
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index 00149657a4bc..da7848f84d12 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -1750,6 +1750,7 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
 		ret += tcrypt_test("rfc3686(ctr(aes))");
 		ret += tcrypt_test("ofb(aes)");
 		ret += tcrypt_test("cfb(aes)");
+		ret += tcrypt_test("xctr(aes)");
 		break;
 
 	case 11:
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 5831d4bbc64f..5acf92354543 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -5454,6 +5454,12 @@ static const struct alg_test_desc alg_test_descs[] = {
 		.suite = {
 			.cipher = __VECS(xchacha20_tv_template)
 		},
+	}, {
+		.alg = "xctr(aes)",
+		.test = alg_test_skcipher,
+		.suite = {
+			.cipher = __VECS(aes_xctr_tv_template)
+		}
 	}, {
 		.alg = "xts(aes)",
 		.generic_driver = "xts(ecb(aes-generic))",
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index a253d66ba1c1..e1ebbb3c4d4c 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -32800,4 +32800,550 @@ static const struct hash_testvec blakes2s_256_tv_template[] = {{
 			  0xd5, 0x06, 0xb5, 0x3a, 0x7c, 0x7a, 0x65, 0x1d, },
 }};
 
+/*
+ * Test vectors generated using https://github.com/google/hctr2
+ */
+static const struct cipher_testvec aes_xctr_tv_template[] = {
+	{
+		.key	= "\x06\x20\x5d\xba\x50\xb5\x12\x8e"
+			  "\xee\x65\x3c\x59\x80\xa1\xfe\xb1",
+		.iv	= "\x16\x52\x22\x0d\x1c\x76\x94\x9f"
+			  "\x74\xba\x41\x0c\xc4\xc4\xaf\xb9",
+		.ptext	= "\x02\x62\x54\x87\x28\x8f\xa1\xd3"
+			  "\x8f\xd8\xc6\xab\x08\xef\xea\x83"
+			  "\xa3\xbd\xf4\x85\x47\x66\x74\x11"
+			  "\xf1\x58\x9f\x9f\xe8\xb9\x95\xc9",
+		.ctext	= "\x11\xfe\xef\xb4\x9e\xed\x5b\xe5"
+			  "\x92\x9b\x03\xa7\x6d\x8e\xf9\x7a"
+			  "\xaa\xfa\x33\x4a\xf7\xd9\xb2\xeb"
+			  "\x73\xa1\x85\xbc\x45\xbc\x42\x70",
+		.klen	= 16,
+		.len	= 32,
+	},
+	{
+		.key	= "\x19\x0e\xea\x30\x59\x8e\x39\x35"
+			  "\x93\x63\xcc\x8b\x5f\x98\x4f\x43",
+		.iv	= "\x4b\x9f\xf4\xd8\xaa\xcf\x99\xdc"
+			  "\xc5\x07\xe0\xde\xb2\x6d\x85\x12",
+		.ptext	= "\x23\x2d\x48\x15\x89\x34\x54\xf9"
+			  "\x2b\x38\xd1\x62\x06\x98\x21\x59"
+			  "\xd4\x3a\x45\x6f\x12\x27\x08\xa9"
+			  "\x3e\x0f\x21\x3d\xda\x80\x92\x3f",
+		.ctext	= "\x01\xa7\xe5\x9e\xf8\x49\xbb\x36"
+			  "\x49\xb8\x59\x7a\x77\x3f\x5a\x10"
+			  "\x2e\x8f\xe7\xc9\xc4\xb8\xdb\x86"
+			  "\xe4\xc0\x6b\x60\x2f\x79\xa0\x91",
+		.klen	= 16,
+		.len	= 32,
+	},
+	{
+		.key	= "\x17\xa6\x01\x3d\x5d\xd6\xef\x2d"
+			  "\x69\x8f\x4c\x54\x5b\xae\x43\xf0",
+		.iv	= "\xa9\x1b\x47\x60\x26\x82\xf7\x1c"
+			  "\x80\xf8\x88\xdd\xfb\x44\xd9\xda",
+		.ptext	= "\xf7\x67\xcd\xa6\x04\x65\x53\x99"
+			  "\x90\x5c\xa2\x56\x74\xd7\x9d\xf2"
+			  "\x0b\x03\x7f\x4e\xa7\x84\x72\x2b"
+			  "\xf0\xa5\xbf\xe6\x9a\x62\x3a\xfe"
+			  "\x69\x5c\x93\x79\x23\x86\x64\x85"
+			  "\xeb\x13\xb1\x5a\xd5\x48\x39\xa0"
+			  "\x70\xfb\x06\x9a\xd7\x12\x5a\xb9"
+			  "\xbe\xed\x2c\x81\x64\xf7\xcf\x80"
+			  "\xee\xe6\x28\x32\x2d\x37\x4c\x32"
+			  "\xf4\x1f\x23\x21\xe9\xc8\xc9\xbf"
+			  "\x54\xbc\xcf\xb4\xc2\x65\x39\xdf"
+			  "\xa5\xfb\x14\x11\xed\x62\x38\xcf"
+			  "\x9b\x58\x11\xdd\xe9\xbd\x37\x57"
+			  "\x75\x4c\x9e\xd5\x67\x0a\x48\xc6"
+			  "\x0d\x05\x4e\xb1\x06\xd7\xec\x2e"
+			  "\x9e\x59\xde\x4f\xab\x38\xbb\xe5"
+			  "\x87\x04\x5a\x2c\x2a\xa2\x8f\x3c"
+			  "\xe7\xe1\x46\xa9\x49\x9f\x24\xad"
+			  "\x2d\xb0\x55\x40\x64\xd5\xda\x7e"
+			  "\x1e\x77\xb8\x29\x72\x73\xc3\x84"
+			  "\xcd\xf3\x94\x90\x58\x76\xc9\x2c"
+			  "\x2a\xad\x56\xde\x33\x18\xb6\x3b"
+			  "\x10\xe9\xe9\x8d\xf0\xa9\x7f\x05"
+			  "\xf7\xb5\x8c\x13\x7e\x11\x3d\x1e"
+			  "\x02\xbb\x5b\xea\x69\xff\x85\xcf"
+			  "\x6a\x18\x97\x45\xe3\x96\xba\x4d"
+			  "\x2d\x7a\x70\x78\x15\x2c\xe9\xdc"
+			  "\x4e\x09\x92\x57\x04\xd8\x0b\xa6"
+			  "\x20\x71\x76\x47\x76\x96\x89\xa0"
+			  "\xd9\x29\xa2\x5a\x06\xdb\x56\x39"
+			  "\x60\x33\x59\x04\x95\x89\xf6\x18"
+			  "\x1d\x70\x75\x85\x3a\xb7\x6e",
+		.ctext	= "\xe1\xe7\x3f\xd3\x6a\xb9\x2f\x64"
+			  "\x37\xc5\xa4\xe9\xca\x0a\xa1\xd6"
+			  "\xea\x7d\x39\xe5\xe6\xcc\x80\x54"
+			  "\x74\x31\x2a\x04\x33\x79\x8c\x8e"
+			  "\x4d\x47\x84\x28\x27\x9b\x3c\x58"
+			  "\x54\x58\x20\x4f\x70\x01\x52\x5b"
+			  "\xac\x95\x61\x49\x5f\xef\xba\xce"
+			  "\xd7\x74\x56\xe7\xbb\xe0\x3c\xd0"
+			  "\x7f\xa9\x23\x57\x33\x2a\xf6\xcb"
+			  "\xbe\x42\x14\x95\xa8\xf9\x7a\x7e"
+			  "\x12\x53\x3a\xe2\x13\xfe\x2d\x89"
+			  "\xeb\xac\xd7\xa8\xa5\xf8\x27\xf3"
+			  "\x74\x9a\x65\x63\xd1\x98\x3a\x7e"
+			  "\x27\x7b\xc0\x20\x00\x4d\xf4\xe5"
+			  "\x7b\x69\xa6\xa8\x06\x50\x85\xb6"
+			  "\x7f\xac\x7f\xda\x1f\xf5\x37\x56"
+			  "\x9b\x2f\xd3\x86\x6b\x70\xbd\x0e"
+			  "\x55\x9a\x9d\x4b\x08\xb5\x5b\x7b"
+			  "\xd4\x7c\xb4\x71\x49\x92\x4a\x1e"
+			  "\xed\x6d\x11\x09\x47\x72\x32\x6a"
+			  "\x97\x53\x36\xaf\xf3\x06\x06\x2c"
+			  "\x69\xf1\x59\x00\x36\x95\x28\x2a"
+			  "\xb6\xcd\x10\x21\x84\x73\x5c\x96"
+			  "\x86\x14\x2c\x3d\x02\xdb\x53\x9a"
+			  "\x61\xde\xea\x99\x84\x7a\x27\xf6"
+			  "\xf7\xc8\x49\x73\x4b\xb8\xeb\xd3"
+			  "\x41\x33\xdd\x09\x68\xe2\x64\xb8"
+			  "\x5f\x75\x74\x97\x91\x54\xda\xc2"
+			  "\x73\x2c\x1e\x5a\x84\x48\x01\x1a"
+			  "\x0d\x8b\x0a\xdf\x07\x2e\xee\x77"
+			  "\x1d\x17\x41\x7a\xc9\x33\x63\xfa"
+			  "\x9f\xc3\x74\x57\x5f\x03\x4c",
+		.klen	= 16,
+		.len	= 255,
+	},
+	{
+		.key	= "\xd1\x87\xd3\xa1\x97\x6a\x4b\xf9"
+			  "\x5d\xcb\x6c\x07\x6e\x2d\x48\xad",
+		.iv	= "\xe9\x8c\x88\x40\xa9\x52\xe0\xbc"
+			  "\x8a\x47\x3a\x09\x5d\x60\xdd\xb2",
+		.ptext	= "\x67\x80\x86\x46\x18\xc6\xed\xd2"
+			  "\x99\x0f\x7a\xc3\xa5\x0b\x80\xcb"
+			  "\x8d\xe4\x0b\x4c\x1e\x4c\x98\x46"
+			  "\x87\x8a\x8c\x76\x75\xce\x2c\x27"
+			  "\x74\x88\xdc\x37\xaa\x77\x53\x14"
+			  "\xd3\x01\xcf\xb5\xcb\xdd\xb4\x8e"
+			  "\x6b\x54\x68\x01\xc3\xdf\xbc\xdd"
+			  "\x1a\x08\x4c\x11\xab\x25\x4b\x69"
+			  "\x25\x21\x78\xb1\x91\x1b\x75\xfa"
+			  "\xd0\x10\xf3\x8a\x65\xd3\x8d\x2e"
+			  "\xf8\xb6\xce\x29\xf9\x1e\x45\x5f"
+			  "\x4e\x41\x63\x6f\xf9\xca\x59\xd7"
+			  "\xc8\x9c\x97\xda\xff\xab\x42\x47"
+			  "\xfb\x2b\xca\xed\xda\x6c\x96\xe4"
+			  "\x59\x0d\xc6\x4a\x26\xde\xa8\x50"
+			  "\xc5\xbb\x13\xf8\xd1\xb9\x6b\xf4"
+			  "\x19\x30\xfb\xc0\x4f\x6b\x96\xc4"
+			  "\x88\x0b\x57\xb3\x43\xbd\xdd\xe2"
+			  "\x06\xae\x88\x44\x41\xdf\xa4\x29"
+			  "\x31\xd3\x38\xeb\xe9\xf8\xa2\xe4"
+			  "\x6a\x55\x2f\x56\x58\x19\xeb\xf7"
+			  "\x5f\x4b\x15\x52\xe4\xaa\xdc\x31"
+			  "\x4a\x32\xc9\x31\x96\x68\x3b\x80"
+			  "\x20\x4f\xe5\x8f\x87\xc9\x37\x58"
+			  "\x79\xfd\xc9\xc1\x9a\x83\xe3\x8b"
+			  "\x6b\x57\x07\xef\x28\x8d\x55\xcb"
+			  "\x4e\xb6\xa2\xb6\xd3\x4f\x8b\x10"
+			  "\x70\x10\x02\xf6\x74\x71\x20\x5a"
+			  "\xe2\x2f\xb6\x46\xc5\x22\xa3\x29"
+			  "\xf5\xc1\x25\xb0\x4d\xda\xaf\x04"
+			  "\xca\x83\xe6\x3f\x66\x6e\x3b\xa4"
+			  "\x09\x40\x22\xd7\x97\x12\x1e",
+		.ctext	= "\xd4\x6d\xfa\xc8\x6e\x54\x31\x69"
+			  "\x47\x51\x0f\xb8\xfa\x03\xa2\xe1"
+			  "\x57\xa8\x4f\x2d\xc5\x4e\x8d\xcd"
+			  "\x92\x0f\x71\x08\xdd\xa4\x5b\xc7"
+			  "\x69\x3a\x3d\x93\x29\x1d\x87\x2c"
+			  "\xfa\x96\xd2\x4d\x72\x61\xb0\x9e"
+			  "\xa7\xf5\xd5\x09\x3d\x43\x32\x82"
+			  "\xd2\x9a\x58\xe3\x4c\x84\xc2\xad"
+			  "\x33\x77\x9c\x5d\x37\xc1\x4f\x95"
+			  "\x56\x55\xc6\x76\x62\x27\x6a\xc7"
+			  "\x45\x80\x9e\x7c\x48\xc8\x14\xbb"
+			  "\x32\xbf\x4a\xbb\x8d\xb4\x2c\x7c"
+			  "\x01\xfa\xc8\xde\x10\x55\xa0\xae"
+			  "\x29\xed\xe2\x3d\xd6\x26\xfa\x3c"
+			  "\x7a\x81\xae\xfd\xc3\x2f\xe5\x3a"
+			  "\x00\xa3\xf0\x66\x0f\x3a\xd2\xa3"
+			  "\xaf\x0e\x75\xbb\x79\xad\xcc\xe0"
+			  "\x98\x10\xfb\xf1\xc0\x0c\xb9\x03"
+			  "\x07\xee\x46\x6a\xc0\xf6\x17\x8f"
+			  "\x7f\xc9\xad\x16\x58\x54\xb0\xd5"
+			  "\x67\x73\x9f\xce\xea\x4b\x60\x57"
+			  "\x1d\x62\x72\xec\xab\xe3\xd8\x32"
+			  "\x29\x48\x37\x1b\x5c\xd6\xd0\xb7"
+			  "\xc3\x39\xef\xf6\x1b\x18\xf6\xd1"
+			  "\x2d\x76\x7c\x68\x50\x37\xfa\x8f"
+			  "\x16\x87\x5e\xf8\xb1\x79\x82\x52"
+			  "\xc7\x3e\x0e\xa3\x61\xb9\x00\xe0"
+			  "\x2e\x03\x80\x6e\xc0\xbf\x63\x78"
+			  "\xdf\xab\xc2\x3b\xf0\x4c\xb0\xcb"
+			  "\x91\x6a\x26\xe6\x3a\x86\xef\x1a"
+			  "\x4e\x4d\x23\x2d\x59\x3a\x02\x3a"
+			  "\xf3\xda\xd1\x9d\x68\xf6\xef",
+		.klen	= 16,
+		.len	= 255,
+	},
+	{
+		.key	= "\x17\xe6\xb1\x85\x40\x24\xbe\x80"
+			  "\x99\xc7\xa1\x0c\x0f\x72\x31\xb8"
+			  "\x10\xb5\x11\x21\x3a\x99\x9e\xc8",
+		.iv	= "\x6b\x5f\xe1\x6a\xe1\x21\xfc\x62"
+			  "\xd9\x85\x2e\x0b\xbd\x58\x79\xd1",
+		.ptext	= "\xea\x3c\xad\x9d\x92\x05\x50\xa4"
+			  "\x68\x56\x6b\x33\x95\xa8\x24\x6c"
+			  "\xa0\x9d\x91\x15\x3a\x26\xb7\xeb"
+			  "\xb4\x5d\xf7\x0c\xec\x91\xbe\x11",
+		.ctext	= "\x6a\xac\xfc\x24\x64\x98\x28\x33"
+			  "\xa4\x39\xfd\x72\x46\x56\x7e\xf7"
+			  "\xd0\x7f\xee\x95\xd8\x68\x44\x67"
+			  "\x70\x80\xd4\x69\x7a\xf5\x8d\xad",
+		.klen	= 24,
+		.len	= 32,
+	},
+	{
+		.key	= "\x02\x81\x0e\xb1\x97\xe0\x20\x0c"
+			  "\x46\x8c\x7b\xde\xac\xe6\xe0\xb5"
+			  "\x2e\xb3\xc0\x40\x0e\xb7\x3d\xd3",
+		.iv	= "\x37\x15\x1c\x61\xab\x95\x8f\xf3"
+			  "\x11\x3a\x79\xe2\xf7\x33\x96\xb3",
+		.ptext	= "\x05\xd9\x7a\xc7\x08\x79\xba\xd8"
+			  "\x4a\x63\x54\xf7\x4e\x0c\x98\x8a"
+			  "\x5d\x40\x05\xe4\x7a\x7a\x14\x0c"
+			  "\xa8\xa7\x53\xf4\x3e\x66\x81\x38",
+		.ctext	= "\x43\x66\x70\x51\xd9\x7c\x6f\x80"
+			  "\x82\x8e\x34\xda\x5d\x3c\x47\xd1"
+			  "\xe0\x67\x76\xb5\x78\x98\x47\x26"
+			  "\x41\x31\xfa\x97\xc9\x79\xeb\x15",
+		.klen	= 24,
+		.len	= 32,
+	},
+	{
+		.key	= "\x9a\xef\x58\x01\x4c\x1e\xa2\x33"
+			  "\xce\x1f\x32\xae\xc8\x69\x1f\xf5"
+			  "\x82\x1b\x74\xf4\x8b\x1b\xce\x30",
+		.iv	= "\xb1\x72\x52\xa8\xc4\x8f\xb5\xec"
+			  "\x95\x12\x14\x5f\xd2\x29\x14\x0f",
+		.ptext	= "\x8a\xbc\x20\xbd\x67\x76\x8d\xd8"
+			  "\xa6\x70\xf0\x74\x8c\x8d\x9c\x00"
+			  "\xdd\xaf\xef\x28\x5d\x8d\xfa\x87"
+			  "\x81\x39\x8c\xb1\x6e\x0a\xcf\x3c"
+			  "\xe8\x3b\xc0\xff\x6e\xe7\xd1\xc6"
+			  "\x70\xb8\xdf\x27\x62\x72\x8e\xb7"
+			  "\x6b\xa7\xb2\x74\xdd\xc6\xb4\xc9"
+			  "\x4c\xd8\x4f\x2c\x09\x75\x6e\xb7"
+			  "\x41\xb3\x8f\x96\x09\x0d\x40\x8e"
+			  "\x0f\x49\xc2\xad\xc4\xf7\x71\x0a"
+			  "\x76\xfb\x45\x97\x29\x7a\xaa\x98"
+			  "\x22\x55\x4f\x9c\x26\x01\xc8\xb9"
+			  "\x41\x42\x51\x9d\x00\x5c\x7f\x02"
+			  "\x9b\x00\xaa\xbd\x69\x47\x9c\x26"
+			  "\x5b\xcb\x08\xf3\x46\x33\xf9\xeb"
+			  "\x79\xdd\xfe\x38\x08\x84\x8c\x81"
+			  "\xb8\x51\xbd\xcd\x72\x00\xdb\xbd"
+			  "\xf5\xd6\xb4\x80\xf7\xd3\x49\xac"
+			  "\x9e\xf9\xea\xd5\xad\xd4\xaa\x8f"
+			  "\x97\x60\xce\x60\xa7\xdd\xc0\xb2"
+			  "\x51\x80\x9b\xae\xab\x0d\x62\xab"
+			  "\x78\x1a\xeb\x8c\x03\x6f\x30\xbf"
+			  "\xe0\xe1\x20\x65\x74\x65\x54\x43"
+			  "\x92\x57\xd2\x73\x8a\xeb\x99\x38"
+			  "\xca\x78\xc8\x11\xd7\x92\x1a\x05"
+			  "\x55\xb8\xfa\xa0\x82\xb7\xd6\x16"
+			  "\x84\x4d\x25\xc4\xd5\xe4\x55\xf3"
+			  "\x6c\xb3\xe4\x6e\x66\x31\x5c\x41"
+			  "\x98\x46\x28\xd8\x71\x05\xf2\x3b"
+			  "\xd1\x3e\x0f\x79\x7f\xf3\x30\x3f"
+			  "\xbe\x36\xf4\x50\xbd\x0c\x89\xd5"
+			  "\xcb\x53\x9f\xeb\x56\xf4\x3f",
+		.ctext	= "\xee\x90\xe1\x45\xf5\xab\x04\x23"
+			  "\x70\x0a\x54\x49\xac\x34\xb8\x69"
+			  "\x3f\xa8\xce\xef\x6e\x63\xc1\x20"
+			  "\x7a\x41\x43\x5d\xa2\x29\x71\x1d"
+			  "\xd2\xbb\xb1\xca\xb4\x3a\x5a\xf3"
+			  "\x0a\x68\x0b\x9d\x6f\x68\x60\x9e"
+			  "\x9d\xb9\x23\x68\xbb\xdd\x12\x31"
+			  "\xc6\xd6\xf9\xb3\x80\xe8\xb5\xab"
+			  "\x84\x2a\x8e\x7b\xb2\x4f\xee\x31"
+			  "\x83\xc4\x1c\x80\x89\xe4\xe7\xd2"
+			  "\x00\x65\x98\xd1\x57\xcc\xf6\x87"
+			  "\x14\xf1\x23\x22\x78\x61\xc7\xb6"
+			  "\xf5\x90\x97\xdd\xcd\x90\x98\xd8"
+			  "\xbb\x02\xfa\x2c\xf0\x89\xfc\x7e"
+			  "\xe7\xcd\xee\x41\x3f\x73\x4a\x08"
+			  "\xf8\x8f\xf3\xbf\x3a\xd5\xce\xb7"
+			  "\x7a\xf4\x49\xcd\x3f\xc7\x1f\x77"
+			  "\x98\xd0\x9d\x82\x20\x8a\x04\x5d"
+			  "\x9f\x77\xcb\xf4\x38\x92\x47\xce"
+			  "\x6d\xc3\x51\xc1\xd9\xf4\x2f\x65"
+			  "\x67\x01\xf4\x46\x3b\xd2\x90\x5d"
+			  "\x2a\xcb\xc5\x39\x1c\x72\xa5\xba"
+			  "\xaf\x80\x9b\x87\x01\x85\xa1\x02"
+			  "\xdf\x79\x4c\x27\x77\x3e\xfc\xb3"
+			  "\x96\xbc\x42\xad\xdf\xa4\x16\x1e"
+			  "\x77\xe7\x39\xcc\x78\x2c\xc1\x00"
+			  "\xe5\xa6\xb5\x9b\x0c\x12\x19\xc5"
+			  "\x8b\xbe\xae\x4b\xc3\xa3\x91\x8f"
+			  "\x5b\x82\x0f\x20\x30\x35\x45\x26"
+			  "\x29\x84\x2e\xc8\x2d\xce\xae\xac"
+			  "\xbe\x93\x50\x7a\x6a\x01\x08\x38"
+			  "\xf5\x49\x4d\x8b\x7e\x96\x70",
+		.klen	= 24,
+		.len	= 255,
+	},
+	{
+		.key	= "\x2c\x3c\x6c\x78\xaa\x83\xed\x14"
+			  "\x4e\xe5\xe2\x3e\x1e\x89\xcb\x2f"
+			  "\x19\x5a\x70\x50\x09\x81\x43\x75",
+		.iv	= "\xa5\x57\x8e\x3c\xba\x52\x87\x4f"
+			  "\xb7\x45\x26\xab\x31\xb9\x58\xfa",
+		.ptext	= "\x43\x29\x69\x02\xf0\xc0\x64\xf3"
+			  "\xe1\x85\x75\x25\x11\x5d\x18\xf8"
+			  "\xdc\x96\x82\x1b\xee\x4d\x01\xd2"
+			  "\x28\x83\xbb\xfe\xe1\x72\x14\x3c"
+			  "\xe9\xe5\x9f\x8c\x40\xb5\x0a\xaa"
+			  "\x9f\xb8\xc5\xf1\x01\x05\x65\x79"
+			  "\x90\x05\xeb\xac\xa8\x52\x35\xc4"
+			  "\x2d\x56\x0d\xe1\x37\x09\xb8\xec"
+			  "\x51\xd8\x79\x13\x5b\x85\x8c\x14"
+			  "\x77\xe3\x64\xea\x89\xb1\x04\x9d"
+			  "\x6c\x58\x1b\x51\x54\x1f\xc7\x2f"
+			  "\xc8\x3d\xa6\x93\x39\xce\x77\x3a"
+			  "\x93\xc2\xaa\x88\xcc\x09\xfa\xc4"
+			  "\x5e\x92\x3b\x46\xd2\xd6\xd4\x5d"
+			  "\x31\x58\xc5\xc6\x30\xb8\x7f\x77"
+			  "\x0f\x1b\xf8\x9a\x7d\x3f\x56\x90"
+			  "\x61\x8f\x08\x8f\x61\x64\x8e\xf4"
+			  "\xaa\x7c\xf8\x4c\x0b\xab\x47\x2a"
+			  "\x0d\xa7\x24\x36\x59\xfe\x94\xfc"
+			  "\x38\x38\x32\xdf\x73\x1b\x75\xb1"
+			  "\x6f\xa2\xd8\x0b\xa1\xd4\x31\x58"
+			  "\xaa\x24\x11\x22\xc9\xf7\x83\x3c"
+			  "\x6e\xee\x75\xc0\xdd\x3b\x21\x99"
+			  "\x9f\xde\x81\x9c\x2a\x70\xc4\xb8"
+			  "\xc6\x27\x4e\x5d\x9a\x4a\xe1\x75"
+			  "\x01\x95\x47\x87\x3f\x9a\x69\x20"
+			  "\xb4\x66\x70\x1a\xe2\xb3\x6c\xfa"
+			  "\x1f\x6e\xf9\xc3\x8a\x1f\x0b\x0b"
+			  "\xc5\x92\xba\xd9\xf8\x27\x6b\x97"
+			  "\x01\xe2\x38\x01\x7f\x06\xde\x54"
+			  "\xb7\x78\xbc\x7d\x6a\xa1\xf2\x6f"
+			  "\x62\x42\x30\xbf\xb1\x6d\xc7",
+		.ctext	= "\x53\xc0\xb3\x13\x8f\xbf\x88\x1a"
+			  "\x6f\xda\xad\x0b\x33\x8b\x82\x9d"
+			  "\xca\x17\x32\x65\xaa\x72\x24\x1b"
+			  "\x95\x33\xcc\x5b\x58\x5d\x08\x58"
+			  "\xe5\x52\xc0\xb7\xc6\x97\x77\x66"
+			  "\xbd\xf4\x50\xde\xe1\xf0\x70\x61"
+			  "\xc2\x05\xce\xe0\x90\x2f\x7f\xb3"
+			  "\x04\x7a\xee\xbe\xb3\xb7\xaf\xda"
+			  "\x3c\xb8\x95\xb4\x20\xba\x66\x0b"
+			  "\x97\xcc\x07\x3f\x22\x07\x0e\xea"
+			  "\x76\xd8\x32\xf9\x34\x47\xcb\xaa"
+			  "\xb3\x5a\x06\x68\xac\x94\x10\x39"
+			  "\xf2\x70\xe1\x7b\x98\x5c\x0c\xcb"
+			  "\x8f\xd8\x48\xfa\x2e\x15\xa1\xf1"
+			  "\x2f\x85\x55\x39\xd8\x24\xe6\xc1"
+			  "\x6f\xd7\x52\x97\x42\x7a\x2e\x14"
+			  "\x39\x74\x16\xf3\x8b\xbd\x38\xb9"
+			  "\x54\x20\xc6\x31\x1b\x4c\xb7\x26"
+			  "\xd4\x71\x63\x97\xaa\xbf\xf5\xb7"
+			  "\x17\x5e\xee\x14\x67\x38\x14\x11"
+			  "\xf6\x98\x3c\x70\x4a\x89\xf4\x27"
+			  "\xb4\x72\x7a\xc0\x5d\x58\x3d\x8b"
+			  "\xf6\xf7\x80\x7b\xa9\xa7\x4d\xf8"
+			  "\x1a\xbe\x07\x0c\x06\x97\x25\xc8"
+			  "\x5a\x18\xae\x21\xa6\xe4\x77\x13"
+			  "\x5a\xe5\xf5\xe0\xd5\x48\x73\x22"
+			  "\x68\xde\x70\x05\xc4\xdf\xd5\x7c"
+			  "\xa0\x2b\x99\x9c\xa8\x21\xd7\x6c"
+			  "\x55\x97\x09\xd6\xb0\x62\x93\x90"
+			  "\x14\xb1\xd1\x83\x5a\xb3\x17\xb9"
+			  "\xc7\xcc\x6b\x51\x23\x44\x4b\xef"
+			  "\x48\x0f\x0f\xf0\x0e\xa1\x8f",
+		.klen	= 24,
+		.len	= 255,
+	},
+	{
+		.key	= "\xed\xd1\xcf\x81\x1c\xf8\x9d\x56"
+			  "\xd4\x3b\x86\x4b\x65\x96\xfe\xe8"
+			  "\x8a\xd4\x3b\xd7\x76\x07\xab\xf4"
+			  "\xe9\xae\xd1\x4d\x50\x9b\x94\x1c",
+		.iv	= "\x09\x90\xf3\x7c\x15\x99\x7d\x94"
+			  "\x88\xf4\x99\x19\xd1\x62\xc4\x65",
+		.ptext	= "\xa2\x06\x41\x55\x60\x2c\xe3\x76"
+			  "\xa9\xaf\xf9\xe1\xd7\x0d\x65\x49"
+			  "\xda\x27\x0d\xf8\xec\xdc\x09\x2b"
+			  "\x06\x24\xe4\xd5\x15\x29\x6b\x5f",
+		.ctext	= "\xad\x5c\xd0\xc1\x03\x45\xba\x9d"
+			  "\xab\x6d\x82\xae\xf7\x8e\x2b\x8b"
+			  "\xd8\x61\xe6\x96\x5c\x5c\xe2\x70"
+			  "\xe5\x19\x0a\x04\x60\xca\x45\xfc",
+		.klen	= 32,
+		.len	= 32,
+	},
+	{
+		.key	= "\xf8\x75\xa6\xba\x7b\x00\xf0\x71"
+			  "\x24\x5d\xdf\x93\x8b\xa3\x7d\x6d"
+			  "\x8e\x0f\x65\xf4\xe2\xbe\x2b\xaa"
+			  "\x2a\x0d\x9e\x00\x6a\x94\x80\xa1",
+		.iv	= "\xb9\xb7\x55\x26\x5f\x96\x16\x68"
+			  "\x5c\x5f\x58\xbb\x4e\x5a\xe1\x3b",
+		.ptext	= "\x2f\xd9\x2c\xc2\x98\x1e\x81\x5e"
+			  "\x89\xc8\xec\x1f\x56\x3e\xd9\xa4"
+			  "\x92\x48\xec\xfc\x5d\xeb\x7f\xad"
+			  "\x7a\x47\xe6\xda\x71\x1b\x2e\xfa",
+		.ctext	= "\x25\x5e\x38\x20\xcf\xbe\x4c\x6c"
+			  "\xe6\xce\xfc\xe2\xca\x6a\xa1\x62"
+			  "\x3a\xb7\xdf\x21\x3e\x49\xa6\xb8"
+			  "\x22\xd2\xc8\x37\xa4\x55\x09\xe6",
+		.klen	= 32,
+		.len	= 32,
+	},
+	{
+		.key	= "\x32\x37\x2b\x8f\x7b\xb1\x23\x79"
+			  "\x05\x52\xde\x05\xf1\x68\x3f\x6c"
+			  "\xa4\xae\xbc\x21\xc2\xc6\xf0\xbd"
+			  "\x0f\x20\xb7\xa4\xc5\x05\x7b\x64",
+		.iv	= "\xff\x26\x4e\x67\x48\xdd\xcf\xfe"
+			  "\x42\x09\x04\x98\x5f\x1e\xfa\x80",
+		.ptext	= "\x99\xdc\x3b\x19\x41\xf9\xff\x6e"
+			  "\x76\xb5\x03\xfa\x61\xed\xf8\x44"
+			  "\x70\xb9\xf0\x83\x80\x6e\x31\x77"
+			  "\x77\xe4\xc7\xb4\x77\x02\xab\x91"
+			  "\x82\xc6\xf8\x7c\x46\x61\x03\x69"
+			  "\x09\xa0\xf7\x12\xb7\x81\x6c\xa9"
+			  "\x10\x5c\xbb\x55\xb3\x44\xed\xb5"
+			  "\xa2\x52\x48\x71\x90\x5d\xda\x40"
+			  "\x0b\x7f\x4a\x11\x6d\xa7\x3d\x8e"
+			  "\x1b\xcd\x9d\x4e\x75\x8b\x7d\x87"
+			  "\xe5\x39\x34\x32\x1e\xe6\x8d\x51"
+			  "\xd4\x1f\xe3\x1d\x50\xa0\x22\x37"
+			  "\x7c\xb0\xd9\xfb\xb6\xb2\x16\xf6"
+			  "\x6d\x26\xa0\x4e\x8c\x6a\xe6\xb6"
+			  "\xbe\x4c\x7c\xe3\x88\x10\x18\x90"
+			  "\x11\x50\x19\x90\xe7\x19\x3f\xd0"
+			  "\x31\x15\x0f\x06\x96\xfe\xa7\x7b"
+			  "\xc3\x32\x88\x69\xa4\x12\xe3\x64"
+			  "\x02\x30\x17\x74\x6c\x88\x7c\x9b"
+			  "\xd6\x6d\x75\xdf\x11\x86\x70\x79"
+			  "\x48\x7d\x34\x3e\x33\x58\x07\x8b"
+			  "\xd2\x50\xac\x35\x15\x45\x05\xb4"
+			  "\x4d\x31\x97\x19\x87\x23\x4b\x87"
+			  "\x53\xdc\xa9\x19\x78\xf1\xbf\x35"
+			  "\x30\x04\x14\xd4\xcf\xb2\x8c\x87"
+			  "\x7d\xdb\x69\xc9\xcd\xfe\x40\x3e"
+			  "\x8d\x66\x5b\x61\xe5\xf0\x2d\x87"
+			  "\x93\x3a\x0c\x2b\x04\x98\x05\xc2"
+			  "\x56\x4d\xc4\x6c\xcd\x7a\x98\x7e"
+			  "\xe2\x2d\x79\x07\x91\x9f\xdf\x2f"
+			  "\x72\xc9\x8f\xcb\x0b\x87\x1b\xb7"
+			  "\x04\x86\xcb\x47\xfa\x5d\x03",
+		.ctext	= "\x0b\x00\xf7\xf2\xc8\x6a\xba\x9a"
+			  "\x0a\x97\x18\x7a\x00\xa0\xdb\xf4"
+			  "\x5e\x8e\x4a\xb7\xe0\x51\xf1\x75"
+			  "\x17\x8b\xb4\xf1\x56\x11\x05\x9f"
+			  "\x2f\x2e\xba\x67\x04\xe1\xb4\xa5"
+			  "\xfc\x7c\x8c\xad\xc6\xb9\xd1\x64"
+			  "\xca\xbd\x5d\xaf\xdb\x65\x48\x4f"
+			  "\x1b\xb3\x94\x5c\x0b\xd0\xee\xcd"
+			  "\xb5\x7f\x43\x8a\xd8\x8b\x66\xde"
+			  "\xd2\x9c\x13\x65\xa4\x47\xa7\x03"
+			  "\xc5\xa1\x46\x8f\x2f\x84\xbc\xef"
+			  "\x48\x9d\x9d\xb5\xbd\x43\xff\xd2"
+			  "\xd2\x7a\x5a\x13\xbf\xb4\xf6\x05"
+			  "\x17\xcd\x01\x12\xf0\x35\x27\x96"
+			  "\xf4\xc1\x65\xf7\x69\xef\x64\x1b"
+			  "\x6e\x4a\xe8\x77\xce\x83\x01\xb7"
+			  "\x60\xe6\x45\x2a\xcd\x41\x4a\xb5"
+			  "\x8e\xcc\x45\x93\xf1\xd6\x64\x5f"
+			  "\x32\x60\xe4\x29\x4a\x82\x6c\x86"
+			  "\x16\xe4\xcc\xdb\x5f\xc8\x11\xa6"
+			  "\xfe\x88\xd6\xc3\xe5\x5c\xbb\x67"
+			  "\xec\xa5\x7b\xf5\xa8\x4f\x77\x25"
+			  "\x5d\x0c\x2a\x99\xf9\xb9\xd1\xae"
+			  "\x3c\x83\x2a\x93\x9b\x66\xec\x68"
+			  "\x2c\x93\x02\x8a\x8a\x1e\x2f\x50"
+			  "\x09\x37\x19\x5c\x2a\x3a\xc2\xcb"
+			  "\xcb\x89\x82\x81\xb7\xbb\xef\x73"
+			  "\x8b\xc9\xae\x42\x96\xef\x70\xc0"
+			  "\x89\xc7\x3e\x6a\x26\xc3\xe4\x39"
+			  "\x53\xa9\xcf\x63\x7d\x05\xf3\xff"
+			  "\x52\x04\xf6\x7f\x23\x96\xe9\xf7"
+			  "\xff\xd6\x50\xa3\x0e\x20\x71",
+		.klen	= 32,
+		.len	= 255,
+	},
+	{
+		.key	= "\x49\x85\x84\x69\xd4\x5f\xf9\xdb"
+			  "\xf2\xc4\x1c\x62\x20\x88\xea\x8a"
+			  "\x5b\x69\xe6\x3b\xe2\x5c\xfe\xce"
+			  "\xe1\x7a\x27\x7b\x1c\xc9\xb4\x43",
+		.iv	= "\xae\x98\xdb\xef\x5c\x6b\xe9\x27"
+			  "\x1a\x2f\x51\x17\x97\x7d\x4f\x10",
+		.ptext	= "\xbe\xf2\x8f\x8a\x51\x9e\x3d\xff"
+			  "\xd7\x68\x0f\xd2\xf2\x5b\xe3\xa5"
+			  "\x59\x3e\xcd\xab\x46\xc6\xe9\x24"
+			  "\x43\xbc\xb8\x37\x1f\x55\x7f\xb5"
+			  "\xc0\xa6\x68\xdf\xbf\x21\x1e\xed"
+			  "\x67\x73\xb7\x06\x47\xff\x67\x07"
+			  "\x5b\x94\xab\xef\x43\x95\x52\xce"
+			  "\xe7\x71\xbd\x72\x5b\x3a\x25\x01"
+			  "\xed\x7d\x02\x2d\x72\xd6\xc4\x3d"
+			  "\xd2\xf5\xe5\xb3\xf2\xd7\xa1\x8d"
+			  "\x12\x0d\x3b\x4a\x58\xf4\x1b\xfd"
+			  "\xcd\x2c\x13\x05\x07\x3d\x30\x8a"
+			  "\x1f\xc6\xed\xfc\x7c\x3c\xa6\x1c"
+			  "\x64\x2c\x36\xa8\x5d\xe2\xfa\x12"
+			  "\xd7\x17\xa9\x39\x43\x63\xbf\x44"
+			  "\xd0\xcb\x4c\xf0\xab\xe6\x75\xd6"
+			  "\x60\xd1\x64\x9e\x01\x2b\x97\x52"
+			  "\x97\x24\x32\xb0\xfa\x22\xf4\x04"
+			  "\xe6\x98\x6a\xbc\xba\xe8\x65\xad"
+			  "\x60\x08\xfc\xd7\x40\xf8\x2a\xf2"
+			  "\x5e\x32\x32\x82\x24\x12\xda\xbc"
+			  "\x8f\x1c\xd4\x06\x81\x08\x80\x35"
+			  "\x20\xa5\xa8\x3a\x6e\x3e\x2f\x78"
+			  "\xe4\x7d\x9e\x81\x43\xb8\xfe\xa7"
+			  "\x3b\xa9\x9b\x1a\xe7\xce\xd2\x3d"
+			  "\xc1\x27\x26\x22\x35\x12\xa2\xc6"
+			  "\x59\x51\x22\x31\x7b\xc8\xca\xa6"
+			  "\xa9\xf3\x16\x57\x72\x3d\xfa\x24"
+			  "\x66\x56\x5d\x21\x29\x9e\xf2\xff"
+			  "\xae\x0c\x71\xcf\xc5\xf0\x98\xe5"
+			  "\xa1\x05\x96\x94\x3e\x36\xed\x97"
+			  "\xc7\xee\xcd\xc2\x54\x35\x5c",
+		.ctext	= "\xde\x7f\x5e\xac\x6f\xec\xed\x2a"
+			  "\x3a\x3b\xb3\x36\x19\x46\x26\x27"
+			  "\x09\x7b\x49\x47\x1b\x88\x43\xb7"
+			  "\x65\x67\xef\x0b\xe4\xde\x0a\x97"
+			  "\x7f\xab\x32\x7c\xa2\xde\x4e\xba"
+			  "\x11\x9b\x19\x12\x7d\x03\x01\x15"
+			  "\xa3\x90\x9f\x52\x9d\x29\x3d\x5c"
+			  "\xc6\x71\x59\x2c\x44\x8f\xb7\x8c"
+			  "\x0d\x75\x81\x76\xe2\x11\x96\x41"
+			  "\xae\x48\x27\x0e\xbc\xaf\x1d\xf5"
+			  "\x51\x68\x5a\x34\xe5\x6d\xdf\x60"
+			  "\xc7\x9d\x4e\x1a\xaa\xb5\x1a\x57"
+			  "\x58\x6a\xa4\x79\x0a\xa9\x50\x8d"
+			  "\x93\x59\xef\x5b\x23\xdb\xc8\xb3"
+			  "\x38\x96\x8c\xdf\x7d\x6a\x3d\x53"
+			  "\x84\x9d\xb0\xf0\x07\x5f\xff\x67"
+			  "\xff\x5b\x3c\x8b\x1f\xa2\x3b\xcf"
+			  "\xf5\x86\x7c\xbc\x98\x38\x7a\xe5"
+			  "\x96\x56\xba\x44\x85\x29\x4f\x3a"
+			  "\x64\xde\xec\xc6\x53\xf0\x30\xca"
+			  "\xa4\x90\x4f\x9c\x2e\x0e\xec\x2d"
+			  "\x8c\x38\x1c\x93\x9a\x5d\x5d\x98"
+			  "\xf9\x2c\xf7\x27\x71\x3c\x69\xa9"
+			  "\x0b\xec\xd9\x9c\x6c\x69\x09\x47"
+			  "\xd9\xc2\x84\x6e\x3e\x2d\x9f\x1f"
+			  "\xb6\x13\x62\x4c\xf3\x33\x44\x13"
+			  "\x6c\x43\x0a\xae\x8e\x89\xd6\x27"
+			  "\xdd\xc3\x5b\x37\x62\x09\x47\x94"
+			  "\xe3\xea\x7d\x08\x14\x70\xb1\x8e"
+			  "\x83\x4a\xcb\xc0\xa9\xf2\xa3\x02"
+			  "\xe9\xa0\x44\xfe\xcf\x5a\x15\x50"
+			  "\xc4\x5a\x6f\xc8\xd6\xf1\x83",
+		.klen	= 32,
+		.len	= 255,
+	},
+};
+
 #endif	/* _CRYPTO_TESTMGR_H */
diff --git a/crypto/xctr.c b/crypto/xctr.c
new file mode 100644
index 000000000000..dfb44c092cc4
--- /dev/null
+++ b/crypto/xctr.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * XCTR: XOR Counter mode - Adapted from ctr.c
+ *
+ * (C) Copyright IBM Corp. 2007 - Joy Latten <[email-masked]>
+ * Copyright 2021 Google LLC
+ */
+
+/*
+ * XCTR mode is a blockcipher mode of operation used to implement HCTR2. XCTR is
+ * closely related to the CTR mode of operation; the main difference is that CTR
+ * generates the keystream using E(CTR + IV) whereas XCTR generates the
+ * keystream using E(CTR ^ IV).
+ *
+ * See the HCTR2 paper for more details:
+ *	Length-preserving encryption with HCTR2
+ *      (https://eprint.iacr.org/2021/1441.pdf)
+ */
+
+#include <crypto/algapi.h>
+#include <crypto/xctr.h>
+#include <crypto/internal/cipher.h>
+#include <crypto/internal/skcipher.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+static void crypto_xctr_crypt_final(struct skcipher_walk *walk,
+				   struct crypto_cipher *tfm, u32 byte_ctr)
+{
+	unsigned int bsize = crypto_cipher_blocksize(tfm);
+	unsigned long alignmask = crypto_cipher_alignmask(tfm);
+	u8 ctr[MAX_CIPHER_BLOCKSIZE];
+	u8 ctrblk[MAX_CIPHER_BLOCKSIZE];
+	u8 tmp[MAX_CIPHER_BLOCKSIZE + MAX_CIPHER_ALIGNMASK];
+	u8 *keystream = PTR_ALIGN(tmp + 0, alignmask + 1);
+	u8 *src = walk->src.virt.addr;
+	u8 *dst = walk->dst.virt.addr;
+	unsigned int nbytes = walk->nbytes;
+	u32 ctr32 = byte_ctr / bsize + 1;
+
+	u32_to_le_block(ctr, ctr32, bsize);
+	crypto_xor_cpy(ctrblk, ctr, walk->iv, bsize);
+	crypto_cipher_encrypt_one(tfm, keystream, ctrblk);
+	crypto_xor_cpy(dst, keystream, src, nbytes);
+}
+
+static int crypto_xctr_crypt_segment(struct skcipher_walk *walk,
+				    struct crypto_cipher *tfm, u32 byte_ctr)
+{
+	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
+		   crypto_cipher_alg(tfm)->cia_encrypt;
+	unsigned int bsize = crypto_cipher_blocksize(tfm);
+	u8 ctr[MAX_CIPHER_BLOCKSIZE];
+	u8 ctrblk[MAX_CIPHER_BLOCKSIZE];
+	u8 *src = walk->src.virt.addr;
+	u8 *dst = walk->dst.virt.addr;
+	unsigned int nbytes = walk->nbytes;
+	u32 ctr32 = byte_ctr / bsize + 1;
+
+	do {
+		/* create keystream */
+		u32_to_le_block(ctr, ctr32, bsize);
+		crypto_xor_cpy(ctrblk, ctr, walk->iv, bsize);
+		fn(crypto_cipher_tfm(tfm), dst, ctrblk);
+		crypto_xor(dst, src, bsize);
+
+		ctr32++;
+
+		src += bsize;
+		dst += bsize;
+	} while ((nbytes -= bsize) >= bsize);
+
+	return nbytes;
+}
+
+static int crypto_xctr_crypt_inplace(struct skcipher_walk *walk,
+				    struct crypto_cipher *tfm, u32 byte_ctr)
+{
+	void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
+		   crypto_cipher_alg(tfm)->cia_encrypt;
+	unsigned int bsize = crypto_cipher_blocksize(tfm);
+	unsigned long alignmask = crypto_cipher_alignmask(tfm);
+	unsigned int nbytes = walk->nbytes;
+	u8 ctr[MAX_CIPHER_BLOCKSIZE];
+	u8 ctrblk[MAX_CIPHER_BLOCKSIZE];
+	u8 *src = walk->src.virt.addr;
+	u8 tmp[MAX_CIPHER_BLOCKSIZE + MAX_CIPHER_ALIGNMASK];
+	u8 *keystream = PTR_ALIGN(tmp + 0, alignmask + 1);
+	u32 ctr32 = byte_ctr / bsize + 1;
+
+	u32_to_le_block(ctr, ctr32, bsize);
+	do {
+		/* create keystream */
+		u32_to_le_block(ctr, ctr32, bsize);
+		crypto_xor_cpy(ctrblk, ctr, walk->iv, bsize);
+		fn(crypto_cipher_tfm(tfm), keystream, ctrblk);
+		crypto_xor(src, keystream, bsize);
+
+		ctr32++;
+
+		src += bsize;
+	} while ((nbytes -= bsize) >= bsize);
+
+	return nbytes;
+}
+
+static int crypto_xctr_crypt(struct skcipher_request *req)
+{
+	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
+	struct crypto_cipher *cipher = skcipher_cipher_simple(tfm);
+	const unsigned int bsize = crypto_cipher_blocksize(cipher);
+	struct skcipher_walk walk;
+	unsigned int nbytes;
+	int err;
+	u32 byte_ctr = 0;
+
+	err = skcipher_walk_virt(&walk, req, false);
+
+	while (walk.nbytes >= bsize) {
+		if (walk.src.virt.addr == walk.dst.virt.addr)
+			nbytes = crypto_xctr_crypt_inplace(&walk, cipher, byte_ctr);
+		else
+			nbytes = crypto_xctr_crypt_segment(&walk, cipher, byte_ctr);
+
+		byte_ctr += walk.nbytes - nbytes;
+		err = skcipher_walk_done(&walk, nbytes);
+	}
+
+	if (walk.nbytes) {
+		crypto_xctr_crypt_final(&walk, cipher, byte_ctr);
+		err = skcipher_walk_done(&walk, 0);
+	}
+
+	return err;
+}
+
+static int crypto_xctr_create(struct crypto_template *tmpl, struct rtattr **tb)
+{
+	struct skcipher_instance *inst;
+	struct crypto_alg *alg;
+	int err;
+
+	inst = skcipher_alloc_instance_simple(tmpl, tb);
+	if (IS_ERR(inst))
+		return PTR_ERR(inst);
+
+	alg = skcipher_ialg_simple(inst);
+
+	/* Block size must be >= 4 bytes. */
+	err = -EINVAL;
+	if (alg->cra_blocksize < 4)
+		goto out_free_inst;
+
+	/* XCTR mode is a stream cipher. */
+	inst->alg.base.cra_blocksize = 1;
+
+	/*
+	 * To simplify the implementation, configure the skcipher walk to only
+	 * give a partial block at the very end, never earlier.
+	 */
+	inst->alg.chunksize = alg->cra_blocksize;
+
+	inst->alg.encrypt = crypto_xctr_crypt;
+	inst->alg.decrypt = crypto_xctr_crypt;
+
+	err = skcipher_register_instance(tmpl, inst);
+	if (err) {
+out_free_inst:
+		inst->free(inst);
+	}
+
+	return err;
+}
+
+static struct crypto_template crypto_xctr_tmpl[] = {
+	{
+		.name = "xctr",
+		.create = crypto_xctr_create,
+		.module = THIS_MODULE,
+	}
+};
+
+static int __init crypto_xctr_module_init(void)
+{
+	return crypto_register_template(crypto_xctr_tmpl);
+}
+
+static void __exit crypto_xctr_module_exit(void)
+{
+	crypto_unregister_template(crypto_xctr_tmpl);
+}
+
+subsys_initcall(crypto_xctr_module_init);
+module_exit(crypto_xctr_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("XCTR block cipher mode of operation");
+MODULE_ALIAS_CRYPTO("xctr");
+MODULE_IMPORT_NS(CRYPTO_INTERNAL);
diff --git a/include/crypto/xctr.h b/include/crypto/xctr.h
new file mode 100644
index 000000000000..0d025e08ca26
--- /dev/null
+++ b/include/crypto/xctr.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * XCTR: XOR Counter mode
+ *
+ * Copyright 2021 Google LLC
+ */
+
+#include <asm/unaligned.h>
+
+#ifndef _CRYPTO_XCTR_H
+#define _CRYPTO_XCTR_H
+
+static inline void u32_to_le_block(u8 *a, u32 x, unsigned int size)
+{
+	memset(a, 0, size);
+	put_unaligned(cpu_to_le32(x), (u32 *)a);
+}
+
+#endif  /* _CRYPTO_XCTR_H */
-- 
2.35.0.rc0.227.g00780c9af4-goog

_______________________________________________
linux-arm-kernel mailing list
[email-masked]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel