1 // SPDX-License-Identifier: BSD-2-Clause
2 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3 *
4 * LibTomCrypt is a library that provides various cryptographic
5 * algorithms in a highly modular and flexible manner.
6 *
7 * The library is free for all purposes without any express
8 * guarantee it works.
9 */
10 #include "tomcrypt_private.h"
11
12 /**
13 @file sober128_stream.c
14 Implementation of SOBER-128 by Tom St Denis.
15 Based on s128fast.c reference code supplied by Greg Rose of QUALCOMM.
16 */
17
18 #ifdef LTC_SOBER128
19
20 #define __LTC_SOBER128TAB_C__
21 #include "sober128tab.c"
22
23 /* don't change these... */
24 #define N 17
25 #define INITKONST 0x6996c53a /* value of KONST to use during key loading */
26 #define KEYP 15 /* where to insert key words */
27 #define FOLDP 4 /* where to insert non-linear feedback */
28
BYTE2WORD(const unsigned char * b)29 static ulong32 BYTE2WORD(const unsigned char *b)
30 {
31 ulong32 t;
32 LOAD32L(t, b);
33 return t;
34 }
35
XORWORD(ulong32 w,const unsigned char * in,unsigned char * out)36 static void XORWORD(ulong32 w, const unsigned char *in, unsigned char *out)
37 {
38 ulong32 t;
39 LOAD32L(t, in);
40 t ^= w;
41 STORE32L(t, out);
42 }
43
44 /* give correct offset for the current position of the register,
45 * where logically R[0] is at position "zero".
46 */
47 #define OFF(zero, i) (((zero)+(i)) % N)
48
49 /* step the LFSR */
50 /* After stepping, "zero" moves right one place */
51 #define STEP(R,z) \
52 R[OFF(z,0)] = R[OFF(z,15)] ^ R[OFF(z,4)] ^ (R[OFF(z,0)] << 8) ^ Multab[(R[OFF(z,0)] >> 24) & 0xFF];
53
cycle(ulong32 * R)54 static void cycle(ulong32 *R)
55 {
56 ulong32 t;
57 int i;
58
59 STEP(R,0);
60 t = R[0];
61 for (i = 1; i < N; ++i) {
62 R[i-1] = R[i];
63 }
64 R[N-1] = t;
65 }
66
67 /* Return a non-linear function of some parts of the register.
68 */
69 #define NLFUNC(st,z) \
70 { \
71 t = st->R[OFF(z,0)] + st->R[OFF(z,16)]; \
72 t ^= Sbox[(t >> 24) & 0xFF]; \
73 t = RORc(t, 8); \
74 t = ((t + st->R[OFF(z,1)]) ^ st->konst) + st->R[OFF(z,6)]; \
75 t ^= Sbox[(t >> 24) & 0xFF]; \
76 t = t + st->R[OFF(z,13)]; \
77 }
78
nltap(const sober128_state * st)79 static ulong32 nltap(const sober128_state *st)
80 {
81 ulong32 t;
82 NLFUNC(st, 0);
83 return t;
84 }
85
86 /* Save the current register state
87 */
s128_savestate(sober128_state * st)88 static void s128_savestate(sober128_state *st)
89 {
90 int i;
91 for (i = 0; i < N; ++i) {
92 st->initR[i] = st->R[i];
93 }
94 }
95
96 /* initialise to previously saved register state
97 */
s128_reloadstate(sober128_state * st)98 static void s128_reloadstate(sober128_state *st)
99 {
100 int i;
101
102 for (i = 0; i < N; ++i) {
103 st->R[i] = st->initR[i];
104 }
105 }
106
107 /* Initialise "konst"
108 */
s128_genkonst(sober128_state * st)109 static void s128_genkonst(sober128_state *st)
110 {
111 ulong32 newkonst;
112
113 do {
114 cycle(st->R);
115 newkonst = nltap(st);
116 } while ((newkonst & 0xFF000000) == 0);
117 st->konst = newkonst;
118 }
119
120 /* Load key material into the register
121 */
122 #define ADDKEY(k) \
123 st->R[KEYP] += (k);
124
125 #define XORNL(nl) \
126 st->R[FOLDP] ^= (nl);
127
128 /* nonlinear diffusion of register for key */
129 #define DROUND(z) STEP(st->R,z); NLFUNC(st,(z+1)); st->R[OFF((z+1),FOLDP)] ^= t;
s128_diffuse(sober128_state * st)130 static void s128_diffuse(sober128_state *st)
131 {
132 ulong32 t;
133 /* relies on FOLD == N == 17! */
134 DROUND(0);
135 DROUND(1);
136 DROUND(2);
137 DROUND(3);
138 DROUND(4);
139 DROUND(5);
140 DROUND(6);
141 DROUND(7);
142 DROUND(8);
143 DROUND(9);
144 DROUND(10);
145 DROUND(11);
146 DROUND(12);
147 DROUND(13);
148 DROUND(14);
149 DROUND(15);
150 DROUND(16);
151 }
152
153 /**
154 Initialize an Sober128 context (only the key)
155 @param st [out] The destination of the Sober128 state
156 @param key The secret key
157 @param keylen The length of the secret key (octets)
158 @return CRYPT_OK if successful
159 */
sober128_stream_setup(sober128_state * st,const unsigned char * key,unsigned long keylen)160 int sober128_stream_setup(sober128_state *st, const unsigned char *key, unsigned long keylen)
161 {
162 ulong32 i, k;
163
164 LTC_ARGCHK(st != NULL);
165 LTC_ARGCHK(key != NULL);
166 LTC_ARGCHK(keylen > 0);
167
168 /* keylen must be multiple of 4 bytes */
169 if ((keylen & 3) != 0) {
170 return CRYPT_INVALID_KEYSIZE;
171 }
172
173 /* Register initialised to Fibonacci numbers */
174 st->R[0] = 1;
175 st->R[1] = 1;
176 for (i = 2; i < N; ++i) {
177 st->R[i] = st->R[i-1] + st->R[i-2];
178 }
179 st->konst = INITKONST;
180
181 for (i = 0; i < keylen; i += 4) {
182 k = BYTE2WORD((unsigned char *)&key[i]);
183 ADDKEY(k);
184 cycle(st->R);
185 XORNL(nltap(st));
186 }
187
188 /* also fold in the length of the key */
189 ADDKEY(keylen);
190
191 /* now diffuse */
192 s128_diffuse(st);
193 s128_genkonst(st);
194 s128_savestate(st);
195 st->nbuf = 0;
196
197 return CRYPT_OK;
198 }
199
200 /**
201 Set IV to the Sober128 state
202 @param st The Sober12820 state
203 @param iv The IV data to add
204 @param ivlen The length of the IV (must be 12)
205 @return CRYPT_OK on success
206 */
sober128_stream_setiv(sober128_state * st,const unsigned char * iv,unsigned long ivlen)207 int sober128_stream_setiv(sober128_state *st, const unsigned char *iv, unsigned long ivlen)
208 {
209 ulong32 i, k;
210
211 LTC_ARGCHK(st != NULL);
212 LTC_ARGCHK(iv != NULL);
213 LTC_ARGCHK(ivlen > 0);
214
215 /* ok we are adding an IV then... */
216 s128_reloadstate(st);
217
218 /* ivlen must be multiple of 4 bytes */
219 if ((ivlen & 3) != 0) {
220 return CRYPT_INVALID_KEYSIZE;
221 }
222
223 for (i = 0; i < ivlen; i += 4) {
224 k = BYTE2WORD((unsigned char *)&iv[i]);
225 ADDKEY(k);
226 cycle(st->R);
227 XORNL(nltap(st));
228 }
229
230 /* also fold in the length of the key */
231 ADDKEY(ivlen);
232
233 /* now diffuse */
234 s128_diffuse(st);
235 st->nbuf = 0;
236
237 return CRYPT_OK;
238 }
239
240 /* XOR pseudo-random bytes into buffer
241 */
242 #define SROUND(z) STEP(st->R,z); NLFUNC(st,(z+1)); XORWORD(t, in+(z*4), out+(z*4));
243
244 /**
245 Encrypt (or decrypt) bytes of ciphertext (or plaintext) with Sober128
246 @param st The Sober128 state
247 @param in The plaintext (or ciphertext)
248 @param inlen The length of the input (octets)
249 @param out [out] The ciphertext (or plaintext), length inlen
250 @return CRYPT_OK if successful
251 */
sober128_stream_crypt(sober128_state * st,const unsigned char * in,unsigned long inlen,unsigned char * out)252 int sober128_stream_crypt(sober128_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out)
253 {
254 ulong32 t;
255
256 if (inlen == 0) return CRYPT_OK; /* nothing to do */
257 LTC_ARGCHK(out != NULL);
258 LTC_ARGCHK(st != NULL);
259
260 /* handle any previously buffered bytes */
261 while (st->nbuf != 0 && inlen != 0) {
262 *out++ = *in++ ^ (unsigned char)(st->sbuf & 0xFF);
263 st->sbuf >>= 8;
264 st->nbuf -= 8;
265 --inlen;
266 }
267
268 #ifndef LTC_SMALL_CODE
269 /* do lots at a time, if there's enough to do */
270 while (inlen >= N*4) {
271 SROUND(0);
272 SROUND(1);
273 SROUND(2);
274 SROUND(3);
275 SROUND(4);
276 SROUND(5);
277 SROUND(6);
278 SROUND(7);
279 SROUND(8);
280 SROUND(9);
281 SROUND(10);
282 SROUND(11);
283 SROUND(12);
284 SROUND(13);
285 SROUND(14);
286 SROUND(15);
287 SROUND(16);
288 out += 4*N;
289 in += 4*N;
290 inlen -= 4*N;
291 }
292 #endif
293
294 /* do small or odd size buffers the slow way */
295 while (4 <= inlen) {
296 cycle(st->R);
297 t = nltap(st);
298 XORWORD(t, in, out);
299 out += 4;
300 in += 4;
301 inlen -= 4;
302 }
303
304 /* handle any trailing bytes */
305 if (inlen != 0) {
306 cycle(st->R);
307 st->sbuf = nltap(st);
308 st->nbuf = 32;
309 while (st->nbuf != 0 && inlen != 0) {
310 *out++ = *in++ ^ (unsigned char)(st->sbuf & 0xFF);
311 st->sbuf >>= 8;
312 st->nbuf -= 8;
313 --inlen;
314 }
315 }
316
317 return CRYPT_OK;
318 }
319
sober128_stream_keystream(sober128_state * st,unsigned char * out,unsigned long outlen)320 int sober128_stream_keystream(sober128_state *st, unsigned char *out, unsigned long outlen)
321 {
322 if (outlen == 0) return CRYPT_OK; /* nothing to do */
323 LTC_ARGCHK(out != NULL);
324 XMEMSET(out, 0, outlen);
325 return sober128_stream_crypt(st, out, outlen, out);
326 }
327
328 /**
329 Terminate and clear Sober128 state
330 @param st The Sober128 state
331 @return CRYPT_OK on success
332 */
sober128_stream_done(sober128_state * st)333 int sober128_stream_done(sober128_state *st)
334 {
335 LTC_ARGCHK(st != NULL);
336 XMEMSET(st, 0, sizeof(sober128_state));
337 return CRYPT_OK;
338 }
339
340 #endif
341
342 /* ref: $Format:%D$ */
343 /* git commit: $Format:%H$ */
344 /* commit time: $Format:%ai$ */
345