xref: /optee_os/core/lib/libtomcrypt/src/prngs/sober128.c (revision 8411e6ad673d20c4742ed30c785e3f5cdea54dfa)
1*8411e6adSJerome Forissier /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2*8411e6adSJerome Forissier /* SPDX-License-Identifier: Unlicense */
35a913ee7SJerome Forissier 
45a913ee7SJerome Forissier #include "tomcrypt_private.h"
55a913ee7SJerome Forissier 
65a913ee7SJerome Forissier /**
75a913ee7SJerome Forissier  @file prngs/sober128.c
85a913ee7SJerome Forissier  Implementation of SOBER-128 by Tom St Denis.
95a913ee7SJerome Forissier  Based on s128fast.c reference code supplied by Greg Rose of QUALCOMM.
105a913ee7SJerome Forissier */
115a913ee7SJerome Forissier 
125a913ee7SJerome Forissier #ifdef LTC_SOBER128
135a913ee7SJerome Forissier 
145a913ee7SJerome Forissier const struct ltc_prng_descriptor sober128_desc =
155a913ee7SJerome Forissier {
165a913ee7SJerome Forissier    "sober128",
175a913ee7SJerome Forissier    40,
185a913ee7SJerome Forissier    &sober128_start,
195a913ee7SJerome Forissier    &sober128_add_entropy,
205a913ee7SJerome Forissier    &sober128_ready,
215a913ee7SJerome Forissier    &sober128_read,
225a913ee7SJerome Forissier    &sober128_done,
235a913ee7SJerome Forissier    &sober128_export,
245a913ee7SJerome Forissier    &sober128_import,
255a913ee7SJerome Forissier    &sober128_test
265a913ee7SJerome Forissier };
275a913ee7SJerome Forissier 
285a913ee7SJerome Forissier /**
295a913ee7SJerome Forissier   Start the PRNG
305a913ee7SJerome Forissier   @param prng     [out] The PRNG state to initialize
315a913ee7SJerome Forissier   @return CRYPT_OK if successful
325a913ee7SJerome Forissier */
sober128_start(prng_state * prng)335a913ee7SJerome Forissier int sober128_start(prng_state *prng)
345a913ee7SJerome Forissier {
355a913ee7SJerome Forissier    LTC_ARGCHK(prng != NULL);
365a913ee7SJerome Forissier    prng->ready = 0;
375a913ee7SJerome Forissier    XMEMSET(&prng->u.sober128.ent, 0, sizeof(prng->u.sober128.ent));
385a913ee7SJerome Forissier    prng->u.sober128.idx = 0;
395a913ee7SJerome Forissier    LTC_MUTEX_INIT(&prng->lock)
405a913ee7SJerome Forissier    return CRYPT_OK;
415a913ee7SJerome Forissier }
425a913ee7SJerome Forissier 
435a913ee7SJerome Forissier /**
445a913ee7SJerome Forissier   Add entropy to the PRNG state
455a913ee7SJerome Forissier   @param in       The data to add
465a913ee7SJerome Forissier   @param inlen    Length of the data to add
475a913ee7SJerome Forissier   @param prng     PRNG state to update
485a913ee7SJerome Forissier   @return CRYPT_OK if successful
495a913ee7SJerome Forissier */
sober128_add_entropy(const unsigned char * in,unsigned long inlen,prng_state * prng)505a913ee7SJerome Forissier int sober128_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
515a913ee7SJerome Forissier {
525a913ee7SJerome Forissier    unsigned char buf[40];
535a913ee7SJerome Forissier    unsigned long i;
545a913ee7SJerome Forissier    int err;
555a913ee7SJerome Forissier 
565a913ee7SJerome Forissier    LTC_ARGCHK(prng != NULL);
575a913ee7SJerome Forissier    LTC_ARGCHK(in != NULL);
585a913ee7SJerome Forissier    LTC_ARGCHK(inlen > 0);
595a913ee7SJerome Forissier 
605a913ee7SJerome Forissier    LTC_MUTEX_LOCK(&prng->lock);
615a913ee7SJerome Forissier    if (prng->ready) {
625a913ee7SJerome Forissier       /* sober128_ready() was already called, do "rekey" operation */
635a913ee7SJerome Forissier       if ((err = sober128_stream_keystream(&prng->u.sober128.s, buf, sizeof(buf))) != CRYPT_OK) goto LBL_UNLOCK;
645a913ee7SJerome Forissier       for(i = 0; i < inlen; i++) buf[i % sizeof(buf)] ^= in[i];
655a913ee7SJerome Forissier       /* key 32 bytes, 20 rounds */
665a913ee7SJerome Forissier       if ((err = sober128_stream_setup(&prng->u.sober128.s, buf, 32)) != CRYPT_OK)     goto LBL_UNLOCK;
675a913ee7SJerome Forissier       /* iv 8 bytes */
685a913ee7SJerome Forissier       if ((err = sober128_stream_setiv(&prng->u.sober128.s, buf + 32, 8)) != CRYPT_OK) goto LBL_UNLOCK;
695a913ee7SJerome Forissier       /* clear KEY + IV */
705a913ee7SJerome Forissier       zeromem(buf, sizeof(buf));
715a913ee7SJerome Forissier    }
725a913ee7SJerome Forissier    else {
735a913ee7SJerome Forissier       /* sober128_ready() was not called yet, add entropy to ent buffer */
745a913ee7SJerome Forissier       while (inlen--) prng->u.sober128.ent[prng->u.sober128.idx++ % sizeof(prng->u.sober128.ent)] ^= *in++;
755a913ee7SJerome Forissier    }
765a913ee7SJerome Forissier    err = CRYPT_OK;
775a913ee7SJerome Forissier LBL_UNLOCK:
785a913ee7SJerome Forissier    LTC_MUTEX_UNLOCK(&prng->lock);
795a913ee7SJerome Forissier    return err;
805a913ee7SJerome Forissier }
815a913ee7SJerome Forissier 
825a913ee7SJerome Forissier /**
835a913ee7SJerome Forissier   Make the PRNG ready to read from
845a913ee7SJerome Forissier   @param prng   The PRNG to make active
855a913ee7SJerome Forissier   @return CRYPT_OK if successful
865a913ee7SJerome Forissier */
sober128_ready(prng_state * prng)875a913ee7SJerome Forissier int sober128_ready(prng_state *prng)
885a913ee7SJerome Forissier {
895a913ee7SJerome Forissier    int err;
905a913ee7SJerome Forissier 
915a913ee7SJerome Forissier    LTC_ARGCHK(prng != NULL);
925a913ee7SJerome Forissier 
935a913ee7SJerome Forissier    LTC_MUTEX_LOCK(&prng->lock);
945a913ee7SJerome Forissier    if (prng->ready)                                                            { err = CRYPT_OK; goto LBL_UNLOCK; }
955a913ee7SJerome Forissier    /* key 32 bytes, 20 rounds */
965a913ee7SJerome Forissier    if ((err = sober128_stream_setup(&prng->u.sober128.s, prng->u.sober128.ent, 32)) != CRYPT_OK)     goto LBL_UNLOCK;
975a913ee7SJerome Forissier    /* iv 8 bytes */
985a913ee7SJerome Forissier    if ((err = sober128_stream_setiv(&prng->u.sober128.s, prng->u.sober128.ent + 32, 8)) != CRYPT_OK) goto LBL_UNLOCK;
995a913ee7SJerome Forissier    XMEMSET(&prng->u.sober128.ent, 0, sizeof(prng->u.sober128.ent));
1005a913ee7SJerome Forissier    prng->u.sober128.idx = 0;
1015a913ee7SJerome Forissier    prng->ready = 1;
1025a913ee7SJerome Forissier LBL_UNLOCK:
1035a913ee7SJerome Forissier    LTC_MUTEX_UNLOCK(&prng->lock);
1045a913ee7SJerome Forissier    return err;
1055a913ee7SJerome Forissier }
1065a913ee7SJerome Forissier 
1075a913ee7SJerome Forissier /**
1085a913ee7SJerome Forissier   Read from the PRNG
1095a913ee7SJerome Forissier   @param out      Destination
1105a913ee7SJerome Forissier   @param outlen   Length of output
1115a913ee7SJerome Forissier   @param prng     The active PRNG to read from
1125a913ee7SJerome Forissier   @return Number of octets read
1135a913ee7SJerome Forissier */
sober128_read(unsigned char * out,unsigned long outlen,prng_state * prng)1145a913ee7SJerome Forissier unsigned long sober128_read(unsigned char *out, unsigned long outlen, prng_state *prng)
1155a913ee7SJerome Forissier {
1165a913ee7SJerome Forissier    if (outlen == 0 || prng == NULL || out == NULL) return 0;
1175a913ee7SJerome Forissier    LTC_MUTEX_LOCK(&prng->lock);
1185a913ee7SJerome Forissier    if (!prng->ready) { outlen = 0; goto LBL_UNLOCK; }
1195a913ee7SJerome Forissier    if (sober128_stream_keystream(&prng->u.sober128.s, out, outlen) != CRYPT_OK) outlen = 0;
1205a913ee7SJerome Forissier LBL_UNLOCK:
1215a913ee7SJerome Forissier    LTC_MUTEX_UNLOCK(&prng->lock);
1225a913ee7SJerome Forissier    return outlen;
1235a913ee7SJerome Forissier }
1245a913ee7SJerome Forissier 
1255a913ee7SJerome Forissier /**
1265a913ee7SJerome Forissier   Terminate the PRNG
1275a913ee7SJerome Forissier   @param prng   The PRNG to terminate
1285a913ee7SJerome Forissier   @return CRYPT_OK if successful
1295a913ee7SJerome Forissier */
sober128_done(prng_state * prng)1305a913ee7SJerome Forissier int sober128_done(prng_state *prng)
1315a913ee7SJerome Forissier {
1325a913ee7SJerome Forissier    int err;
1335a913ee7SJerome Forissier    LTC_ARGCHK(prng != NULL);
1345a913ee7SJerome Forissier    LTC_MUTEX_LOCK(&prng->lock);
1355a913ee7SJerome Forissier    prng->ready = 0;
1365a913ee7SJerome Forissier    err = sober128_stream_done(&prng->u.sober128.s);
1375a913ee7SJerome Forissier    LTC_MUTEX_UNLOCK(&prng->lock);
1385a913ee7SJerome Forissier    LTC_MUTEX_DESTROY(&prng->lock);
1395a913ee7SJerome Forissier    return err;
1405a913ee7SJerome Forissier }
1415a913ee7SJerome Forissier 
1425a913ee7SJerome Forissier /**
1435a913ee7SJerome Forissier   Export the PRNG state
1445a913ee7SJerome Forissier   @param out       [out] Destination
1455a913ee7SJerome Forissier   @param outlen    [in/out] Max size and resulting size of the state
1465a913ee7SJerome Forissier   @param prng      The PRNG to export
1475a913ee7SJerome Forissier   @return CRYPT_OK if successful
1485a913ee7SJerome Forissier */
LTC_PRNG_EXPORT(sober128)149*8411e6adSJerome Forissier LTC_PRNG_EXPORT(sober128)
1505a913ee7SJerome Forissier 
1515a913ee7SJerome Forissier /**
1525a913ee7SJerome Forissier   Import a PRNG state
1535a913ee7SJerome Forissier   @param in       The PRNG state
1545a913ee7SJerome Forissier   @param inlen    Size of the state
1555a913ee7SJerome Forissier   @param prng     The PRNG to import
1565a913ee7SJerome Forissier   @return CRYPT_OK if successful
1575a913ee7SJerome Forissier */
1585a913ee7SJerome Forissier int sober128_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
1595a913ee7SJerome Forissier {
1605a913ee7SJerome Forissier    int err;
1615a913ee7SJerome Forissier 
1625a913ee7SJerome Forissier    LTC_ARGCHK(prng != NULL);
1635a913ee7SJerome Forissier    LTC_ARGCHK(in   != NULL);
1645a913ee7SJerome Forissier    if (inlen < (unsigned long)sober128_desc.export_size) return CRYPT_INVALID_ARG;
1655a913ee7SJerome Forissier 
1665a913ee7SJerome Forissier    if ((err = sober128_start(prng)) != CRYPT_OK) return err;
1675a913ee7SJerome Forissier    if ((err = sober128_add_entropy(in, inlen, prng)) != CRYPT_OK) return err;
1685a913ee7SJerome Forissier    return CRYPT_OK;
1695a913ee7SJerome Forissier }
1705a913ee7SJerome Forissier 
1715a913ee7SJerome Forissier /**
1725a913ee7SJerome Forissier   PRNG self-test
1735a913ee7SJerome Forissier   @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
1745a913ee7SJerome Forissier */
sober128_test(void)1755a913ee7SJerome Forissier int sober128_test(void)
1765a913ee7SJerome Forissier {
1775a913ee7SJerome Forissier #ifndef LTC_TEST
1785a913ee7SJerome Forissier    return CRYPT_NOP;
1795a913ee7SJerome Forissier #else
1805a913ee7SJerome Forissier    prng_state st;
1815a913ee7SJerome Forissier    unsigned char en[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
1825a913ee7SJerome Forissier                           0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
1835a913ee7SJerome Forissier                           0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
1845a913ee7SJerome Forissier                           0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
1855a913ee7SJerome Forissier                           0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32 };
1865a913ee7SJerome Forissier    unsigned char dmp[300];
1875a913ee7SJerome Forissier    unsigned long dmplen = sizeof(dmp);
1885a913ee7SJerome Forissier    unsigned char out[500];
1895a913ee7SJerome Forissier    unsigned char t1[] = { 0x31, 0x82, 0xA7, 0xA5, 0x8B, 0xD7, 0xCB, 0x39, 0x86, 0x1A };
1905a913ee7SJerome Forissier    unsigned char t2[] = { 0x6B, 0x43, 0x9E, 0xBC, 0xE7, 0x62, 0x9B, 0xE6, 0x9B, 0x83 };
1915a913ee7SJerome Forissier    unsigned char t3[] = { 0x4A, 0x0E, 0x6C, 0xC1, 0xCF, 0xB4, 0x73, 0x49, 0x99, 0x05 };
1925a913ee7SJerome Forissier    int err;
1935a913ee7SJerome Forissier 
1945a913ee7SJerome Forissier    if ((err = sober128_start(&st)) != CRYPT_OK)                         return err;
1955a913ee7SJerome Forissier    /* add entropy to uninitialized prng */
1965a913ee7SJerome Forissier    if ((err = sober128_add_entropy(en, sizeof(en), &st)) != CRYPT_OK)   return err;
1975a913ee7SJerome Forissier    if ((err = sober128_ready(&st)) != CRYPT_OK)                         return err;
1985a913ee7SJerome Forissier    if (sober128_read(out, 10, &st) != 10)                               return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
1995a913ee7SJerome Forissier    if (compare_testvector(out, 10, t1, sizeof(t1), "SOBER128-PRNG", 1)) return CRYPT_FAIL_TESTVECTOR;
2005a913ee7SJerome Forissier    if (sober128_read(out, 500, &st) != 500)                             return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
2015a913ee7SJerome Forissier    /* add entropy to already initialized prng */
2025a913ee7SJerome Forissier    if ((err = sober128_add_entropy(en, sizeof(en), &st)) != CRYPT_OK)   return err;
2035a913ee7SJerome Forissier    if (sober128_read(out, 500, &st) != 500)                             return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
2045a913ee7SJerome Forissier    if ((err = sober128_export(dmp, &dmplen, &st)) != CRYPT_OK)          return err;
2055a913ee7SJerome Forissier    if (sober128_read(out, 500, &st) != 500)                             return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
2065a913ee7SJerome Forissier    if (sober128_read(out, 10, &st) != 10)                               return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
2075a913ee7SJerome Forissier    if (compare_testvector(out, 10, t2, sizeof(t2), "SOBER128-PRNG", 2)) return CRYPT_FAIL_TESTVECTOR;
2085a913ee7SJerome Forissier    if ((err = sober128_done(&st)) != CRYPT_OK)                          return err;
2095a913ee7SJerome Forissier    if ((err = sober128_import(dmp, dmplen, &st)) != CRYPT_OK)           return err;
2105a913ee7SJerome Forissier    if ((err = sober128_ready(&st)) != CRYPT_OK)                         return err;
2115a913ee7SJerome Forissier    if (sober128_read(out, 500, &st) != 500)                             return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
2125a913ee7SJerome Forissier    if (sober128_read(out, 10, &st) != 10)                               return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
2135a913ee7SJerome Forissier    if (compare_testvector(out, 10, t3, sizeof(t3), "SOBER128-PRNG", 3)) return CRYPT_FAIL_TESTVECTOR;
2145a913ee7SJerome Forissier    if ((err = sober128_done(&st)) != CRYPT_OK)                          return err;
2155a913ee7SJerome Forissier 
2165a913ee7SJerome Forissier    return CRYPT_OK;
2175a913ee7SJerome Forissier #endif
2185a913ee7SJerome Forissier }
2195a913ee7SJerome Forissier 
2205a913ee7SJerome Forissier #endif
221