18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Salsa20: Salsa20 stream cipher algorithm
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (c) 2007 Tan Swee Heng <thesweeheng@gmail.com>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Derived from:
78c2ecf20Sopenharmony_ci * - salsa20.c: Public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Salsa20 is a stream cipher candidate in eSTREAM, the ECRYPT Stream
108c2ecf20Sopenharmony_ci * Cipher Project. It is designed by Daniel J. Bernstein <djb@cr.yp.to>.
118c2ecf20Sopenharmony_ci * More information about eSTREAM and Salsa20 can be found here:
128c2ecf20Sopenharmony_ci *   https://www.ecrypt.eu.org/stream/
138c2ecf20Sopenharmony_ci *   https://cr.yp.to/snuffle.html
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it
168c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License as published by the Free
178c2ecf20Sopenharmony_ci * Software Foundation; either version 2 of the License, or (at your option)
188c2ecf20Sopenharmony_ci * any later version.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci */
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
238c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h>
248c2ecf20Sopenharmony_ci#include <linux/module.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define SALSA20_IV_SIZE        8
278c2ecf20Sopenharmony_ci#define SALSA20_MIN_KEY_SIZE  16
288c2ecf20Sopenharmony_ci#define SALSA20_MAX_KEY_SIZE  32
298c2ecf20Sopenharmony_ci#define SALSA20_BLOCK_SIZE    64
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistruct salsa20_ctx {
328c2ecf20Sopenharmony_ci	u32 initial_state[16];
338c2ecf20Sopenharmony_ci};
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic void salsa20_block(u32 *state, __le32 *stream)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	u32 x[16];
388c2ecf20Sopenharmony_ci	int i;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	memcpy(x, state, sizeof(x));
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	for (i = 0; i < 20; i += 2) {
438c2ecf20Sopenharmony_ci		x[ 4] ^= rol32((x[ 0] + x[12]),  7);
448c2ecf20Sopenharmony_ci		x[ 8] ^= rol32((x[ 4] + x[ 0]),  9);
458c2ecf20Sopenharmony_ci		x[12] ^= rol32((x[ 8] + x[ 4]), 13);
468c2ecf20Sopenharmony_ci		x[ 0] ^= rol32((x[12] + x[ 8]), 18);
478c2ecf20Sopenharmony_ci		x[ 9] ^= rol32((x[ 5] + x[ 1]),  7);
488c2ecf20Sopenharmony_ci		x[13] ^= rol32((x[ 9] + x[ 5]),  9);
498c2ecf20Sopenharmony_ci		x[ 1] ^= rol32((x[13] + x[ 9]), 13);
508c2ecf20Sopenharmony_ci		x[ 5] ^= rol32((x[ 1] + x[13]), 18);
518c2ecf20Sopenharmony_ci		x[14] ^= rol32((x[10] + x[ 6]),  7);
528c2ecf20Sopenharmony_ci		x[ 2] ^= rol32((x[14] + x[10]),  9);
538c2ecf20Sopenharmony_ci		x[ 6] ^= rol32((x[ 2] + x[14]), 13);
548c2ecf20Sopenharmony_ci		x[10] ^= rol32((x[ 6] + x[ 2]), 18);
558c2ecf20Sopenharmony_ci		x[ 3] ^= rol32((x[15] + x[11]),  7);
568c2ecf20Sopenharmony_ci		x[ 7] ^= rol32((x[ 3] + x[15]),  9);
578c2ecf20Sopenharmony_ci		x[11] ^= rol32((x[ 7] + x[ 3]), 13);
588c2ecf20Sopenharmony_ci		x[15] ^= rol32((x[11] + x[ 7]), 18);
598c2ecf20Sopenharmony_ci		x[ 1] ^= rol32((x[ 0] + x[ 3]),  7);
608c2ecf20Sopenharmony_ci		x[ 2] ^= rol32((x[ 1] + x[ 0]),  9);
618c2ecf20Sopenharmony_ci		x[ 3] ^= rol32((x[ 2] + x[ 1]), 13);
628c2ecf20Sopenharmony_ci		x[ 0] ^= rol32((x[ 3] + x[ 2]), 18);
638c2ecf20Sopenharmony_ci		x[ 6] ^= rol32((x[ 5] + x[ 4]),  7);
648c2ecf20Sopenharmony_ci		x[ 7] ^= rol32((x[ 6] + x[ 5]),  9);
658c2ecf20Sopenharmony_ci		x[ 4] ^= rol32((x[ 7] + x[ 6]), 13);
668c2ecf20Sopenharmony_ci		x[ 5] ^= rol32((x[ 4] + x[ 7]), 18);
678c2ecf20Sopenharmony_ci		x[11] ^= rol32((x[10] + x[ 9]),  7);
688c2ecf20Sopenharmony_ci		x[ 8] ^= rol32((x[11] + x[10]),  9);
698c2ecf20Sopenharmony_ci		x[ 9] ^= rol32((x[ 8] + x[11]), 13);
708c2ecf20Sopenharmony_ci		x[10] ^= rol32((x[ 9] + x[ 8]), 18);
718c2ecf20Sopenharmony_ci		x[12] ^= rol32((x[15] + x[14]),  7);
728c2ecf20Sopenharmony_ci		x[13] ^= rol32((x[12] + x[15]),  9);
738c2ecf20Sopenharmony_ci		x[14] ^= rol32((x[13] + x[12]), 13);
748c2ecf20Sopenharmony_ci		x[15] ^= rol32((x[14] + x[13]), 18);
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++)
788c2ecf20Sopenharmony_ci		stream[i] = cpu_to_le32(x[i] + state[i]);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	if (++state[8] == 0)
818c2ecf20Sopenharmony_ci		state[9]++;
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic void salsa20_docrypt(u32 *state, u8 *dst, const u8 *src,
858c2ecf20Sopenharmony_ci			    unsigned int bytes)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	__le32 stream[SALSA20_BLOCK_SIZE / sizeof(__le32)];
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	while (bytes >= SALSA20_BLOCK_SIZE) {
908c2ecf20Sopenharmony_ci		salsa20_block(state, stream);
918c2ecf20Sopenharmony_ci		crypto_xor_cpy(dst, src, (const u8 *)stream,
928c2ecf20Sopenharmony_ci			       SALSA20_BLOCK_SIZE);
938c2ecf20Sopenharmony_ci		bytes -= SALSA20_BLOCK_SIZE;
948c2ecf20Sopenharmony_ci		dst += SALSA20_BLOCK_SIZE;
958c2ecf20Sopenharmony_ci		src += SALSA20_BLOCK_SIZE;
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci	if (bytes) {
988c2ecf20Sopenharmony_ci		salsa20_block(state, stream);
998c2ecf20Sopenharmony_ci		crypto_xor_cpy(dst, src, (const u8 *)stream, bytes);
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic void salsa20_init(u32 *state, const struct salsa20_ctx *ctx,
1048c2ecf20Sopenharmony_ci			 const u8 *iv)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	memcpy(state, ctx->initial_state, sizeof(ctx->initial_state));
1078c2ecf20Sopenharmony_ci	state[6] = get_unaligned_le32(iv + 0);
1088c2ecf20Sopenharmony_ci	state[7] = get_unaligned_le32(iv + 4);
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic int salsa20_setkey(struct crypto_skcipher *tfm, const u8 *key,
1128c2ecf20Sopenharmony_ci			  unsigned int keysize)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	static const char sigma[16] = "expand 32-byte k";
1158c2ecf20Sopenharmony_ci	static const char tau[16] = "expand 16-byte k";
1168c2ecf20Sopenharmony_ci	struct salsa20_ctx *ctx = crypto_skcipher_ctx(tfm);
1178c2ecf20Sopenharmony_ci	const char *constants;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	if (keysize != SALSA20_MIN_KEY_SIZE &&
1208c2ecf20Sopenharmony_ci	    keysize != SALSA20_MAX_KEY_SIZE)
1218c2ecf20Sopenharmony_ci		return -EINVAL;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	ctx->initial_state[1] = get_unaligned_le32(key + 0);
1248c2ecf20Sopenharmony_ci	ctx->initial_state[2] = get_unaligned_le32(key + 4);
1258c2ecf20Sopenharmony_ci	ctx->initial_state[3] = get_unaligned_le32(key + 8);
1268c2ecf20Sopenharmony_ci	ctx->initial_state[4] = get_unaligned_le32(key + 12);
1278c2ecf20Sopenharmony_ci	if (keysize == 32) { /* recommended */
1288c2ecf20Sopenharmony_ci		key += 16;
1298c2ecf20Sopenharmony_ci		constants = sigma;
1308c2ecf20Sopenharmony_ci	} else { /* keysize == 16 */
1318c2ecf20Sopenharmony_ci		constants = tau;
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci	ctx->initial_state[11] = get_unaligned_le32(key + 0);
1348c2ecf20Sopenharmony_ci	ctx->initial_state[12] = get_unaligned_le32(key + 4);
1358c2ecf20Sopenharmony_ci	ctx->initial_state[13] = get_unaligned_le32(key + 8);
1368c2ecf20Sopenharmony_ci	ctx->initial_state[14] = get_unaligned_le32(key + 12);
1378c2ecf20Sopenharmony_ci	ctx->initial_state[0]  = get_unaligned_le32(constants + 0);
1388c2ecf20Sopenharmony_ci	ctx->initial_state[5]  = get_unaligned_le32(constants + 4);
1398c2ecf20Sopenharmony_ci	ctx->initial_state[10] = get_unaligned_le32(constants + 8);
1408c2ecf20Sopenharmony_ci	ctx->initial_state[15] = get_unaligned_le32(constants + 12);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	/* space for the nonce; it will be overridden for each request */
1438c2ecf20Sopenharmony_ci	ctx->initial_state[6] = 0;
1448c2ecf20Sopenharmony_ci	ctx->initial_state[7] = 0;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	/* initial block number */
1478c2ecf20Sopenharmony_ci	ctx->initial_state[8] = 0;
1488c2ecf20Sopenharmony_ci	ctx->initial_state[9] = 0;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return 0;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic int salsa20_crypt(struct skcipher_request *req)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
1568c2ecf20Sopenharmony_ci	const struct salsa20_ctx *ctx = crypto_skcipher_ctx(tfm);
1578c2ecf20Sopenharmony_ci	struct skcipher_walk walk;
1588c2ecf20Sopenharmony_ci	u32 state[16];
1598c2ecf20Sopenharmony_ci	int err;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	err = skcipher_walk_virt(&walk, req, false);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	salsa20_init(state, ctx, req->iv);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	while (walk.nbytes > 0) {
1668c2ecf20Sopenharmony_ci		unsigned int nbytes = walk.nbytes;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci		if (nbytes < walk.total)
1698c2ecf20Sopenharmony_ci			nbytes = round_down(nbytes, walk.stride);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci		salsa20_docrypt(state, walk.dst.virt.addr, walk.src.virt.addr,
1728c2ecf20Sopenharmony_ci				nbytes);
1738c2ecf20Sopenharmony_ci		err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	return err;
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic struct skcipher_alg alg = {
1808c2ecf20Sopenharmony_ci	.base.cra_name		= "salsa20",
1818c2ecf20Sopenharmony_ci	.base.cra_driver_name	= "salsa20-generic",
1828c2ecf20Sopenharmony_ci	.base.cra_priority	= 100,
1838c2ecf20Sopenharmony_ci	.base.cra_blocksize	= 1,
1848c2ecf20Sopenharmony_ci	.base.cra_ctxsize	= sizeof(struct salsa20_ctx),
1858c2ecf20Sopenharmony_ci	.base.cra_module	= THIS_MODULE,
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	.min_keysize		= SALSA20_MIN_KEY_SIZE,
1888c2ecf20Sopenharmony_ci	.max_keysize		= SALSA20_MAX_KEY_SIZE,
1898c2ecf20Sopenharmony_ci	.ivsize			= SALSA20_IV_SIZE,
1908c2ecf20Sopenharmony_ci	.chunksize		= SALSA20_BLOCK_SIZE,
1918c2ecf20Sopenharmony_ci	.setkey			= salsa20_setkey,
1928c2ecf20Sopenharmony_ci	.encrypt		= salsa20_crypt,
1938c2ecf20Sopenharmony_ci	.decrypt		= salsa20_crypt,
1948c2ecf20Sopenharmony_ci};
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cistatic int __init salsa20_generic_mod_init(void)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	return crypto_register_skcipher(&alg);
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic void __exit salsa20_generic_mod_fini(void)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	crypto_unregister_skcipher(&alg);
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cisubsys_initcall(salsa20_generic_mod_init);
2078c2ecf20Sopenharmony_cimodule_exit(salsa20_generic_mod_fini);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
2108c2ecf20Sopenharmony_ciMODULE_DESCRIPTION ("Salsa20 stream cipher algorithm");
2118c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("salsa20");
2128c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("salsa20-generic");
213