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