115 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * The "hash function" used as the core of the ChaCha stream cipher (RFC7539)4 *5 * Copyright (C) 2015 Martin Willi6 */7 8#include <linux/bug.h>9#include <linux/kernel.h>10#include <linux/export.h>11#include <linux/bitops.h>12#include <linux/string.h>13#include <linux/unaligned.h>14#include <crypto/chacha.h>15 16static void chacha_permute(u32 *x, int nrounds)17{18 int i;19 20 /* whitelist the allowed round counts */21 WARN_ON_ONCE(nrounds != 20 && nrounds != 12);22 23 for (i = 0; i < nrounds; i += 2) {24 x[0] += x[4]; x[12] = rol32(x[12] ^ x[0], 16);25 x[1] += x[5]; x[13] = rol32(x[13] ^ x[1], 16);26 x[2] += x[6]; x[14] = rol32(x[14] ^ x[2], 16);27 x[3] += x[7]; x[15] = rol32(x[15] ^ x[3], 16);28 29 x[8] += x[12]; x[4] = rol32(x[4] ^ x[8], 12);30 x[9] += x[13]; x[5] = rol32(x[5] ^ x[9], 12);31 x[10] += x[14]; x[6] = rol32(x[6] ^ x[10], 12);32 x[11] += x[15]; x[7] = rol32(x[7] ^ x[11], 12);33 34 x[0] += x[4]; x[12] = rol32(x[12] ^ x[0], 8);35 x[1] += x[5]; x[13] = rol32(x[13] ^ x[1], 8);36 x[2] += x[6]; x[14] = rol32(x[14] ^ x[2], 8);37 x[3] += x[7]; x[15] = rol32(x[15] ^ x[3], 8);38 39 x[8] += x[12]; x[4] = rol32(x[4] ^ x[8], 7);40 x[9] += x[13]; x[5] = rol32(x[5] ^ x[9], 7);41 x[10] += x[14]; x[6] = rol32(x[6] ^ x[10], 7);42 x[11] += x[15]; x[7] = rol32(x[7] ^ x[11], 7);43 44 x[0] += x[5]; x[15] = rol32(x[15] ^ x[0], 16);45 x[1] += x[6]; x[12] = rol32(x[12] ^ x[1], 16);46 x[2] += x[7]; x[13] = rol32(x[13] ^ x[2], 16);47 x[3] += x[4]; x[14] = rol32(x[14] ^ x[3], 16);48 49 x[10] += x[15]; x[5] = rol32(x[5] ^ x[10], 12);50 x[11] += x[12]; x[6] = rol32(x[6] ^ x[11], 12);51 x[8] += x[13]; x[7] = rol32(x[7] ^ x[8], 12);52 x[9] += x[14]; x[4] = rol32(x[4] ^ x[9], 12);53 54 x[0] += x[5]; x[15] = rol32(x[15] ^ x[0], 8);55 x[1] += x[6]; x[12] = rol32(x[12] ^ x[1], 8);56 x[2] += x[7]; x[13] = rol32(x[13] ^ x[2], 8);57 x[3] += x[4]; x[14] = rol32(x[14] ^ x[3], 8);58 59 x[10] += x[15]; x[5] = rol32(x[5] ^ x[10], 7);60 x[11] += x[12]; x[6] = rol32(x[6] ^ x[11], 7);61 x[8] += x[13]; x[7] = rol32(x[7] ^ x[8], 7);62 x[9] += x[14]; x[4] = rol32(x[4] ^ x[9], 7);63 }64}65 66/**67 * chacha_block_generic - generate one keystream block and increment block counter68 * @state: input state matrix (16 32-bit words)69 * @stream: output keystream block (64 bytes)70 * @nrounds: number of rounds (20 or 12; 20 is recommended)71 *72 * This is the ChaCha core, a function from 64-byte strings to 64-byte strings.73 * The caller has already converted the endianness of the input. This function74 * also handles incrementing the block counter in the input matrix.75 */76void chacha_block_generic(u32 *state, u8 *stream, int nrounds)77{78 u32 x[16];79 int i;80 81 memcpy(x, state, 64);82 83 chacha_permute(x, nrounds);84 85 for (i = 0; i < ARRAY_SIZE(x); i++)86 put_unaligned_le32(x[i] + state[i], &stream[i * sizeof(u32)]);87 88 state[12]++;89}90EXPORT_SYMBOL(chacha_block_generic);91 92/**93 * hchacha_block_generic - abbreviated ChaCha core, for XChaCha94 * @state: input state matrix (16 32-bit words)95 * @stream: output (8 32-bit words)96 * @nrounds: number of rounds (20 or 12; 20 is recommended)97 *98 * HChaCha is the ChaCha equivalent of HSalsa and is an intermediate step99 * towards XChaCha (see https://cr.yp.to/snuffle/xsalsa-20081128.pdf). HChaCha100 * skips the final addition of the initial state, and outputs only certain words101 * of the state. It should not be used for streaming directly.102 */103void hchacha_block_generic(const u32 *state, u32 *stream, int nrounds)104{105 u32 x[16];106 107 memcpy(x, state, 64);108 109 chacha_permute(x, nrounds);110 111 memcpy(&stream[0], &x[0], 16);112 memcpy(&stream[4], &x[12], 16);113}114EXPORT_SYMBOL(hchacha_block_generic);115