1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */ 2 /* SPDX-License-Identifier: Unlicense */ 3 4 #include "tomcrypt_private.h" 5 6 /** 7 @file prngs/sober128.c 8 Implementation of SOBER-128 by Tom St Denis. 9 Based on s128fast.c reference code supplied by Greg Rose of QUALCOMM. 10 */ 11 12 #ifdef LTC_SOBER128 13 14 const struct ltc_prng_descriptor sober128_desc = 15 { 16 "sober128", 17 40, 18 &sober128_start, 19 &sober128_add_entropy, 20 &sober128_ready, 21 &sober128_read, 22 &sober128_done, 23 &sober128_export, 24 &sober128_import, 25 &sober128_test 26 }; 27 28 /** 29 Start the PRNG 30 @param prng [out] The PRNG state to initialize 31 @return CRYPT_OK if successful 32 */ 33 int sober128_start(prng_state *prng) 34 { 35 LTC_ARGCHK(prng != NULL); 36 prng->ready = 0; 37 XMEMSET(&prng->u.sober128.ent, 0, sizeof(prng->u.sober128.ent)); 38 prng->u.sober128.idx = 0; 39 LTC_MUTEX_INIT(&prng->lock) 40 return CRYPT_OK; 41 } 42 43 /** 44 Add entropy to the PRNG state 45 @param in The data to add 46 @param inlen Length of the data to add 47 @param prng PRNG state to update 48 @return CRYPT_OK if successful 49 */ 50 int sober128_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng) 51 { 52 unsigned char buf[40]; 53 unsigned long i; 54 int err; 55 56 LTC_ARGCHK(prng != NULL); 57 LTC_ARGCHK(in != NULL); 58 LTC_ARGCHK(inlen > 0); 59 60 LTC_MUTEX_LOCK(&prng->lock); 61 if (prng->ready) { 62 /* sober128_ready() was already called, do "rekey" operation */ 63 if ((err = sober128_stream_keystream(&prng->u.sober128.s, buf, sizeof(buf))) != CRYPT_OK) goto LBL_UNLOCK; 64 for(i = 0; i < inlen; i++) buf[i % sizeof(buf)] ^= in[i]; 65 /* key 32 bytes, 20 rounds */ 66 if ((err = sober128_stream_setup(&prng->u.sober128.s, buf, 32)) != CRYPT_OK) goto LBL_UNLOCK; 67 /* iv 8 bytes */ 68 if ((err = sober128_stream_setiv(&prng->u.sober128.s, buf + 32, 8)) != CRYPT_OK) goto LBL_UNLOCK; 69 /* clear KEY + IV */ 70 zeromem(buf, sizeof(buf)); 71 } 72 else { 73 /* sober128_ready() was not called yet, add entropy to ent buffer */ 74 while (inlen--) prng->u.sober128.ent[prng->u.sober128.idx++ % sizeof(prng->u.sober128.ent)] ^= *in++; 75 } 76 err = CRYPT_OK; 77 LBL_UNLOCK: 78 LTC_MUTEX_UNLOCK(&prng->lock); 79 return err; 80 } 81 82 /** 83 Make the PRNG ready to read from 84 @param prng The PRNG to make active 85 @return CRYPT_OK if successful 86 */ 87 int sober128_ready(prng_state *prng) 88 { 89 int err; 90 91 LTC_ARGCHK(prng != NULL); 92 93 LTC_MUTEX_LOCK(&prng->lock); 94 if (prng->ready) { err = CRYPT_OK; goto LBL_UNLOCK; } 95 /* key 32 bytes, 20 rounds */ 96 if ((err = sober128_stream_setup(&prng->u.sober128.s, prng->u.sober128.ent, 32)) != CRYPT_OK) goto LBL_UNLOCK; 97 /* iv 8 bytes */ 98 if ((err = sober128_stream_setiv(&prng->u.sober128.s, prng->u.sober128.ent + 32, 8)) != CRYPT_OK) goto LBL_UNLOCK; 99 XMEMSET(&prng->u.sober128.ent, 0, sizeof(prng->u.sober128.ent)); 100 prng->u.sober128.idx = 0; 101 prng->ready = 1; 102 LBL_UNLOCK: 103 LTC_MUTEX_UNLOCK(&prng->lock); 104 return err; 105 } 106 107 /** 108 Read from the PRNG 109 @param out Destination 110 @param outlen Length of output 111 @param prng The active PRNG to read from 112 @return Number of octets read 113 */ 114 unsigned long sober128_read(unsigned char *out, unsigned long outlen, prng_state *prng) 115 { 116 if (outlen == 0 || prng == NULL || out == NULL) return 0; 117 LTC_MUTEX_LOCK(&prng->lock); 118 if (!prng->ready) { outlen = 0; goto LBL_UNLOCK; } 119 if (sober128_stream_keystream(&prng->u.sober128.s, out, outlen) != CRYPT_OK) outlen = 0; 120 LBL_UNLOCK: 121 LTC_MUTEX_UNLOCK(&prng->lock); 122 return outlen; 123 } 124 125 /** 126 Terminate the PRNG 127 @param prng The PRNG to terminate 128 @return CRYPT_OK if successful 129 */ 130 int sober128_done(prng_state *prng) 131 { 132 int err; 133 LTC_ARGCHK(prng != NULL); 134 LTC_MUTEX_LOCK(&prng->lock); 135 prng->ready = 0; 136 err = sober128_stream_done(&prng->u.sober128.s); 137 LTC_MUTEX_UNLOCK(&prng->lock); 138 LTC_MUTEX_DESTROY(&prng->lock); 139 return err; 140 } 141 142 /** 143 Export the PRNG state 144 @param out [out] Destination 145 @param outlen [in/out] Max size and resulting size of the state 146 @param prng The PRNG to export 147 @return CRYPT_OK if successful 148 */ 149 LTC_PRNG_EXPORT(sober128) 150 151 /** 152 Import a PRNG state 153 @param in The PRNG state 154 @param inlen Size of the state 155 @param prng The PRNG to import 156 @return CRYPT_OK if successful 157 */ 158 int sober128_import(const unsigned char *in, unsigned long inlen, prng_state *prng) 159 { 160 int err; 161 162 LTC_ARGCHK(prng != NULL); 163 LTC_ARGCHK(in != NULL); 164 if (inlen < (unsigned long)sober128_desc.export_size) return CRYPT_INVALID_ARG; 165 166 if ((err = sober128_start(prng)) != CRYPT_OK) return err; 167 if ((err = sober128_add_entropy(in, inlen, prng)) != CRYPT_OK) return err; 168 return CRYPT_OK; 169 } 170 171 /** 172 PRNG self-test 173 @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled 174 */ 175 int sober128_test(void) 176 { 177 #ifndef LTC_TEST 178 return CRYPT_NOP; 179 #else 180 prng_state st; 181 unsigned char en[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 182 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 183 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 184 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 185 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32 }; 186 unsigned char dmp[300]; 187 unsigned long dmplen = sizeof(dmp); 188 unsigned char out[500]; 189 unsigned char t1[] = { 0x31, 0x82, 0xA7, 0xA5, 0x8B, 0xD7, 0xCB, 0x39, 0x86, 0x1A }; 190 unsigned char t2[] = { 0x6B, 0x43, 0x9E, 0xBC, 0xE7, 0x62, 0x9B, 0xE6, 0x9B, 0x83 }; 191 unsigned char t3[] = { 0x4A, 0x0E, 0x6C, 0xC1, 0xCF, 0xB4, 0x73, 0x49, 0x99, 0x05 }; 192 int err; 193 194 if ((err = sober128_start(&st)) != CRYPT_OK) return err; 195 /* add entropy to uninitialized prng */ 196 if ((err = sober128_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err; 197 if ((err = sober128_ready(&st)) != CRYPT_OK) return err; 198 if (sober128_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */ 199 if (compare_testvector(out, 10, t1, sizeof(t1), "SOBER128-PRNG", 1)) return CRYPT_FAIL_TESTVECTOR; 200 if (sober128_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ 201 /* add entropy to already initialized prng */ 202 if ((err = sober128_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err; 203 if (sober128_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ 204 if ((err = sober128_export(dmp, &dmplen, &st)) != CRYPT_OK) return err; 205 if (sober128_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ 206 if (sober128_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */ 207 if (compare_testvector(out, 10, t2, sizeof(t2), "SOBER128-PRNG", 2)) return CRYPT_FAIL_TESTVECTOR; 208 if ((err = sober128_done(&st)) != CRYPT_OK) return err; 209 if ((err = sober128_import(dmp, dmplen, &st)) != CRYPT_OK) return err; 210 if ((err = sober128_ready(&st)) != CRYPT_OK) return err; 211 if (sober128_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ 212 if (sober128_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */ 213 if (compare_testvector(out, 10, t3, sizeof(t3), "SOBER128-PRNG", 3)) return CRYPT_FAIL_TESTVECTOR; 214 if ((err = sober128_done(&st)) != CRYPT_OK) return err; 215 216 return CRYPT_OK; 217 #endif 218 } 219 220 #endif 221