summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2015-01-21 23:19:37 +0100
committerantirez <antirez@gmail.com>2015-01-22 11:12:28 +0100
commitb25154a387261a41c0f1a81eba58426dc72ae373 (patch)
tree14f51a5228c37632396c6f899ff27378879737a7
parent7e41200b98ecf1ac79fb342c6486e5a270729f85 (diff)
downloadredis-b25154a387261a41c0f1a81eba58426dc72ae373.tar.gz
getRandomHexChars(): use /dev/urandom just to seed.
On Darwin /dev/urandom depletes terribly fast. This is not an issue normally, but with Redis Cluster we generate a lot of unique IDs, for example during nodes handshakes. Our IDs need just to be unique without other strong crypto requirements, so this commit turns the function into something that gets a 20 bytes seed from /dev/urandom, and produces the rest of the output just using SHA1 in counter mode.
-rw-r--r--src/util.c46
1 files changed, 38 insertions, 8 deletions
diff --git a/src/util.c b/src/util.c
index 80242ff71..e29c7862b 100644
--- a/src/util.c
+++ b/src/util.c
@@ -40,6 +40,7 @@
#include <stdint.h>
#include "util.h"
+#include "sha1.h"
/* Glob-style pattern matching. */
int stringmatchlen(const char *pattern, int patternLen,
@@ -428,11 +429,42 @@ int d2string(char *buf, size_t len, double value) {
* having run_id == A, and you reconnect and it has run_id == B, you can be
* sure that it is either a different instance or it was restarted. */
void getRandomHexChars(char *p, unsigned int len) {
- FILE *fp = fopen("/dev/urandom","r");
char *charset = "0123456789abcdef";
unsigned int j;
+ static int seed_initialized = 0;
+ unsigned char seed[20]; /* A seed to have a different sequence each run. */
+ uint64_t counter = 0; /* The counter we hash together with the seed. */
+
+ if (!seed_initialized) {
+ /* Initialize a seed and use SHA1 in counter mode, where we hash
+ * the same seed with a progressive counter. For the goals of this
+ * function we just need non-colliding strings, there are no
+ * cryptographic security needs. */
+ FILE *fp = fopen("/dev/urandom","r");
+ if (fp && fread(seed,sizeof(seed),1,fp) == 1)
+ seed_initialized = 1;
+ if (fp) fclose(fp);
+ }
- if (fp == NULL || fread(p,len,1,fp) == 0) {
+ if (seed_initialized) {
+ while(len) {
+ unsigned char digest[20];
+ SHA1_CTX ctx;
+ unsigned int copylen = len > 20 ? 20 : len;
+
+ SHA1Init(&ctx);
+ SHA1Update(&ctx, seed, sizeof(seed));
+ SHA1Update(&ctx, (unsigned char*)&counter,sizeof(counter));
+ SHA1Final(digest, &ctx);
+ counter++;
+
+ memcpy(p,digest,copylen);
+ /* Convert to hex digits. */
+ for (j = 0; j < copylen; j++) p[j] = charset[p[j] & 0x0F];
+ len -= copylen;
+ p += copylen;
+ }
+ } else {
/* If we can't read from /dev/urandom, do some reasonable effort
* in order to create some entropy, since this function is used to
* generate run_id and cluster instance IDs */
@@ -459,14 +491,12 @@ void getRandomHexChars(char *p, unsigned int len) {
x += sizeof(pid);
}
/* Finally xor it with rand() output, that was already seeded with
- * time() at startup. */
- for (j = 0; j < len; j++)
+ * time() at startup, and convert to hex digits. */
+ for (j = 0; j < len; j++) {
p[j] ^= rand();
+ p[j] = charset[p[j] & 0x0F];
+ }
}
- /* Turn it into hex digits taking just 4 bits out of 8 for every byte. */
- for (j = 0; j < len; j++)
- p[j] = charset[p[j] & 0x0F];
- if (fp) fclose(fp);
}
/* Given the filename, return the absolute path as an SDS string, or NULL