diff options
Diffstat (limited to '3rd_party/libsrp6a-sha512/t_misc.c')
-rw-r--r-- | 3rd_party/libsrp6a-sha512/t_misc.c | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/3rd_party/libsrp6a-sha512/t_misc.c b/3rd_party/libsrp6a-sha512/t_misc.c new file mode 100644 index 0000000..3a2cda1 --- /dev/null +++ b/3rd_party/libsrp6a-sha512/t_misc.c @@ -0,0 +1,439 @@ +/* + * Copyright (c) 1997-2007 The Stanford SRP Authentication Project + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF + * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Redistributions in source or binary form must retain an intact copy + * of this copyright notice. + */ + +#include "t_defines.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#ifdef WIN32 +#include <process.h> +#include <io.h> +#endif + +#include "t_sha.h" + +#ifndef NULL +#define NULL 0 +#endif + +#ifdef OPENSSL +#include <openssl/opensslv.h> +#include <openssl/rand.h> +#elif defined(TOMCRYPT) +#include "tomcrypt.h" +static prng_state g_rng; +static unsigned char entropy[32]; +#elif defined(CRYPTOLIB) +# include "libcrypt.h" +static unsigned char crpool[64]; +#else +static unsigned char randpool[SHA_DIGESTSIZE], randout[SHA_DIGESTSIZE]; +static unsigned long randcnt = 0; +static unsigned int outpos = 0; +SHA1_CTX randctxt; +#endif /* OPENSSL */ + +/* + * t_envhash - Generate a 160-bit SHA hash of the environment + * + * This routine performs an SHA hash of all the "name=value" pairs + * in the environment concatenated together and dumps them in the + * output. While it is true that anyone on the system can see + * your environment, someone not on the system will have a very + * difficult time guessing it, especially since some systems play + * tricks with variable ordering and sometimes define quirky + * environment variables like $WINDOWID or $_. + */ +extern char ** environ; + +static void +t_envhash(unsigned char * out) +{ + char ** ptr; + char ebuf[256]; + SHA1_CTX ctxt; + + SHA1Init(&ctxt); + for(ptr = environ; *ptr; ++ptr) { + strncpy(ebuf, *ptr, 255); + ebuf[255] = '\0'; + SHA1Update(&ctxt, ebuf, strlen(ebuf)); + } + SHA1Final(out, &ctxt); +} + +/* + * t_fshash - Generate a 160-bit SHA hash from the file system + * + * This routine climbs up the directory tree from the current + * directory, running stat() on each directory until it hits the + * root directory. This information is sensitive to the last + * access/modification times of all the directories above you, + * so someone who lists one of those directories injects some + * entropy into the system. Obviously, this hash is very sensitive + * to your current directory when the program is run. + * + * For good measure, it also performs an fstat on the standard input, + * usually your tty, throws that into the buffer, creates a file in + * /tmp (the inode is unpredictable on a busy system), and runs stat() + * on that before deleting it. + * + * The entire buffer is run once through SHA to obtain the final result. + */ +static void +t_fshash(unsigned char * out) +{ + char dotpath[128]; + struct stat st; + SHA1_CTX ctxt; + int i, pinode; + dev_t pdev; + + SHA1Init(&ctxt); + if(stat(".", &st) >= 0) { + SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st)); + pinode = st.st_ino; + pdev = st.st_dev; + strcpy(dotpath, ".."); + for(i = 0; i < 40; ++i) { + if(stat(dotpath, &st) < 0) + break; + if(st.st_ino == pinode && st.st_dev == pdev) + break; + SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st)); + pinode = st.st_ino; + pdev = st.st_dev; + strcat(dotpath, "/.."); + } + } + + if(fstat(0, &st) >= 0) + SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st)); + + sprintf(dotpath, "/tmp/rnd.%d", getpid()); + if(creat(dotpath, 0600) >= 0 && stat(dotpath, &st) >= 0) + SHA1Update(&ctxt, (unsigned char *) &st, sizeof(st)); + unlink(dotpath); + + SHA1Final(out, &ctxt); +} + +/* + * Generate a high-entropy seed for the strong random number generator. + * This uses a wide variety of quickly gathered and somewhat unpredictable + * system information. The 'preseed' structure is assembled from: + * + * The system time in seconds + * The system time in microseconds + * The current process ID + * The parent process ID + * A hash of the user's environment + * A hash gathered from the file system + * Input from a random device, if available + * Timings of system interrupts + * + * The entire structure (60 bytes on most systems) is fed to SHA to produce + * a 160-bit seed for the strong random number generator. It is believed + * that in the worst case (on a quiet system with no random device versus + * an attacker who has access to the system already), the seed contains at + * least about 80 bits of entropy. Versus an attacker who does not have + * access to the system, the entropy should be slightly over 128 bits. + */ +static char initialized = 0; + +static struct { + unsigned int trand1; + time_t sec; + time_t subsec; + short pid; + short ppid; + unsigned char envh[SHA_DIGESTSIZE]; + unsigned char fsh[SHA_DIGESTSIZE]; + unsigned char devrand[20]; + unsigned int trand2; +} preseed; + +unsigned long raw_truerand(); + +static void +t_initrand() +{ + SHA1_CTX ctxt; +#ifdef USE_FTIME + struct timeb t; +#else + struct timeval t; +#endif + int i, r=0; + + if(initialized) + return; + + initialized = 1; + +#if defined(OPENSSL) /* OpenSSL has nifty win32 entropy-gathering code */ +#if OPENSSL_VERSION_NUMBER >= 0x00905100 + r = RAND_status(); +#if defined(WINDOWS) || defined(WIN32) + if(r) /* Don't do the Unix-y stuff on Windows if possible */ + return; +#else +#endif +#endif + +#elif defined(TOMCRYPT) + yarrow_start(&g_rng); + r = rng_get_bytes(entropy, sizeof(entropy), NULL); + if(r > 0) { + yarrow_add_entropy(entropy, r, &g_rng); + memset(entropy, 0, sizeof(entropy)); +# if defined(WINDOWS) || defined(WIN32) + /* Don't do the Unix-y stuff on Windows if possible */ + yarrow_ready(&g_rng); + return; +# endif + } +#endif + +#if !defined(WINDOWS) && !defined(WIN32) + i = open("/dev/urandom", O_RDONLY); + if(i > 0) { + r += read(i, preseed.devrand, sizeof(preseed.devrand)); + close(i); + } +#endif /* !WINDOWS && !WIN32 */ + + /* Resort to truerand only if desperate for some Real entropy */ + if(r == 0) + preseed.trand1 = raw_truerand(); + +#ifdef USE_FTIME + ftime(&t); + preseed.sec = t.time; + preseed.subsec = t.millitm; +#else + gettimeofday(&t, NULL); + preseed.sec = t.tv_sec; + preseed.subsec = t.tv_usec; +#endif + preseed.pid = getpid(); +#ifndef WIN32 + preseed.ppid = getppid(); +#endif + t_envhash(preseed.envh); + t_fshash(preseed.fsh); + + if(r == 0) + preseed.trand2 = raw_truerand(); + +#ifdef OPENSSL + RAND_seed((unsigned char *)&preseed, sizeof(preseed)); +#elif defined(TOMCRYPT) + yarrow_add_entropy((unsigned char *)&preseed, sizeof(preseed), &g_rng); + yarrow_ready(&g_rng); +#elif defined(CRYPTOLIB) + t_mgf1(crpool, sizeof(crpool), (unsigned char *) &preseed, sizeof(preseed)); + seedDesRandom(crpool, sizeof(crpool)); + memset(crpool, 0, sizeof(crpool)); +#elif defined(GCRYPT) + gcry_random_add_bytes((unsigned char *)&preseed, sizeof(preseed), -1); +#else + SHA1Init(&ctxt); + SHA1Update(&ctxt, (unsigned char *) &preseed, sizeof(preseed)); + SHA1Final(randpool, &ctxt); + memset((unsigned char *) &ctxt, 0, sizeof(ctxt)); + outpos = 0; +#endif /* OPENSSL */ + memset((unsigned char *) &preseed, 0, sizeof(preseed)); +} + +#define NUM_RANDOMS 12 + +_TYPE( void ) +t_stronginitrand() +{ +#if 1 /* t_initrand() has been improved enough to make this unnecessary */ + t_initrand(); +#else + SHA1_CTX ctxt; + unsigned int rawrand[NUM_RANDOMS]; + int i; + + if(!initialized) + t_initrand(); + for(i = 0; i < NUM_RANDOMS; ++i) + rawrand[i] = raw_truerand(); + SHA1Init(&ctxt); + SHA1Update(&ctxt, (unsigned char *) rawrand, sizeof(rawrand)); + SHA1Final(randkey2, &ctxt); + memset(rawrand, 0, sizeof(rawrand)); +#endif +} + +/* + * The strong random number generator. This uses a 160-bit seed + * and uses SHA-1 in a feedback configuration to generate successive + * outputs. If S[0] is set to the initial seed, then: + * + * S[i+1] = SHA-1(i || S[i]) + * A[i] = SHA-1(S[i]) + * + * where the A[i] are the output blocks starting with i=0. + * Each cycle generates 20 bytes of new output. + */ +_TYPE( void ) +t_random(unsigned char * data, unsigned size) +{ + if(!initialized) + t_initrand(); + + if(size <= 0) /* t_random(NULL, 0) forces seed initialization */ + return; + +#ifdef OPENSSL + RAND_bytes(data, size); +#elif defined(TOMCRYPT) + yarrow_read(data, size, &g_rng); +#elif defined(GCRYPT) + gcry_randomize(data, size, GCRY_STRONG_RANDOM); +#elif defined(CRYPTOLIB) + randomBytes(data, size, PSEUDO); +#else + while(size > outpos) { + if(outpos > 0) { + memcpy(data, randout + (sizeof(randout) - outpos), outpos); + data += outpos; + size -= outpos; + } + + /* Recycle */ + SHA1Init(&randctxt); + SHA1Update(&randctxt, randpool, sizeof(randpool)); + SHA1Final(randout, &randctxt); + SHA1Init(&randctxt); + SHA1Update(&randctxt, (unsigned char *) &randcnt, sizeof(randcnt)); + SHA1Update(&randctxt, randpool, sizeof(randpool)); + SHA1Final(randpool, &randctxt); + ++randcnt; + outpos = sizeof(randout); + } + + if(size > 0) { + memcpy(data, randout + (sizeof(randout) - outpos), size); + outpos -= size; + } +#endif +} + +/* + * The interleaved session-key hash. This separates the even and the odd + * bytes of the input (ignoring the first byte if the input length is odd), + * hashes them separately, and re-interleaves the two outputs to form a + * single 320-bit value. + */ +_TYPE( unsigned char * ) +t_sessionkey(unsigned char * key, unsigned char * sk, unsigned sklen) +{ + unsigned i, klen; + unsigned char * hbuf; + unsigned char hout[SHA_DIGESTSIZE]; + SHA1_CTX ctxt; + + while(sklen > 0 && *sk == 0) { /* Skip leading 0's */ + --sklen; + ++sk; + } + + klen = sklen / 2; + if((hbuf = malloc(klen * sizeof(char))) == 0) + return 0; + + for(i = 0; i < klen; ++i) + hbuf[i] = sk[sklen - 2 * i - 1]; + SHA1Init(&ctxt); + SHA1Update(&ctxt, hbuf, klen); + SHA1Final(hout, &ctxt); + for(i = 0; i < sizeof(hout); ++i) + key[2 * i] = hout[i]; + + for(i = 0; i < klen; ++i) + hbuf[i] = sk[sklen - 2 * i - 2]; + SHA1Init(&ctxt); + SHA1Update(&ctxt, hbuf, klen); + SHA1Final(hout, &ctxt); + for(i = 0; i < sizeof(hout); ++i) + key[2 * i + 1] = hout[i]; + + memset(hout, 0, sizeof(hout)); + memset(hbuf, 0, klen); + free(hbuf); + return key; +} + +_TYPE( void ) +t_mgf1(unsigned char * mask, unsigned masklen, const unsigned char * seed, unsigned seedlen) +{ + SHA1_CTX ctxt; + unsigned i = 0; + unsigned pos = 0; + unsigned char cnt[4]; + unsigned char hout[SHA_DIGESTSIZE]; + + while(pos < masklen) { + cnt[0] = (i >> 24) & 0xFF; + cnt[1] = (i >> 16) & 0xFF; + cnt[2] = (i >> 8) & 0xFF; + cnt[3] = i & 0xFF; + SHA1Init(&ctxt); + SHA1Update(&ctxt, seed, seedlen); + SHA1Update(&ctxt, cnt, 4); + + if(pos + SHA_DIGESTSIZE > masklen) { + SHA1Final(hout, &ctxt); + memcpy(mask + pos, hout, masklen - pos); + pos = masklen; + } + else { + SHA1Final(mask + pos, &ctxt); + pos += SHA_DIGESTSIZE; + } + + ++i; + } + + memset(hout, 0, sizeof(hout)); + memset((unsigned char *)&ctxt, 0, sizeof(ctxt)); +} |