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