1/*
2 * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25#include "inner.h"
26
27/* see bearssl_block.h */
28uint32_t
29br_chacha20_ct_run(const void *key,
30	const void *iv, uint32_t cc, void *data, size_t len)
31{
32	unsigned char *buf;
33	uint32_t kw[8], ivw[3];
34	size_t u;
35
36	static const uint32_t CW[] = {
37		0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
38	};
39
40	buf = data;
41	for (u = 0; u < 8; u ++) {
42		kw[u] = br_dec32le((const unsigned char *)key + (u << 2));
43	}
44	for (u = 0; u < 3; u ++) {
45		ivw[u] = br_dec32le((const unsigned char *)iv + (u << 2));
46	}
47	while (len > 0) {
48		uint32_t state[16];
49		int i;
50		size_t clen;
51		unsigned char tmp[64];
52
53		memcpy(&state[0], CW, sizeof CW);
54		memcpy(&state[4], kw, sizeof kw);
55		state[12] = cc;
56		memcpy(&state[13], ivw, sizeof ivw);
57		for (i = 0; i < 10; i ++) {
58
59#define QROUND(a, b, c, d)   do { \
60		state[a] += state[b]; \
61		state[d] ^= state[a]; \
62		state[d] = (state[d] << 16) | (state[d] >> 16); \
63		state[c] += state[d]; \
64		state[b] ^= state[c]; \
65		state[b] = (state[b] << 12) | (state[b] >> 20); \
66		state[a] += state[b]; \
67		state[d] ^= state[a]; \
68		state[d] = (state[d] <<  8) | (state[d] >> 24); \
69		state[c] += state[d]; \
70		state[b] ^= state[c]; \
71		state[b] = (state[b] <<  7) | (state[b] >> 25); \
72	} while (0)
73
74			QROUND( 0,  4,  8, 12);
75			QROUND( 1,  5,  9, 13);
76			QROUND( 2,  6, 10, 14);
77			QROUND( 3,  7, 11, 15);
78			QROUND( 0,  5, 10, 15);
79			QROUND( 1,  6, 11, 12);
80			QROUND( 2,  7,  8, 13);
81			QROUND( 3,  4,  9, 14);
82
83#undef QROUND
84
85		}
86		for (u = 0; u < 4; u ++) {
87			br_enc32le(&tmp[u << 2], state[u] + CW[u]);
88		}
89		for (u = 4; u < 12; u ++) {
90			br_enc32le(&tmp[u << 2], state[u] + kw[u - 4]);
91		}
92		br_enc32le(&tmp[48], state[12] + cc);
93		for (u = 13; u < 16; u ++) {
94			br_enc32le(&tmp[u << 2], state[u] + ivw[u - 13]);
95		}
96
97		clen = len < 64 ? len : 64;
98		for (u = 0; u < clen; u ++) {
99			buf[u] ^= tmp[u];
100		}
101		buf += clen;
102		len -= clen;
103		cc ++;
104	}
105	return cc;
106}
107