1/* LibTomCrypt, modular cryptographic library -- Tom St Denis 2 * 3 * LibTomCrypt is a library that provides various cryptographic 4 * algorithms in a highly modular and flexible manner. 5 * 6 * The library is free for all purposes without any express 7 * guarantee it works. 8 * 9 * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com 10 */ 11#include "tomcrypt.h" 12 13/** 14 @file sober128.c 15 Implementation of SOBER-128 by Tom St Denis. 16 Based on s128fast.c reference code supplied by Greg Rose of QUALCOMM. 17*/ 18 19#ifdef SOBER128 20 21#include "sober128tab.c" 22 23const struct ltc_prng_descriptor sober128_desc = 24{ 25 "sober128", 64, 26 &sober128_start, 27 &sober128_add_entropy, 28 &sober128_ready, 29 &sober128_read, 30 &sober128_done, 31 &sober128_export, 32 &sober128_import, 33 &sober128_test 34}; 35 36/* don't change these... */ 37#define N 17 38#define FOLD N /* how many iterations of folding to do */ 39#define INITKONST 0x6996c53a /* value of KONST to use during key loading */ 40#define KEYP 15 /* where to insert key words */ 41#define FOLDP 4 /* where to insert non-linear feedback */ 42 43#define B(x,i) ((unsigned char)(((x) >> (8*i)) & 0xFF)) 44 45static ulong32 BYTE2WORD(unsigned char *b) 46{ 47 ulong32 t; 48 LOAD32L(t, b); 49 return t; 50} 51 52#define WORD2BYTE(w, b) STORE32L(b, w) 53 54static void XORWORD(ulong32 w, unsigned char *b) 55{ 56 ulong32 t; 57 LOAD32L(t, b); 58 t ^= w; 59 STORE32L(t, b); 60} 61 62/* give correct offset for the current position of the register, 63 * where logically R[0] is at position "zero". 64 */ 65#define OFF(zero, i) (((zero)+(i)) % N) 66 67/* step the LFSR */ 68/* After stepping, "zero" moves right one place */ 69#define STEP(R,z) \ 70 R[OFF(z,0)] = R[OFF(z,15)] ^ R[OFF(z,4)] ^ (R[OFF(z,0)] << 8) ^ Multab[(R[OFF(z,0)] >> 24) & 0xFF]; 71 72static void cycle(ulong32 *R) 73{ 74 ulong32 t; 75 int i; 76 77 STEP(R,0); 78 t = R[0]; 79 for (i = 1; i < N; ++i) { 80 R[i-1] = R[i]; 81 } 82 R[N-1] = t; 83} 84 85/* Return a non-linear function of some parts of the register. 86 */ 87#define NLFUNC(c,z) \ 88{ \ 89 t = c->R[OFF(z,0)] + c->R[OFF(z,16)]; \ 90 t ^= Sbox[(t >> 24) & 0xFF]; \ 91 t = RORc(t, 8); \ 92 t = ((t + c->R[OFF(z,1)]) ^ c->konst) + c->R[OFF(z,6)]; \ 93 t ^= Sbox[(t >> 24) & 0xFF]; \ 94 t = t + c->R[OFF(z,13)]; \ 95} 96 97static ulong32 nltap(struct sober128_prng *c) 98{ 99 ulong32 t; 100 NLFUNC(c, 0); 101 return t; 102} 103 104/** 105 Start the PRNG 106 @param prng [out] The PRNG state to initialize 107 @return CRYPT_OK if successful 108*/ 109int sober128_start(prng_state *prng) 110{ 111 int i; 112 struct sober128_prng *c; 113 114 LTC_ARGCHK(prng != NULL); 115 116 c = &(prng->sober128); 117 118 /* Register initialised to Fibonacci numbers */ 119 c->R[0] = 1; 120 c->R[1] = 1; 121 for (i = 2; i < N; ++i) { 122 c->R[i] = c->R[i-1] + c->R[i-2]; 123 } 124 c->konst = INITKONST; 125 126 /* next add_entropy will be the key */ 127 c->flag = 1; 128 c->set = 0; 129 130 return CRYPT_OK; 131} 132 133/* Save the current register state 134 */ 135static void s128_savestate(struct sober128_prng *c) 136{ 137 int i; 138 for (i = 0; i < N; ++i) { 139 c->initR[i] = c->R[i]; 140 } 141} 142 143/* initialise to previously saved register state 144 */ 145static void s128_reloadstate(struct sober128_prng *c) 146{ 147 int i; 148 149 for (i = 0; i < N; ++i) { 150 c->R[i] = c->initR[i]; 151 } 152} 153 154/* Initialise "konst" 155 */ 156static void s128_genkonst(struct sober128_prng *c) 157{ 158 ulong32 newkonst; 159 160 do { 161 cycle(c->R); 162 newkonst = nltap(c); 163 } while ((newkonst & 0xFF000000) == 0); 164 c->konst = newkonst; 165} 166 167/* Load key material into the register 168 */ 169#define ADDKEY(k) \ 170 c->R[KEYP] += (k); 171 172#define XORNL(nl) \ 173 c->R[FOLDP] ^= (nl); 174 175/* nonlinear diffusion of register for key */ 176#define DROUND(z) STEP(c->R,z); NLFUNC(c,(z+1)); c->R[OFF((z+1),FOLDP)] ^= t; 177static void s128_diffuse(struct sober128_prng *c) 178{ 179 ulong32 t; 180 /* relies on FOLD == N == 17! */ 181 DROUND(0); 182 DROUND(1); 183 DROUND(2); 184 DROUND(3); 185 DROUND(4); 186 DROUND(5); 187 DROUND(6); 188 DROUND(7); 189 DROUND(8); 190 DROUND(9); 191 DROUND(10); 192 DROUND(11); 193 DROUND(12); 194 DROUND(13); 195 DROUND(14); 196 DROUND(15); 197 DROUND(16); 198} 199 200/** 201 Add entropy to the PRNG state 202 @param in The data to add 203 @param inlen Length of the data to add 204 @param prng PRNG state to update 205 @return CRYPT_OK if successful 206*/ 207int sober128_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng) 208{ 209 struct sober128_prng *c; 210 ulong32 i, k; 211 212 LTC_ARGCHK(in != NULL); 213 LTC_ARGCHK(prng != NULL); 214 c = &(prng->sober128); 215 216 if (c->flag == 1) { 217 /* this is the first call to the add_entropy so this input is the key */ 218 /* inlen must be multiple of 4 bytes */ 219 if ((inlen & 3) != 0) { 220 return CRYPT_INVALID_KEYSIZE; 221 } 222 223 for (i = 0; i < inlen; i += 4) { 224 k = BYTE2WORD((unsigned char *)&in[i]); 225 ADDKEY(k); 226 cycle(c->R); 227 XORNL(nltap(c)); 228 } 229 230 /* also fold in the length of the key */ 231 ADDKEY(inlen); 232 233 /* now diffuse */ 234 s128_diffuse(c); 235 236 s128_genkonst(c); 237 s128_savestate(c); 238 c->nbuf = 0; 239 c->flag = 0; 240 c->set = 1; 241 } else { 242 /* ok we are adding an IV then... */ 243 s128_reloadstate(c); 244 245 /* inlen must be multiple of 4 bytes */ 246 if ((inlen & 3) != 0) { 247 return CRYPT_INVALID_KEYSIZE; 248 } 249 250 for (i = 0; i < inlen; i += 4) { 251 k = BYTE2WORD((unsigned char *)&in[i]); 252 ADDKEY(k); 253 cycle(c->R); 254 XORNL(nltap(c)); 255 } 256 257 /* also fold in the length of the key */ 258 ADDKEY(inlen); 259 260 /* now diffuse */ 261 s128_diffuse(c); 262 c->nbuf = 0; 263 } 264 265 return CRYPT_OK; 266} 267 268/** 269 Make the PRNG ready to read from 270 @param prng The PRNG to make active 271 @return CRYPT_OK if successful 272*/ 273int sober128_ready(prng_state *prng) 274{ 275 return prng->sober128.set == 1 ? CRYPT_OK : CRYPT_ERROR; 276} 277 278/* XOR pseudo-random bytes into buffer 279 */ 280#define SROUND(z) STEP(c->R,z); NLFUNC(c,(z+1)); XORWORD(t, out+(z*4)); 281 282/** 283 Read from the PRNG 284 @param out Destination 285 @param outlen Length of output 286 @param prng The active PRNG to read from 287 @return Number of octets read 288*/ 289unsigned long sober128_read(unsigned char *out, unsigned long outlen, prng_state *prng) 290{ 291 struct sober128_prng *c; 292 ulong32 t, tlen; 293 294 LTC_ARGCHK(out != NULL); 295 LTC_ARGCHK(prng != NULL); 296 297#ifdef LTC_VALGRIND 298 zeromem(out, outlen); 299#endif 300 301 c = &(prng->sober128); 302 t = 0; 303 tlen = outlen; 304 305 /* handle any previously buffered bytes */ 306 while (c->nbuf != 0 && outlen != 0) { 307 *out++ ^= c->sbuf & 0xFF; 308 c->sbuf >>= 8; 309 c->nbuf -= 8; 310 --outlen; 311 } 312 313#ifndef LTC_SMALL_CODE 314 /* do lots at a time, if there's enough to do */ 315 while (outlen >= N*4) { 316 SROUND(0); 317 SROUND(1); 318 SROUND(2); 319 SROUND(3); 320 SROUND(4); 321 SROUND(5); 322 SROUND(6); 323 SROUND(7); 324 SROUND(8); 325 SROUND(9); 326 SROUND(10); 327 SROUND(11); 328 SROUND(12); 329 SROUND(13); 330 SROUND(14); 331 SROUND(15); 332 SROUND(16); 333 out += 4*N; 334 outlen -= 4*N; 335 } 336#endif 337 338 /* do small or odd size buffers the slow way */ 339 while (4 <= outlen) { 340 cycle(c->R); 341 t = nltap(c); 342 XORWORD(t, out); 343 out += 4; 344 outlen -= 4; 345 } 346 347 /* handle any trailing bytes */ 348 if (outlen != 0) { 349 cycle(c->R); 350 c->sbuf = nltap(c); 351 c->nbuf = 32; 352 while (c->nbuf != 0 && outlen != 0) { 353 *out++ ^= c->sbuf & 0xFF; 354 c->sbuf >>= 8; 355 c->nbuf -= 8; 356 --outlen; 357 } 358 } 359 360 return tlen; 361} 362 363/** 364 Terminate the PRNG 365 @param prng The PRNG to terminate 366 @return CRYPT_OK if successful 367*/ 368int sober128_done(prng_state *prng) 369{ 370 LTC_ARGCHK(prng != NULL); 371 return CRYPT_OK; 372} 373 374/** 375 Export the PRNG state 376 @param out [out] Destination 377 @param outlen [in/out] Max size and resulting size of the state 378 @param prng The PRNG to export 379 @return CRYPT_OK if successful 380*/ 381int sober128_export(unsigned char *out, unsigned long *outlen, prng_state *prng) 382{ 383 LTC_ARGCHK(outlen != NULL); 384 LTC_ARGCHK(out != NULL); 385 LTC_ARGCHK(prng != NULL); 386 387 if (*outlen < 64) { 388 *outlen = 64; 389 return CRYPT_BUFFER_OVERFLOW; 390 } 391 392 if (sober128_read(out, 64, prng) != 64) { 393 return CRYPT_ERROR_READPRNG; 394 } 395 *outlen = 64; 396 397 return CRYPT_OK; 398} 399 400/** 401 Import a PRNG state 402 @param in The PRNG state 403 @param inlen Size of the state 404 @param prng The PRNG to import 405 @return CRYPT_OK if successful 406*/ 407int sober128_import(const unsigned char *in, unsigned long inlen, prng_state *prng) 408{ 409 int err; 410 LTC_ARGCHK(in != NULL); 411 LTC_ARGCHK(prng != NULL); 412 413 if (inlen != 64) { 414 return CRYPT_INVALID_ARG; 415 } 416 417 if ((err = sober128_start(prng)) != CRYPT_OK) { 418 return err; 419 } 420 if ((err = sober128_add_entropy(in, 64, prng)) != CRYPT_OK) { 421 return err; 422 } 423 return sober128_ready(prng); 424} 425 426/** 427 PRNG self-test 428 @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled 429*/ 430int sober128_test(void) 431{ 432#ifndef LTC_TEST 433 return CRYPT_NOP; 434#else 435 static const struct { 436 int keylen, ivlen, len; 437 unsigned char key[16], iv[4], out[20]; 438 } tests[] = { 439 440{ 441 16, 4, 20, 442 443 /* key */ 444 { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6b, 0x65, 0x79, 445 0x20, 0x31, 0x32, 0x38, 0x62, 0x69, 0x74, 0x73 }, 446 447 /* IV */ 448 { 0x00, 0x00, 0x00, 0x00 }, 449 450 /* expected output */ 451 { 0x43, 0x50, 0x0c, 0xcf, 0x89, 0x91, 0x9f, 0x1d, 452 0xaa, 0x37, 0x74, 0x95, 0xf4, 0xb4, 0x58, 0xc2, 453 0x40, 0x37, 0x8b, 0xbb } 454} 455 456}; 457 prng_state prng; 458 unsigned char dst[20]; 459 int err, x; 460 461 for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) { 462 if ((err = sober128_start(&prng)) != CRYPT_OK) { 463 return err; 464 } 465 if ((err = sober128_add_entropy(tests[x].key, tests[x].keylen, &prng)) != CRYPT_OK) { 466 return err; 467 } 468 /* add IV */ 469 if ((err = sober128_add_entropy(tests[x].iv, tests[x].ivlen, &prng)) != CRYPT_OK) { 470 return err; 471 } 472 473 /* ready up */ 474 if ((err = sober128_ready(&prng)) != CRYPT_OK) { 475 return err; 476 } 477 XMEMSET(dst, 0, tests[x].len); 478 if (sober128_read(dst, tests[x].len, &prng) != (unsigned long)tests[x].len) { 479 return CRYPT_ERROR_READPRNG; 480 } 481 sober128_done(&prng); 482 if (XMEMCMP(dst, tests[x].out, tests[x].len)) { 483#if 0 484 printf("\n\nSOBER128 failed, I got:\n"); 485 for (y = 0; y < tests[x].len; y++) printf("%02x ", dst[y]); 486 printf("\n"); 487#endif 488 return CRYPT_FAIL_TESTVECTOR; 489 } 490 } 491 return CRYPT_OK; 492#endif 493} 494 495#endif 496 497 498/* $Source: /cvs/libtom/libtomcrypt/src/prngs/sober128.c,v $ */ 499/* $Revision: 1.8 $ */ 500/* $Date: 2006/11/05 00:11:36 $ */ 501