162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * The "hash function" used as the core of the ChaCha stream cipher (RFC7539) 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2015 Martin Willi 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/bug.h> 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/export.h> 1162306a36Sopenharmony_ci#include <linux/bitops.h> 1262306a36Sopenharmony_ci#include <linux/string.h> 1362306a36Sopenharmony_ci#include <asm/unaligned.h> 1462306a36Sopenharmony_ci#include <crypto/chacha.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic void chacha_permute(u32 *x, int nrounds) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci int i; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci /* whitelist the allowed round counts */ 2162306a36Sopenharmony_ci WARN_ON_ONCE(nrounds != 20 && nrounds != 12); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci for (i = 0; i < nrounds; i += 2) { 2462306a36Sopenharmony_ci x[0] += x[4]; x[12] = rol32(x[12] ^ x[0], 16); 2562306a36Sopenharmony_ci x[1] += x[5]; x[13] = rol32(x[13] ^ x[1], 16); 2662306a36Sopenharmony_ci x[2] += x[6]; x[14] = rol32(x[14] ^ x[2], 16); 2762306a36Sopenharmony_ci x[3] += x[7]; x[15] = rol32(x[15] ^ x[3], 16); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci x[8] += x[12]; x[4] = rol32(x[4] ^ x[8], 12); 3062306a36Sopenharmony_ci x[9] += x[13]; x[5] = rol32(x[5] ^ x[9], 12); 3162306a36Sopenharmony_ci x[10] += x[14]; x[6] = rol32(x[6] ^ x[10], 12); 3262306a36Sopenharmony_ci x[11] += x[15]; x[7] = rol32(x[7] ^ x[11], 12); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci x[0] += x[4]; x[12] = rol32(x[12] ^ x[0], 8); 3562306a36Sopenharmony_ci x[1] += x[5]; x[13] = rol32(x[13] ^ x[1], 8); 3662306a36Sopenharmony_ci x[2] += x[6]; x[14] = rol32(x[14] ^ x[2], 8); 3762306a36Sopenharmony_ci x[3] += x[7]; x[15] = rol32(x[15] ^ x[3], 8); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci x[8] += x[12]; x[4] = rol32(x[4] ^ x[8], 7); 4062306a36Sopenharmony_ci x[9] += x[13]; x[5] = rol32(x[5] ^ x[9], 7); 4162306a36Sopenharmony_ci x[10] += x[14]; x[6] = rol32(x[6] ^ x[10], 7); 4262306a36Sopenharmony_ci x[11] += x[15]; x[7] = rol32(x[7] ^ x[11], 7); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci x[0] += x[5]; x[15] = rol32(x[15] ^ x[0], 16); 4562306a36Sopenharmony_ci x[1] += x[6]; x[12] = rol32(x[12] ^ x[1], 16); 4662306a36Sopenharmony_ci x[2] += x[7]; x[13] = rol32(x[13] ^ x[2], 16); 4762306a36Sopenharmony_ci x[3] += x[4]; x[14] = rol32(x[14] ^ x[3], 16); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci x[10] += x[15]; x[5] = rol32(x[5] ^ x[10], 12); 5062306a36Sopenharmony_ci x[11] += x[12]; x[6] = rol32(x[6] ^ x[11], 12); 5162306a36Sopenharmony_ci x[8] += x[13]; x[7] = rol32(x[7] ^ x[8], 12); 5262306a36Sopenharmony_ci x[9] += x[14]; x[4] = rol32(x[4] ^ x[9], 12); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci x[0] += x[5]; x[15] = rol32(x[15] ^ x[0], 8); 5562306a36Sopenharmony_ci x[1] += x[6]; x[12] = rol32(x[12] ^ x[1], 8); 5662306a36Sopenharmony_ci x[2] += x[7]; x[13] = rol32(x[13] ^ x[2], 8); 5762306a36Sopenharmony_ci x[3] += x[4]; x[14] = rol32(x[14] ^ x[3], 8); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci x[10] += x[15]; x[5] = rol32(x[5] ^ x[10], 7); 6062306a36Sopenharmony_ci x[11] += x[12]; x[6] = rol32(x[6] ^ x[11], 7); 6162306a36Sopenharmony_ci x[8] += x[13]; x[7] = rol32(x[7] ^ x[8], 7); 6262306a36Sopenharmony_ci x[9] += x[14]; x[4] = rol32(x[4] ^ x[9], 7); 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/** 6762306a36Sopenharmony_ci * chacha_block_generic - generate one keystream block and increment block counter 6862306a36Sopenharmony_ci * @state: input state matrix (16 32-bit words) 6962306a36Sopenharmony_ci * @stream: output keystream block (64 bytes) 7062306a36Sopenharmony_ci * @nrounds: number of rounds (20 or 12; 20 is recommended) 7162306a36Sopenharmony_ci * 7262306a36Sopenharmony_ci * This is the ChaCha core, a function from 64-byte strings to 64-byte strings. 7362306a36Sopenharmony_ci * The caller has already converted the endianness of the input. This function 7462306a36Sopenharmony_ci * also handles incrementing the block counter in the input matrix. 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_civoid chacha_block_generic(u32 *state, u8 *stream, int nrounds) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci u32 x[16]; 7962306a36Sopenharmony_ci int i; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci memcpy(x, state, 64); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci chacha_permute(x, nrounds); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(x); i++) 8662306a36Sopenharmony_ci put_unaligned_le32(x[i] + state[i], &stream[i * sizeof(u32)]); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci state[12]++; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ciEXPORT_SYMBOL(chacha_block_generic); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/** 9362306a36Sopenharmony_ci * hchacha_block_generic - abbreviated ChaCha core, for XChaCha 9462306a36Sopenharmony_ci * @state: input state matrix (16 32-bit words) 9562306a36Sopenharmony_ci * @stream: output (8 32-bit words) 9662306a36Sopenharmony_ci * @nrounds: number of rounds (20 or 12; 20 is recommended) 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci * HChaCha is the ChaCha equivalent of HSalsa and is an intermediate step 9962306a36Sopenharmony_ci * towards XChaCha (see https://cr.yp.to/snuffle/xsalsa-20081128.pdf). HChaCha 10062306a36Sopenharmony_ci * skips the final addition of the initial state, and outputs only certain words 10162306a36Sopenharmony_ci * of the state. It should not be used for streaming directly. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_civoid hchacha_block_generic(const u32 *state, u32 *stream, int nrounds) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci u32 x[16]; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci memcpy(x, state, 64); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci chacha_permute(x, nrounds); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci memcpy(&stream[0], &x[0], 16); 11262306a36Sopenharmony_ci memcpy(&stream[4], &x[12], 16); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ciEXPORT_SYMBOL(hchacha_block_generic); 115