18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Cryptographic API.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * TEA, XTEA, and XETA crypto alogrithms
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * The TEA and Xtended TEA algorithms were developed by David Wheeler
88c2ecf20Sopenharmony_ci * and Roger Needham at the Computer Laboratory of Cambridge University.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Due to the order of evaluation in XTEA many people have incorrectly
118c2ecf20Sopenharmony_ci * implemented it.  XETA (XTEA in the wrong order), exists for
128c2ecf20Sopenharmony_ci * compatibility with these implementations.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * Copyright (c) 2004 Aaron Grothe ajgrothe@yahoo.com
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/init.h>
188c2ecf20Sopenharmony_ci#include <linux/module.h>
198c2ecf20Sopenharmony_ci#include <linux/mm.h>
208c2ecf20Sopenharmony_ci#include <asm/byteorder.h>
218c2ecf20Sopenharmony_ci#include <linux/crypto.h>
228c2ecf20Sopenharmony_ci#include <linux/types.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define TEA_KEY_SIZE		16
258c2ecf20Sopenharmony_ci#define TEA_BLOCK_SIZE		8
268c2ecf20Sopenharmony_ci#define TEA_ROUNDS		32
278c2ecf20Sopenharmony_ci#define TEA_DELTA		0x9e3779b9
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define XTEA_KEY_SIZE		16
308c2ecf20Sopenharmony_ci#define XTEA_BLOCK_SIZE		8
318c2ecf20Sopenharmony_ci#define XTEA_ROUNDS		32
328c2ecf20Sopenharmony_ci#define XTEA_DELTA		0x9e3779b9
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistruct tea_ctx {
358c2ecf20Sopenharmony_ci	u32 KEY[4];
368c2ecf20Sopenharmony_ci};
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistruct xtea_ctx {
398c2ecf20Sopenharmony_ci	u32 KEY[4];
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic int tea_setkey(struct crypto_tfm *tfm, const u8 *in_key,
438c2ecf20Sopenharmony_ci		      unsigned int key_len)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct tea_ctx *ctx = crypto_tfm_ctx(tfm);
468c2ecf20Sopenharmony_ci	const __le32 *key = (const __le32 *)in_key;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	ctx->KEY[0] = le32_to_cpu(key[0]);
498c2ecf20Sopenharmony_ci	ctx->KEY[1] = le32_to_cpu(key[1]);
508c2ecf20Sopenharmony_ci	ctx->KEY[2] = le32_to_cpu(key[2]);
518c2ecf20Sopenharmony_ci	ctx->KEY[3] = le32_to_cpu(key[3]);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	return 0;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic void tea_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	u32 y, z, n, sum = 0;
608c2ecf20Sopenharmony_ci	u32 k0, k1, k2, k3;
618c2ecf20Sopenharmony_ci	struct tea_ctx *ctx = crypto_tfm_ctx(tfm);
628c2ecf20Sopenharmony_ci	const __le32 *in = (const __le32 *)src;
638c2ecf20Sopenharmony_ci	__le32 *out = (__le32 *)dst;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	y = le32_to_cpu(in[0]);
668c2ecf20Sopenharmony_ci	z = le32_to_cpu(in[1]);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	k0 = ctx->KEY[0];
698c2ecf20Sopenharmony_ci	k1 = ctx->KEY[1];
708c2ecf20Sopenharmony_ci	k2 = ctx->KEY[2];
718c2ecf20Sopenharmony_ci	k3 = ctx->KEY[3];
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	n = TEA_ROUNDS;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	while (n-- > 0) {
768c2ecf20Sopenharmony_ci		sum += TEA_DELTA;
778c2ecf20Sopenharmony_ci		y += ((z << 4) + k0) ^ (z + sum) ^ ((z >> 5) + k1);
788c2ecf20Sopenharmony_ci		z += ((y << 4) + k2) ^ (y + sum) ^ ((y >> 5) + k3);
798c2ecf20Sopenharmony_ci	}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	out[0] = cpu_to_le32(y);
828c2ecf20Sopenharmony_ci	out[1] = cpu_to_le32(z);
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic void tea_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	u32 y, z, n, sum;
888c2ecf20Sopenharmony_ci	u32 k0, k1, k2, k3;
898c2ecf20Sopenharmony_ci	struct tea_ctx *ctx = crypto_tfm_ctx(tfm);
908c2ecf20Sopenharmony_ci	const __le32 *in = (const __le32 *)src;
918c2ecf20Sopenharmony_ci	__le32 *out = (__le32 *)dst;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	y = le32_to_cpu(in[0]);
948c2ecf20Sopenharmony_ci	z = le32_to_cpu(in[1]);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	k0 = ctx->KEY[0];
978c2ecf20Sopenharmony_ci	k1 = ctx->KEY[1];
988c2ecf20Sopenharmony_ci	k2 = ctx->KEY[2];
998c2ecf20Sopenharmony_ci	k3 = ctx->KEY[3];
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	sum = TEA_DELTA << 5;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	n = TEA_ROUNDS;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	while (n-- > 0) {
1068c2ecf20Sopenharmony_ci		z -= ((y << 4) + k2) ^ (y + sum) ^ ((y >> 5) + k3);
1078c2ecf20Sopenharmony_ci		y -= ((z << 4) + k0) ^ (z + sum) ^ ((z >> 5) + k1);
1088c2ecf20Sopenharmony_ci		sum -= TEA_DELTA;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	out[0] = cpu_to_le32(y);
1128c2ecf20Sopenharmony_ci	out[1] = cpu_to_le32(z);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic int xtea_setkey(struct crypto_tfm *tfm, const u8 *in_key,
1168c2ecf20Sopenharmony_ci		       unsigned int key_len)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct xtea_ctx *ctx = crypto_tfm_ctx(tfm);
1198c2ecf20Sopenharmony_ci	const __le32 *key = (const __le32 *)in_key;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	ctx->KEY[0] = le32_to_cpu(key[0]);
1228c2ecf20Sopenharmony_ci	ctx->KEY[1] = le32_to_cpu(key[1]);
1238c2ecf20Sopenharmony_ci	ctx->KEY[2] = le32_to_cpu(key[2]);
1248c2ecf20Sopenharmony_ci	ctx->KEY[3] = le32_to_cpu(key[3]);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	return 0;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic void xtea_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	u32 y, z, sum = 0;
1338c2ecf20Sopenharmony_ci	u32 limit = XTEA_DELTA * XTEA_ROUNDS;
1348c2ecf20Sopenharmony_ci	struct xtea_ctx *ctx = crypto_tfm_ctx(tfm);
1358c2ecf20Sopenharmony_ci	const __le32 *in = (const __le32 *)src;
1368c2ecf20Sopenharmony_ci	__le32 *out = (__le32 *)dst;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	y = le32_to_cpu(in[0]);
1398c2ecf20Sopenharmony_ci	z = le32_to_cpu(in[1]);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	while (sum != limit) {
1428c2ecf20Sopenharmony_ci		y += ((z << 4 ^ z >> 5) + z) ^ (sum + ctx->KEY[sum&3]);
1438c2ecf20Sopenharmony_ci		sum += XTEA_DELTA;
1448c2ecf20Sopenharmony_ci		z += ((y << 4 ^ y >> 5) + y) ^ (sum + ctx->KEY[sum>>11 &3]);
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	out[0] = cpu_to_le32(y);
1488c2ecf20Sopenharmony_ci	out[1] = cpu_to_le32(z);
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic void xtea_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	u32 y, z, sum;
1548c2ecf20Sopenharmony_ci	struct tea_ctx *ctx = crypto_tfm_ctx(tfm);
1558c2ecf20Sopenharmony_ci	const __le32 *in = (const __le32 *)src;
1568c2ecf20Sopenharmony_ci	__le32 *out = (__le32 *)dst;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	y = le32_to_cpu(in[0]);
1598c2ecf20Sopenharmony_ci	z = le32_to_cpu(in[1]);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	sum = XTEA_DELTA * XTEA_ROUNDS;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	while (sum) {
1648c2ecf20Sopenharmony_ci		z -= ((y << 4 ^ y >> 5) + y) ^ (sum + ctx->KEY[sum>>11 & 3]);
1658c2ecf20Sopenharmony_ci		sum -= XTEA_DELTA;
1668c2ecf20Sopenharmony_ci		y -= ((z << 4 ^ z >> 5) + z) ^ (sum + ctx->KEY[sum & 3]);
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	out[0] = cpu_to_le32(y);
1708c2ecf20Sopenharmony_ci	out[1] = cpu_to_le32(z);
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic void xeta_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	u32 y, z, sum = 0;
1778c2ecf20Sopenharmony_ci	u32 limit = XTEA_DELTA * XTEA_ROUNDS;
1788c2ecf20Sopenharmony_ci	struct xtea_ctx *ctx = crypto_tfm_ctx(tfm);
1798c2ecf20Sopenharmony_ci	const __le32 *in = (const __le32 *)src;
1808c2ecf20Sopenharmony_ci	__le32 *out = (__le32 *)dst;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	y = le32_to_cpu(in[0]);
1838c2ecf20Sopenharmony_ci	z = le32_to_cpu(in[1]);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	while (sum != limit) {
1868c2ecf20Sopenharmony_ci		y += (z << 4 ^ z >> 5) + (z ^ sum) + ctx->KEY[sum&3];
1878c2ecf20Sopenharmony_ci		sum += XTEA_DELTA;
1888c2ecf20Sopenharmony_ci		z += (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 &3];
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	out[0] = cpu_to_le32(y);
1928c2ecf20Sopenharmony_ci	out[1] = cpu_to_le32(z);
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic void xeta_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	u32 y, z, sum;
1988c2ecf20Sopenharmony_ci	struct tea_ctx *ctx = crypto_tfm_ctx(tfm);
1998c2ecf20Sopenharmony_ci	const __le32 *in = (const __le32 *)src;
2008c2ecf20Sopenharmony_ci	__le32 *out = (__le32 *)dst;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	y = le32_to_cpu(in[0]);
2038c2ecf20Sopenharmony_ci	z = le32_to_cpu(in[1]);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	sum = XTEA_DELTA * XTEA_ROUNDS;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	while (sum) {
2088c2ecf20Sopenharmony_ci		z -= (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 & 3];
2098c2ecf20Sopenharmony_ci		sum -= XTEA_DELTA;
2108c2ecf20Sopenharmony_ci		y -= (z << 4 ^ z >> 5) + (z ^ sum) + ctx->KEY[sum & 3];
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	out[0] = cpu_to_le32(y);
2148c2ecf20Sopenharmony_ci	out[1] = cpu_to_le32(z);
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic struct crypto_alg tea_algs[3] = { {
2188c2ecf20Sopenharmony_ci	.cra_name		=	"tea",
2198c2ecf20Sopenharmony_ci	.cra_driver_name	=	"tea-generic",
2208c2ecf20Sopenharmony_ci	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
2218c2ecf20Sopenharmony_ci	.cra_blocksize		=	TEA_BLOCK_SIZE,
2228c2ecf20Sopenharmony_ci	.cra_ctxsize		=	sizeof (struct tea_ctx),
2238c2ecf20Sopenharmony_ci	.cra_alignmask		=	3,
2248c2ecf20Sopenharmony_ci	.cra_module		=	THIS_MODULE,
2258c2ecf20Sopenharmony_ci	.cra_u			=	{ .cipher = {
2268c2ecf20Sopenharmony_ci	.cia_min_keysize	=	TEA_KEY_SIZE,
2278c2ecf20Sopenharmony_ci	.cia_max_keysize	=	TEA_KEY_SIZE,
2288c2ecf20Sopenharmony_ci	.cia_setkey		= 	tea_setkey,
2298c2ecf20Sopenharmony_ci	.cia_encrypt		=	tea_encrypt,
2308c2ecf20Sopenharmony_ci	.cia_decrypt		=	tea_decrypt } }
2318c2ecf20Sopenharmony_ci}, {
2328c2ecf20Sopenharmony_ci	.cra_name		=	"xtea",
2338c2ecf20Sopenharmony_ci	.cra_driver_name	=	"xtea-generic",
2348c2ecf20Sopenharmony_ci	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
2358c2ecf20Sopenharmony_ci	.cra_blocksize		=	XTEA_BLOCK_SIZE,
2368c2ecf20Sopenharmony_ci	.cra_ctxsize		=	sizeof (struct xtea_ctx),
2378c2ecf20Sopenharmony_ci	.cra_alignmask		=	3,
2388c2ecf20Sopenharmony_ci	.cra_module		=	THIS_MODULE,
2398c2ecf20Sopenharmony_ci	.cra_u			=	{ .cipher = {
2408c2ecf20Sopenharmony_ci	.cia_min_keysize	=	XTEA_KEY_SIZE,
2418c2ecf20Sopenharmony_ci	.cia_max_keysize	=	XTEA_KEY_SIZE,
2428c2ecf20Sopenharmony_ci	.cia_setkey		= 	xtea_setkey,
2438c2ecf20Sopenharmony_ci	.cia_encrypt		=	xtea_encrypt,
2448c2ecf20Sopenharmony_ci	.cia_decrypt		=	xtea_decrypt } }
2458c2ecf20Sopenharmony_ci}, {
2468c2ecf20Sopenharmony_ci	.cra_name		=	"xeta",
2478c2ecf20Sopenharmony_ci	.cra_driver_name	=	"xeta-generic",
2488c2ecf20Sopenharmony_ci	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
2498c2ecf20Sopenharmony_ci	.cra_blocksize		=	XTEA_BLOCK_SIZE,
2508c2ecf20Sopenharmony_ci	.cra_ctxsize		=	sizeof (struct xtea_ctx),
2518c2ecf20Sopenharmony_ci	.cra_alignmask		=	3,
2528c2ecf20Sopenharmony_ci	.cra_module		=	THIS_MODULE,
2538c2ecf20Sopenharmony_ci	.cra_u			=	{ .cipher = {
2548c2ecf20Sopenharmony_ci	.cia_min_keysize	=	XTEA_KEY_SIZE,
2558c2ecf20Sopenharmony_ci	.cia_max_keysize	=	XTEA_KEY_SIZE,
2568c2ecf20Sopenharmony_ci	.cia_setkey		= 	xtea_setkey,
2578c2ecf20Sopenharmony_ci	.cia_encrypt		=	xeta_encrypt,
2588c2ecf20Sopenharmony_ci	.cia_decrypt		=	xeta_decrypt } }
2598c2ecf20Sopenharmony_ci} };
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic int __init tea_mod_init(void)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	return crypto_register_algs(tea_algs, ARRAY_SIZE(tea_algs));
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic void __exit tea_mod_fini(void)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	crypto_unregister_algs(tea_algs, ARRAY_SIZE(tea_algs));
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("tea");
2728c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("xtea");
2738c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("xeta");
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cisubsys_initcall(tea_mod_init);
2768c2ecf20Sopenharmony_cimodule_exit(tea_mod_fini);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
2798c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TEA, XTEA & XETA Cryptographic Algorithms");
280