/src/gnutls/lib/nettle/gost/kuznyechik.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* kuznyechik.c - GOST R 34.12-2015 (Kuznyechik) cipher implementation |
2 | | |
3 | | Copyright: 2017 Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> |
4 | | |
5 | | This file is part of GNU Nettle. |
6 | | |
7 | | GNU Nettle is free software: you can redistribute it and/or |
8 | | modify it under the terms of either: |
9 | | |
10 | | * the GNU Lesser General Public License as published by the Free |
11 | | Software Foundation; either version 3 of the License, or (at your |
12 | | option) any later version. |
13 | | |
14 | | or |
15 | | |
16 | | * the GNU General Public License as published by the Free |
17 | | Software Foundation; either version 2 of the License, or (at your |
18 | | option) any later version. |
19 | | |
20 | | or both in parallel, as here. |
21 | | |
22 | | GNU Nettle is distributed in the hope that it will be useful, |
23 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
24 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
25 | | General Public License for more details. |
26 | | |
27 | | You should have received copies of the GNU General Public License and |
28 | | the GNU Lesser General Public License along with this program. If |
29 | | not, see https://www.gnu.org/licenses/. |
30 | | */ |
31 | | |
32 | | #if HAVE_CONFIG_H |
33 | | #include "config.h" |
34 | | #endif |
35 | | |
36 | | #ifndef HAVE_NETTLE_KUZNYECHIK_SET_KEY |
37 | | |
38 | | #include <assert.h> |
39 | | #include <string.h> |
40 | | |
41 | | #include <nettle/macros.h> |
42 | | #include <nettle/memxor.h> |
43 | | #include "nettle-write.h" |
44 | | #include "kuznyechik.h" |
45 | | |
46 | | #include "kuztable.h" |
47 | | |
48 | | static void S(uint8_t *a, const uint8_t *b) |
49 | 0 | { |
50 | 0 | a[0] = pi[b[0]]; |
51 | 0 | a[1] = pi[b[1]]; |
52 | 0 | a[2] = pi[b[2]]; |
53 | 0 | a[3] = pi[b[3]]; |
54 | 0 | a[4] = pi[b[4]]; |
55 | 0 | a[5] = pi[b[5]]; |
56 | 0 | a[6] = pi[b[6]]; |
57 | 0 | a[7] = pi[b[7]]; |
58 | 0 | a[8] = pi[b[8]]; |
59 | 0 | a[9] = pi[b[9]]; |
60 | 0 | a[10] = pi[b[10]]; |
61 | 0 | a[11] = pi[b[11]]; |
62 | 0 | a[12] = pi[b[12]]; |
63 | 0 | a[13] = pi[b[13]]; |
64 | 0 | a[14] = pi[b[14]]; |
65 | 0 | a[15] = pi[b[15]]; |
66 | 0 | } |
67 | | |
68 | | static void Sinv(uint8_t *a, const uint8_t *b) |
69 | 0 | { |
70 | 0 | a[0] = pi_inv[b[0]]; |
71 | 0 | a[1] = pi_inv[b[1]]; |
72 | 0 | a[2] = pi_inv[b[2]]; |
73 | 0 | a[3] = pi_inv[b[3]]; |
74 | 0 | a[4] = pi_inv[b[4]]; |
75 | 0 | a[5] = pi_inv[b[5]]; |
76 | 0 | a[6] = pi_inv[b[6]]; |
77 | 0 | a[7] = pi_inv[b[7]]; |
78 | 0 | a[8] = pi_inv[b[8]]; |
79 | 0 | a[9] = pi_inv[b[9]]; |
80 | 0 | a[10] = pi_inv[b[10]]; |
81 | 0 | a[11] = pi_inv[b[11]]; |
82 | 0 | a[12] = pi_inv[b[12]]; |
83 | 0 | a[13] = pi_inv[b[13]]; |
84 | 0 | a[14] = pi_inv[b[14]]; |
85 | 0 | a[15] = pi_inv[b[15]]; |
86 | 0 | } |
87 | | |
88 | | static void Linv(uint8_t *a, const uint8_t *b) |
89 | 0 | { |
90 | 0 | memcpy(a, &kuz_table_inv[0][b[0] * 16], KUZNYECHIK_BLOCK_SIZE); |
91 | 0 | memxor(a, &kuz_table_inv[1][b[1] * 16], KUZNYECHIK_BLOCK_SIZE); |
92 | 0 | memxor(a, &kuz_table_inv[2][b[2] * 16], KUZNYECHIK_BLOCK_SIZE); |
93 | 0 | memxor(a, &kuz_table_inv[3][b[3] * 16], KUZNYECHIK_BLOCK_SIZE); |
94 | 0 | memxor(a, &kuz_table_inv[4][b[4] * 16], KUZNYECHIK_BLOCK_SIZE); |
95 | 0 | memxor(a, &kuz_table_inv[5][b[5] * 16], KUZNYECHIK_BLOCK_SIZE); |
96 | 0 | memxor(a, &kuz_table_inv[6][b[6] * 16], KUZNYECHIK_BLOCK_SIZE); |
97 | 0 | memxor(a, &kuz_table_inv[7][b[7] * 16], KUZNYECHIK_BLOCK_SIZE); |
98 | 0 | memxor(a, &kuz_table_inv[8][b[8] * 16], KUZNYECHIK_BLOCK_SIZE); |
99 | 0 | memxor(a, &kuz_table_inv[9][b[9] * 16], KUZNYECHIK_BLOCK_SIZE); |
100 | 0 | memxor(a, &kuz_table_inv[10][b[10] * 16], KUZNYECHIK_BLOCK_SIZE); |
101 | 0 | memxor(a, &kuz_table_inv[11][b[11] * 16], KUZNYECHIK_BLOCK_SIZE); |
102 | 0 | memxor(a, &kuz_table_inv[12][b[12] * 16], KUZNYECHIK_BLOCK_SIZE); |
103 | 0 | memxor(a, &kuz_table_inv[13][b[13] * 16], KUZNYECHIK_BLOCK_SIZE); |
104 | 0 | memxor(a, &kuz_table_inv[14][b[14] * 16], KUZNYECHIK_BLOCK_SIZE); |
105 | 0 | memxor(a, &kuz_table_inv[15][b[15] * 16], KUZNYECHIK_BLOCK_SIZE); |
106 | 0 | } |
107 | | |
108 | | static void LSX(uint8_t *a, const uint8_t *b, const uint8_t *c) |
109 | 0 | { |
110 | 0 | uint8_t t[16]; |
111 | | |
112 | | /* https://github.com/llvm/llvm-project/issues/53518 */ |
113 | | #if defined(__clang_analyzer__) && \ |
114 | | (defined(__clang_major__) && __clang_major__ == 13) |
115 | | assert(0); |
116 | | #else |
117 | 0 | memcpy(t, &kuz_table[0][(b[0] ^ c[0]) * 16], KUZNYECHIK_BLOCK_SIZE); |
118 | 0 | memxor(t, &kuz_table[1][(b[1] ^ c[1]) * 16], KUZNYECHIK_BLOCK_SIZE); |
119 | 0 | memxor(t, &kuz_table[2][(b[2] ^ c[2]) * 16], KUZNYECHIK_BLOCK_SIZE); |
120 | 0 | memxor(t, &kuz_table[3][(b[3] ^ c[3]) * 16], KUZNYECHIK_BLOCK_SIZE); |
121 | 0 | memxor(t, &kuz_table[4][(b[4] ^ c[4]) * 16], KUZNYECHIK_BLOCK_SIZE); |
122 | 0 | memxor(t, &kuz_table[5][(b[5] ^ c[5]) * 16], KUZNYECHIK_BLOCK_SIZE); |
123 | 0 | memxor(t, &kuz_table[6][(b[6] ^ c[6]) * 16], KUZNYECHIK_BLOCK_SIZE); |
124 | 0 | memxor(t, &kuz_table[7][(b[7] ^ c[7]) * 16], KUZNYECHIK_BLOCK_SIZE); |
125 | 0 | memxor(t, &kuz_table[8][(b[8] ^ c[8]) * 16], KUZNYECHIK_BLOCK_SIZE); |
126 | 0 | memxor(t, &kuz_table[9][(b[9] ^ c[9]) * 16], KUZNYECHIK_BLOCK_SIZE); |
127 | 0 | memxor(t, &kuz_table[10][(b[10] ^ c[10]) * 16], KUZNYECHIK_BLOCK_SIZE); |
128 | 0 | memxor(t, &kuz_table[11][(b[11] ^ c[11]) * 16], KUZNYECHIK_BLOCK_SIZE); |
129 | 0 | memxor(t, &kuz_table[12][(b[12] ^ c[12]) * 16], KUZNYECHIK_BLOCK_SIZE); |
130 | 0 | memxor(t, &kuz_table[13][(b[13] ^ c[13]) * 16], KUZNYECHIK_BLOCK_SIZE); |
131 | 0 | memxor(t, &kuz_table[14][(b[14] ^ c[14]) * 16], KUZNYECHIK_BLOCK_SIZE); |
132 | 0 | memxor3(a, t, &kuz_table[15][(b[15] ^ c[15]) * 16], |
133 | 0 | KUZNYECHIK_BLOCK_SIZE); |
134 | 0 | #endif |
135 | 0 | } |
136 | | |
137 | | static void XLiSi(uint8_t *a, const uint8_t *b, const uint8_t *c) |
138 | 0 | { |
139 | 0 | uint8_t t[16]; |
140 | |
|
141 | 0 | memcpy(t, &kuz_table_inv_LS[0][b[0] * 16], KUZNYECHIK_BLOCK_SIZE); |
142 | 0 | memxor(t, &kuz_table_inv_LS[1][b[1] * 16], KUZNYECHIK_BLOCK_SIZE); |
143 | 0 | memxor(t, &kuz_table_inv_LS[2][b[2] * 16], KUZNYECHIK_BLOCK_SIZE); |
144 | 0 | memxor(t, &kuz_table_inv_LS[3][b[3] * 16], KUZNYECHIK_BLOCK_SIZE); |
145 | 0 | memxor(t, &kuz_table_inv_LS[4][b[4] * 16], KUZNYECHIK_BLOCK_SIZE); |
146 | 0 | memxor(t, &kuz_table_inv_LS[5][b[5] * 16], KUZNYECHIK_BLOCK_SIZE); |
147 | 0 | memxor(t, &kuz_table_inv_LS[6][b[6] * 16], KUZNYECHIK_BLOCK_SIZE); |
148 | 0 | memxor(t, &kuz_table_inv_LS[7][b[7] * 16], KUZNYECHIK_BLOCK_SIZE); |
149 | 0 | memxor(t, &kuz_table_inv_LS[8][b[8] * 16], KUZNYECHIK_BLOCK_SIZE); |
150 | 0 | memxor(t, &kuz_table_inv_LS[9][b[9] * 16], KUZNYECHIK_BLOCK_SIZE); |
151 | 0 | memxor(t, &kuz_table_inv_LS[10][b[10] * 16], KUZNYECHIK_BLOCK_SIZE); |
152 | 0 | memxor(t, &kuz_table_inv_LS[11][b[11] * 16], KUZNYECHIK_BLOCK_SIZE); |
153 | 0 | memxor(t, &kuz_table_inv_LS[12][b[12] * 16], KUZNYECHIK_BLOCK_SIZE); |
154 | 0 | memxor(t, &kuz_table_inv_LS[13][b[13] * 16], KUZNYECHIK_BLOCK_SIZE); |
155 | 0 | memxor(t, &kuz_table_inv_LS[14][b[14] * 16], KUZNYECHIK_BLOCK_SIZE); |
156 | 0 | memxor(t, &kuz_table_inv_LS[15][b[15] * 16], KUZNYECHIK_BLOCK_SIZE); |
157 | 0 | memxor3(a, t, c, 16); |
158 | 0 | } |
159 | | |
160 | | static void subkey(uint8_t *out, const uint8_t *key, unsigned i) |
161 | 0 | { |
162 | 0 | uint8_t test[16]; |
163 | |
|
164 | 0 | LSX(test, key + 0, kuz_key_table[i + 0]); |
165 | 0 | memxor3(out + 16, test, key + 16, 16); |
166 | 0 | LSX(test, out + 16, kuz_key_table[i + 1]); |
167 | 0 | memxor3(out + 0, test, key + 0, 16); |
168 | 0 | LSX(test, out + 0, kuz_key_table[i + 2]); |
169 | 0 | memxor(out + 16, test, 16); |
170 | 0 | LSX(test, out + 16, kuz_key_table[i + 3]); |
171 | 0 | memxor(out + 0, test, 16); |
172 | 0 | LSX(test, out + 0, kuz_key_table[i + 4]); |
173 | 0 | memxor(out + 16, test, 16); |
174 | 0 | LSX(test, out + 16, kuz_key_table[i + 5]); |
175 | 0 | memxor(out + 0, test, 16); |
176 | 0 | LSX(test, out + 0, kuz_key_table[i + 6]); |
177 | 0 | memxor(out + 16, test, 16); |
178 | 0 | LSX(test, out + 16, kuz_key_table[i + 7]); |
179 | 0 | memxor(out + 0, test, 16); |
180 | 0 | } |
181 | | |
182 | | void kuznyechik_set_key(struct kuznyechik_ctx *ctx, const uint8_t *key) |
183 | 0 | { |
184 | 0 | unsigned i; |
185 | |
|
186 | 0 | memcpy(ctx->key, key, 32); |
187 | 0 | subkey(ctx->key + 32, ctx->key, 0); |
188 | 0 | subkey(ctx->key + 64, ctx->key + 32, 8); |
189 | 0 | subkey(ctx->key + 96, ctx->key + 64, 16); |
190 | 0 | subkey(ctx->key + 128, ctx->key + 96, 24); |
191 | 0 | for (i = 0; i < 10; i++) |
192 | 0 | Linv(ctx->dekey + 16 * i, ctx->key + 16 * i); |
193 | 0 | } |
194 | | |
195 | | void kuznyechik_encrypt(const struct kuznyechik_ctx *ctx, size_t length, |
196 | | uint8_t *dst, const uint8_t *src) |
197 | 0 | { |
198 | 0 | uint8_t temp[KUZNYECHIK_BLOCK_SIZE]; |
199 | |
|
200 | 0 | assert(!(length % KUZNYECHIK_BLOCK_SIZE)); |
201 | | |
202 | 0 | while (length) { |
203 | 0 | LSX(temp, ctx->key + 16 * 0, src); |
204 | 0 | LSX(temp, ctx->key + 16 * 1, temp); |
205 | 0 | LSX(temp, ctx->key + 16 * 2, temp); |
206 | 0 | LSX(temp, ctx->key + 16 * 3, temp); |
207 | 0 | LSX(temp, ctx->key + 16 * 4, temp); |
208 | 0 | LSX(temp, ctx->key + 16 * 5, temp); |
209 | 0 | LSX(temp, ctx->key + 16 * 6, temp); |
210 | 0 | LSX(temp, ctx->key + 16 * 7, temp); |
211 | 0 | LSX(temp, ctx->key + 16 * 8, temp); |
212 | 0 | memxor3(dst, ctx->key + 16 * 9, temp, 16); |
213 | 0 | src += KUZNYECHIK_BLOCK_SIZE; |
214 | 0 | dst += KUZNYECHIK_BLOCK_SIZE; |
215 | 0 | length -= KUZNYECHIK_BLOCK_SIZE; |
216 | 0 | } |
217 | 0 | } |
218 | | |
219 | | void kuznyechik_decrypt(const struct kuznyechik_ctx *ctx, size_t length, |
220 | | uint8_t *dst, const uint8_t *src) |
221 | 0 | { |
222 | 0 | uint8_t temp[KUZNYECHIK_BLOCK_SIZE]; |
223 | |
|
224 | 0 | assert(!(length % KUZNYECHIK_BLOCK_SIZE)); |
225 | | |
226 | 0 | while (length) { |
227 | 0 | S(temp, src); |
228 | 0 | XLiSi(temp, temp, ctx->dekey + 16 * 9); |
229 | 0 | XLiSi(temp, temp, ctx->dekey + 16 * 8); |
230 | 0 | XLiSi(temp, temp, ctx->dekey + 16 * 7); |
231 | 0 | XLiSi(temp, temp, ctx->dekey + 16 * 6); |
232 | 0 | XLiSi(temp, temp, ctx->dekey + 16 * 5); |
233 | 0 | XLiSi(temp, temp, ctx->dekey + 16 * 4); |
234 | 0 | XLiSi(temp, temp, ctx->dekey + 16 * 3); |
235 | 0 | XLiSi(temp, temp, ctx->dekey + 16 * 2); |
236 | 0 | XLiSi(temp, temp, ctx->dekey + 16 * 1); |
237 | 0 | Sinv(dst, temp); |
238 | 0 | memxor(dst, ctx->key + 16 * 0, 16); |
239 | 0 | src += KUZNYECHIK_BLOCK_SIZE; |
240 | 0 | dst += KUZNYECHIK_BLOCK_SIZE; |
241 | 0 | length -= KUZNYECHIK_BLOCK_SIZE; |
242 | 0 | } |
243 | 0 | } |
244 | | #endif /* HAVE_NETTLE_KUZNYECHIK_SET_KEY */ |