Home | History | Annotate | Download | only in prngs
      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 (at) 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 
     23 const 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 
     45 static 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 
     54 static 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 
     72 static 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 
     97 static 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 */
    109 int 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  */
    135 static 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  */
    145 static 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  */
    156 static 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;
    177 static 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 */
    207 int 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 */
    273 int 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 */
    289 unsigned 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 */
    368 int 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 */
    381 int 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 */
    407 int 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 */
    430 int 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