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