summaryrefslogtreecommitdiff
path: root/src/util.c
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2020-04-23 11:17:42 +0200
committerantirez <antirez@gmail.com>2020-04-23 11:23:50 +0200
commit9ae8254e20c151bb153519a868933cbd13d4c164 (patch)
tree894e6a14e69bfd0f101f6b4eda31ea26e9802643 /src/util.c
parenta95a086be7b6c8eda5b0d181b6874ac88502aae5 (diff)
downloadredis-9ae8254e20c151bb153519a868933cbd13d4c164.tar.gz
getRandomBytes(): use HMAC-SHA256.
Now that we have an interface to use this API directly, via ACL GENPASS, we are no longer sure what people could do with it. So why don't make it a strong primitive exported by Redis in order to create unique IDs and so forth? The implementation was tested against the test vectors that can be found in RFC4231.
Diffstat (limited to 'src/util.c')
-rw-r--r--src/util.c40
1 files changed, 30 insertions, 10 deletions
diff --git a/src/util.c b/src/util.c
index bd8f0fb98..d173f776f 100644
--- a/src/util.c
+++ b/src/util.c
@@ -42,7 +42,7 @@
#include <time.h>
#include "util.h"
-#include "sha1.h"
+#include "sha256.h"
/* Glob-style pattern matching. */
int stringmatchlen(const char *pattern, int patternLen,
@@ -622,7 +622,7 @@ int ld2string(char *buf, size_t len, long double value, ld2string_mode mode) {
void getRandomBytes(unsigned char *p, size_t len) {
/* Global state. */
static int seed_initialized = 0;
- static unsigned char seed[20]; /* The SHA1 seed, from /dev/urandom. */
+ static unsigned char seed[64]; /* 512 bit internal block size. */
static uint64_t counter = 0; /* The counter we hash with the seed. */
if (!seed_initialized) {
@@ -647,14 +647,34 @@ void getRandomBytes(unsigned char *p, size_t len) {
}
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);
+ /* This implements SHA256-HMAC. */
+ unsigned char digest[SHA256_BLOCK_SIZE];
+ unsigned char kxor[64];
+ unsigned int copylen =
+ len > SHA256_BLOCK_SIZE ? SHA256_BLOCK_SIZE : len;
+
+ /* IKEY: key xored with 0x36. */
+ memcpy(kxor,seed,sizeof(kxor));
+ for (unsigned int i = 0; i < sizeof(kxor); i++) kxor[i] ^= 0x36;
+
+ /* Obtain HASH(IKEY||MESSAGE). */
+ SHA256_CTX ctx;
+ sha256_init(&ctx);
+ sha256_update(&ctx,kxor,sizeof(kxor));
+ sha256_update(&ctx,(unsigned char*)&counter,sizeof(counter));
+ sha256_final(&ctx,digest);
+
+ /* OKEY: key xored with 0x5c. */
+ memcpy(kxor,seed,sizeof(kxor));
+ for (unsigned int i = 0; i < sizeof(kxor); i++) kxor[i] ^= 0x5C;
+
+ /* Obtain HASH(OKEY || HASH(IKEY||MESSAGE)). */
+ sha256_init(&ctx);
+ sha256_update(&ctx,kxor,sizeof(kxor));
+ sha256_update(&ctx,digest,SHA256_BLOCK_SIZE);
+ sha256_final(&ctx,digest);
+
+ /* Increment the counter for the next iteration. */
counter++;
memcpy(p,digest,copylen);