qrc_opensource_rs/cipher/
chacha.rs

1/* The AGPL version 3 License (AGPLv3)
2* 
3* Copyright (c) 2021 Digital Freedom Defence Inc.
4* This file is part of the QSC Cryptographic library
5* 
6* This program is free software : you can redistribute it and / or modify
7* it under the terms of the GNU Affero General Public License as published by
8* the Free Software Foundation, either version 3 of the License, or
9* (at your option) any later version.
10* 
11* This program is distributed in the hope that it will be useful,
12* but WITHOUT ANY WARRANTY; without even the implied warranty of
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14* See the GNU Affero General Public License for more details.
15* 
16* You should have received a copy of the GNU Affero General Public License
17* along with this program. If not, see <http://www.gnu.org/licenses/>.
18*
19*
20*
21* Copyright (c) Original-2021 John G. Underhill <john.underhill@mailfence.com>
22* Copyright (c) 2022-Present QRC Eurosmart SA <opensource-support@qrcrypto.ch>
23*
24* The following code is a derivative work of the code from the QSC Cryptographic library in C, 
25* which is licensed AGPLv3. This code therefore is also licensed under the terms of 
26* the GNU Affero General Public License, version 3. The AGPL version 3 License (AGPLv3). */
27
28use crate::tools::intutils::{qrc_intutils_clear32, qrc_intutils_copy8, qrc_intutils_le32to8, qrc_intutils_le8to32, qrc_intutils_rotl32, qrc_intutils_xor};
29
30use core::default::Default;
31
32#[cfg(feature = "no_std")]
33use alloc::vec::Vec;
34
35/*
36* \def QRC_CHACHA_BLOCK_SIZE
37* \brief The internal block size
38*/
39pub const QRC_CHACHA_BLOCK_SIZE: usize = 64;
40
41/*
42* \def QRC_CHACHA_KEY128_SIZE
43* \brief The size of the 128-bit secret key array in bytes
44*/
45pub const QRC_CHACHA_KEY128_SIZE: usize = 16;
46
47/*
48* \def QRC_CHACHA_KEY256_SIZE
49* \brief The size of the 256-bit secret key array in bytes
50*/
51pub const QRC_CHACHA_KEY256_SIZE: usize = 32;
52
53/*
54* \def QRC_CHACHA_NONCE_SIZE
55* \brief The size of the nonce array in bytes
56*/
57pub const QRC_CHACHA_NONCE_SIZE: usize = 8;
58
59/*
60* \def QRC_CHACHA_ROUND_COUNT
61* \brief The number of mixing rounds used by ChaCha
62*/
63pub const QRC_CHACHA_ROUND_COUNT: usize = 20;
64
65/*
66* \struct qrc_chacha_state
67* \brief Internal: contains the qrc_chacha_state state
68*/
69#[derive(Clone)]
70pub struct QrcChachaState {
71	pub state: [u32; 16],	/*< The internal state array */
72}
73impl Default for QrcChachaState{
74    fn default() -> Self {
75        Self {
76            state: [Default::default(); 16],
77        }
78    }
79}
80
81/* 
82* \struct qrc_chacha_keyparams
83* \brief The key parameters structure containing key, and nonce arrays and lengths.
84* Use this structure to load an input cipher-key and nonce using the qrc_chacha_initialize function.
85* Keys must be random and secret, and align to the corresponding key size of the cipher implemented.
86* The key must be QRC_CHACHA_KEY128_SIZE or QRC_CHACHA_KEY256_SIZE in length.
87* The nonce is always QRC_CHACHA_NONCE_SIZE in length.
88*/
89#[derive(Clone)]
90pub struct QrcChachaKeyparams {
91	pub key: Vec<u8>,	/*< The input cipher key */
92	pub keylen: usize,		/*< The length in bytes of the cipher key */
93	pub nonce: Vec<u8>,		/*< The nonce or initialization vector */
94}
95impl Default for QrcChachaKeyparams{
96    fn default() -> Self {
97        Self {
98            key: Default::default(),
99			keylen: Default::default(),
100			nonce: Default::default(),
101        }
102    }
103}
104
105/*
106* \brief Dispose of the ChaCha cipher state.
107*
108* \warning The dispose function must be called when disposing of the cipher.
109* This function destroys internal arrays and data
110*
111* \param ctx: [struct] The cipher state structure
112*/
113pub fn qrc_chacha_dispose(ctx: &mut QrcChachaState) {
114	qrc_intutils_clear32(&mut ctx.state, 16);
115}
116
117/*
118* \brief Initialize the state with the secret key and nonce.
119*
120* \warning The key array must be either 16 or 32 bytes in length
121* \warning The nonce array must be 8 bytes bytes in length
122*
123* \param ctx: [struct] The cipher state structure
124* \param keyparams: [const][struct] The secret key and nonce structure
125*/
126pub fn qrc_chacha_initialize(ctx: &mut QrcChachaState, keyparams: QrcChachaKeyparams) {
127	if keyparams.keylen == 32 {
128		ctx.state[0] = 0x61707865;
129		ctx.state[1] = 0x3320646E;
130		ctx.state[2] = 0x79622D32;
131		ctx.state[3] = 0x6B206574;
132		ctx.state[4] = qrc_intutils_le8to32(&keyparams.key);
133		ctx.state[5] = qrc_intutils_le8to32(&keyparams.key[4..]);
134		ctx.state[6] = qrc_intutils_le8to32(&keyparams.key[8..]);
135		ctx.state[7] = qrc_intutils_le8to32(&keyparams.key[12..]);
136		ctx.state[8] = qrc_intutils_le8to32(&keyparams.key[16..]);
137		ctx.state[9] = qrc_intutils_le8to32(&keyparams.key[20..]);
138		ctx.state[10] = qrc_intutils_le8to32(&keyparams.key[24..]);
139		ctx.state[11] = qrc_intutils_le8to32(&keyparams.key[28..]);
140		ctx.state[12] = 0;
141		ctx.state[13] = 0;
142		ctx.state[14] = qrc_intutils_le8to32(&keyparams.nonce);
143		ctx.state[15] = qrc_intutils_le8to32(&keyparams.nonce[4..]);
144	} else {
145		ctx.state[0] = 0x61707865;
146		ctx.state[1] = 0x3120646E;
147		ctx.state[2] = 0x79622D36;
148		ctx.state[3] = 0x6B206574;
149		ctx.state[4] = qrc_intutils_le8to32(&keyparams.key[0..]);
150		ctx.state[5] = qrc_intutils_le8to32(&keyparams.key[4..]);
151		ctx.state[6] = qrc_intutils_le8to32(&keyparams.key[8..]);
152		ctx.state[7] = qrc_intutils_le8to32(&keyparams.key[12..]);
153		ctx.state[8] = qrc_intutils_le8to32(&keyparams.key[0..]);
154		ctx.state[9] = qrc_intutils_le8to32(&keyparams.key[4..]);
155		ctx.state[10] = qrc_intutils_le8to32(&keyparams.key[8..]);
156		ctx.state[11] = qrc_intutils_le8to32(&keyparams.key[12..]);
157		ctx.state[12] = 0;
158		ctx.state[13] = 0;
159		ctx.state[14] = qrc_intutils_le8to32(&keyparams.nonce);
160		ctx.state[15] = qrc_intutils_le8to32(&keyparams.nonce[4..]);
161	}
162}
163
164/*
165* \brief Transform a length of input text.
166*
167* \param ctx: [struct] The cipher state structure
168* \param output: A pointer to the output byte array
169* \param input: [const] A pointer to the input byte array
170* \param length: The number of bytes to process
171*/
172pub fn qrc_chacha_transform(ctx: &mut QrcChachaState, output: &mut [u8], input: &[u8], mut length: usize) {
173	let mut oft = 0;
174
175	if length != 0 {
176		while length >= QRC_CHACHA_BLOCK_SIZE {
177			chacha_permute_p512c(ctx.clone(), &mut output[oft..]);
178			chacha_increment(ctx);
179			qrc_intutils_xor(&mut output[oft..], &input[oft..], QRC_CHACHA_BLOCK_SIZE);
180			oft += QRC_CHACHA_BLOCK_SIZE;
181			length -= QRC_CHACHA_BLOCK_SIZE;
182		}
183
184		if length != 0	{
185			let tmp = &mut [0u8; QRC_CHACHA_BLOCK_SIZE];
186			chacha_permute_p512c(ctx.clone(), tmp);
187			chacha_increment(ctx);
188			qrc_intutils_copy8(&mut output[oft..], tmp, length);
189
190			for i in oft..oft + length {
191				output[i] ^= input[i];
192			}
193		}
194	}
195}
196
197//const CHACHA_STATE_SIZE: usize = 16;
198
199fn chacha_increment(ctx: &mut QrcChachaState) {
200	ctx.state[12] = ctx.state[12].wrapping_add(1);
201
202	if ctx.state[12] == 0 {
203		ctx.state[13] =  ctx.state[13].wrapping_add(1);
204	}
205}
206
207fn chacha_permute_p512c(ctx: QrcChachaState, output: &mut [u8]) {
208	let mut x0 = ctx.state[0];
209	let mut x1 = ctx.state[1];
210	let mut x2 = ctx.state[2];
211	let mut x3 = ctx.state[3];
212	let mut x4 = ctx.state[4];
213	let mut x5 = ctx.state[5];
214	let mut x6 = ctx.state[6];
215	let mut x7 = ctx.state[7];
216	let mut x8 = ctx.state[8];
217	let mut x9 = ctx.state[9];
218	let mut x10 = ctx.state[10];
219	let mut x11 = ctx.state[11];
220	let mut x12 = ctx.state[12];
221	let mut x13 = ctx.state[13];
222	let mut x14 = ctx.state[14];
223	let mut x15 = ctx.state[15];
224	let mut ctr = QRC_CHACHA_ROUND_COUNT;
225
226	while ctr != 0 {
227		x0 = x0.wrapping_add(x4);
228		x12 = qrc_intutils_rotl32(x12 ^ x0, 16);
229		x8 = x8.wrapping_add(x12);
230		x4 = qrc_intutils_rotl32(x4 ^ x8, 12);
231		x0 = x0.wrapping_add(x4);
232		x12 = qrc_intutils_rotl32(x12 ^ x0, 8);
233		x8 = x8.wrapping_add(x12);
234		x4 = qrc_intutils_rotl32(x4 ^ x8, 7);
235		x1 = x1.wrapping_add(x5);
236		x13 = qrc_intutils_rotl32(x13 ^ x1, 16);
237		x9 = x9.wrapping_add(x13);
238		x5 = qrc_intutils_rotl32(x5 ^ x9, 12);
239		x1 = x1.wrapping_add(x5);
240		x13 = qrc_intutils_rotl32(x13 ^ x1, 8);
241		x9 = x9.wrapping_add(x13);
242		x5 = qrc_intutils_rotl32(x5 ^ x9, 7);
243		x2 = x2.wrapping_add(x6);
244		x14 = qrc_intutils_rotl32(x14 ^ x2, 16);
245		x10 = x10.wrapping_add(x14);
246		x6 = qrc_intutils_rotl32(x6 ^ x10, 12);
247		x2 = x2.wrapping_add(x6);
248		x14 = qrc_intutils_rotl32(x14 ^ x2, 8);
249		x10 = x10.wrapping_add(x14);
250		x6 = qrc_intutils_rotl32(x6 ^ x10, 7);
251		x3 = x3.wrapping_add(x7);
252		x15 = qrc_intutils_rotl32(x15 ^ x3, 16);
253		x11 = x11.wrapping_add(x15);
254		x7 = qrc_intutils_rotl32(x7 ^ x11, 12);
255		x3 = x3.wrapping_add(x7);
256		x15 = qrc_intutils_rotl32(x15 ^ x3, 8);
257		x11 = x11.wrapping_add(x15);
258		x7 = qrc_intutils_rotl32(x7 ^ x11, 7);
259		x0 = x0.wrapping_add(x5);
260		x15 = qrc_intutils_rotl32(x15 ^ x0, 16);
261		x10 = x10.wrapping_add(x15);
262		x5 = qrc_intutils_rotl32(x5 ^ x10, 12);
263		x0 = x0.wrapping_add(x5);
264		x15 = qrc_intutils_rotl32(x15 ^ x0, 8);
265		x10 = x10.wrapping_add(x15);
266		x5 = qrc_intutils_rotl32(x5 ^ x10, 7);
267		x1 = x1.wrapping_add(x6);
268		x12 = qrc_intutils_rotl32(x12 ^ x1, 16);
269		x11 = x11.wrapping_add(x12);
270		x6 = qrc_intutils_rotl32(x6 ^ x11, 12);
271		x1 = x1.wrapping_add(x6);
272		x12 = qrc_intutils_rotl32(x12 ^ x1, 8);
273		x11 = x11.wrapping_add(x12);
274		x6 = qrc_intutils_rotl32(x6 ^ x11, 7);
275		x2 = x2.wrapping_add(x7);
276		x13 = qrc_intutils_rotl32(x13 ^ x2, 16);
277		x8 = x8.wrapping_add(x13);
278		x7 = qrc_intutils_rotl32(x7 ^ x8, 12);
279		x2 = x2.wrapping_add(x7);
280		x13 = qrc_intutils_rotl32(x13 ^ x2, 8);
281		x8 = x8.wrapping_add(x13);
282		x7 = qrc_intutils_rotl32(x7 ^ x8, 7);
283		x3 = x3.wrapping_add(x4);
284		x14 = qrc_intutils_rotl32(x14 ^ x3, 16);
285		x9 = x9.wrapping_add(x14);
286		x4 = qrc_intutils_rotl32(x4 ^ x9, 12);
287		x3 = x3.wrapping_add(x4);
288		x14 = qrc_intutils_rotl32(x14 ^ x3, 8);
289		x9 = x9.wrapping_add(x14);
290		x4 = qrc_intutils_rotl32(x4 ^ x9, 7);
291		ctr -= 2;
292	}
293
294	qrc_intutils_le32to8(output, x0.wrapping_add(ctx.state[0]));
295	qrc_intutils_le32to8(&mut output[4..], x1.wrapping_add(ctx.state[1]));
296	qrc_intutils_le32to8(&mut output[8..], x2.wrapping_add(ctx.state[2]));
297	qrc_intutils_le32to8(&mut output[12..], x3.wrapping_add(ctx.state[3]));
298	qrc_intutils_le32to8(&mut output[16..], x4.wrapping_add(ctx.state[4]));
299	qrc_intutils_le32to8(&mut output[20..], x5.wrapping_add(ctx.state[5]));
300	qrc_intutils_le32to8(&mut output[24..], x6.wrapping_add(ctx.state[6]));
301	qrc_intutils_le32to8(&mut output[28..], x7.wrapping_add(ctx.state[7]));
302	qrc_intutils_le32to8(&mut output[32..], x8.wrapping_add(ctx.state[8]));
303	qrc_intutils_le32to8(&mut output[36..], x9.wrapping_add(ctx.state[9]));
304	qrc_intutils_le32to8(&mut output[40..], x10.wrapping_add(ctx.state[10]));
305	qrc_intutils_le32to8(&mut output[44..], x11.wrapping_add(ctx.state[11]));
306	qrc_intutils_le32to8(&mut output[48..], x12.wrapping_add(ctx.state[12]));
307	qrc_intutils_le32to8(&mut output[52..], x13.wrapping_add(ctx.state[13]));
308	qrc_intutils_le32to8(&mut output[56..], x14.wrapping_add(ctx.state[14]));
309	qrc_intutils_le32to8(&mut output[60..], x15.wrapping_add(ctx.state[15]));
310}