162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Common values and helper functions for the ChaCha and XChaCha stream ciphers.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * XChaCha extends ChaCha's nonce to 192 bits, while provably retaining ChaCha's
662306a36Sopenharmony_ci * security.  Here they share the same key size, tfm context, and setkey
762306a36Sopenharmony_ci * function; only their IV size and encrypt/decrypt function differ.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * The ChaCha paper specifies 20, 12, and 8-round variants.  In general, it is
1062306a36Sopenharmony_ci * recommended to use the 20-round variant ChaCha20.  However, the other
1162306a36Sopenharmony_ci * variants can be needed in some performance-sensitive scenarios.  The generic
1262306a36Sopenharmony_ci * ChaCha code currently allows only the 20 and 12-round variants.
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#ifndef _CRYPTO_CHACHA_H
1662306a36Sopenharmony_ci#define _CRYPTO_CHACHA_H
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <asm/unaligned.h>
1962306a36Sopenharmony_ci#include <linux/types.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/* 32-bit stream position, then 96-bit nonce (RFC7539 convention) */
2262306a36Sopenharmony_ci#define CHACHA_IV_SIZE		16
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define CHACHA_KEY_SIZE		32
2562306a36Sopenharmony_ci#define CHACHA_BLOCK_SIZE	64
2662306a36Sopenharmony_ci#define CHACHAPOLY_IV_SIZE	12
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define CHACHA_STATE_WORDS	(CHACHA_BLOCK_SIZE / sizeof(u32))
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/* 192-bit nonce, then 64-bit stream position */
3162306a36Sopenharmony_ci#define XCHACHA_IV_SIZE		32
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_civoid chacha_block_generic(u32 *state, u8 *stream, int nrounds);
3462306a36Sopenharmony_cistatic inline void chacha20_block(u32 *state, u8 *stream)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	chacha_block_generic(state, stream, 20);
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_civoid hchacha_block_arch(const u32 *state, u32 *out, int nrounds);
4062306a36Sopenharmony_civoid hchacha_block_generic(const u32 *state, u32 *out, int nrounds);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic inline void hchacha_block(const u32 *state, u32 *out, int nrounds)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA))
4562306a36Sopenharmony_ci		hchacha_block_arch(state, out, nrounds);
4662306a36Sopenharmony_ci	else
4762306a36Sopenharmony_ci		hchacha_block_generic(state, out, nrounds);
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cienum chacha_constants { /* expand 32-byte k */
5162306a36Sopenharmony_ci	CHACHA_CONSTANT_EXPA = 0x61707865U,
5262306a36Sopenharmony_ci	CHACHA_CONSTANT_ND_3 = 0x3320646eU,
5362306a36Sopenharmony_ci	CHACHA_CONSTANT_2_BY = 0x79622d32U,
5462306a36Sopenharmony_ci	CHACHA_CONSTANT_TE_K = 0x6b206574U
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic inline void chacha_init_consts(u32 *state)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	state[0]  = CHACHA_CONSTANT_EXPA;
6062306a36Sopenharmony_ci	state[1]  = CHACHA_CONSTANT_ND_3;
6162306a36Sopenharmony_ci	state[2]  = CHACHA_CONSTANT_2_BY;
6262306a36Sopenharmony_ci	state[3]  = CHACHA_CONSTANT_TE_K;
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_civoid chacha_init_arch(u32 *state, const u32 *key, const u8 *iv);
6662306a36Sopenharmony_cistatic inline void chacha_init_generic(u32 *state, const u32 *key, const u8 *iv)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	chacha_init_consts(state);
6962306a36Sopenharmony_ci	state[4]  = key[0];
7062306a36Sopenharmony_ci	state[5]  = key[1];
7162306a36Sopenharmony_ci	state[6]  = key[2];
7262306a36Sopenharmony_ci	state[7]  = key[3];
7362306a36Sopenharmony_ci	state[8]  = key[4];
7462306a36Sopenharmony_ci	state[9]  = key[5];
7562306a36Sopenharmony_ci	state[10] = key[6];
7662306a36Sopenharmony_ci	state[11] = key[7];
7762306a36Sopenharmony_ci	state[12] = get_unaligned_le32(iv +  0);
7862306a36Sopenharmony_ci	state[13] = get_unaligned_le32(iv +  4);
7962306a36Sopenharmony_ci	state[14] = get_unaligned_le32(iv +  8);
8062306a36Sopenharmony_ci	state[15] = get_unaligned_le32(iv + 12);
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic inline void chacha_init(u32 *state, const u32 *key, const u8 *iv)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA))
8662306a36Sopenharmony_ci		chacha_init_arch(state, key, iv);
8762306a36Sopenharmony_ci	else
8862306a36Sopenharmony_ci		chacha_init_generic(state, key, iv);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_civoid chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src,
9262306a36Sopenharmony_ci		       unsigned int bytes, int nrounds);
9362306a36Sopenharmony_civoid chacha_crypt_generic(u32 *state, u8 *dst, const u8 *src,
9462306a36Sopenharmony_ci			  unsigned int bytes, int nrounds);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic inline void chacha_crypt(u32 *state, u8 *dst, const u8 *src,
9762306a36Sopenharmony_ci				unsigned int bytes, int nrounds)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA))
10062306a36Sopenharmony_ci		chacha_crypt_arch(state, dst, src, bytes, nrounds);
10162306a36Sopenharmony_ci	else
10262306a36Sopenharmony_ci		chacha_crypt_generic(state, dst, src, bytes, nrounds);
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic inline void chacha20_crypt(u32 *state, u8 *dst, const u8 *src,
10662306a36Sopenharmony_ci				  unsigned int bytes)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	chacha_crypt(state, dst, src, bytes, 20);
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#endif /* _CRYPTO_CHACHA_H */
112