diff --git a/auto/sources b/auto/sources index 46408ee53..2bce9cf8d 100644 --- a/auto/sources +++ b/auto/sources @@ -25,6 +25,7 @@ CORE_DEPS="src/core/nginx.h \ src/core/ngx_crc.h \ src/core/ngx_crc32.h \ src/core/ngx_murmurhash.h \ + src/core/ngx_siphash.h \ src/core/ngx_md5.h \ src/core/ngx_sha1.h \ src/core/ngx_rbtree.h \ @@ -60,6 +61,7 @@ CORE_SRCS="src/core/nginx.c \ src/core/ngx_file.c \ src/core/ngx_crc32.c \ src/core/ngx_murmurhash.c \ + src/core/ngx_siphash.c \ src/core/ngx_md5.c \ src/core/ngx_sha1.c \ src/core/ngx_rbtree.c \ diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h index 02890b843..b919d5b31 100644 --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -71,6 +71,7 @@ typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c); #include #include #include +#include #if (NGX_PCRE) #include #endif diff --git a/src/core/ngx_siphash.c b/src/core/ngx_siphash.c new file mode 100644 index 000000000..46e857926 --- /dev/null +++ b/src/core/ngx_siphash.c @@ -0,0 +1,95 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include +#include + + +/* + * SipHash-2-4 implementation based on the SipHash specification by + * Jean-Philippe Aumasson and Daniel J. Bernstein. + * https://eprint.iacr.org/2012/351.pdf + */ + + +#define ngx_siphash_rotl(x, b) \ + (uint64_t) (((x) << (b)) | ((x) >> (64 - (b)))) + +#define ngx_sipround \ + do { \ + v0 += v1; v1 = ngx_siphash_rotl(v1, 13); v1 ^= v0; \ + v0 = ngx_siphash_rotl(v0, 32); \ + v2 += v3; v3 = ngx_siphash_rotl(v3, 16); v3 ^= v2; \ + v0 += v3; v3 = ngx_siphash_rotl(v3, 21); v3 ^= v0; \ + v2 += v1; v1 = ngx_siphash_rotl(v1, 17); v1 ^= v2; \ + v2 = ngx_siphash_rotl(v2, 32); \ + } while (0) + + +uint64_t +ngx_siphash(uint64_t k0, uint64_t k1, u_char *data, size_t len) +{ + u_char *end; + size_t remainder; + uint64_t v0, v1, v2, v3, m; + + v0 = k0 ^ 0x736f6d6570736575ULL; + v1 = k1 ^ 0x646f72616e646f6dULL; + v2 = k0 ^ 0x6c7967656e657261ULL; + v3 = k1 ^ 0x7465646279746573ULL; + + end = data + (len - (len % 8)); + + for ( ; data != end; data += 8) { + ngx_memcpy(&m, data, 8); + v3 ^= m; + ngx_sipround; + ngx_sipround; + v0 ^= m; + } + + m = (uint64_t) len << 56; + remainder = len & 7; + + switch (remainder) { + case 7: + m |= (uint64_t) data[6] << 48; + /* fall through */ + case 6: + m |= (uint64_t) data[5] << 40; + /* fall through */ + case 5: + m |= (uint64_t) data[4] << 32; + /* fall through */ + case 4: + m |= (uint64_t) data[3] << 24; + /* fall through */ + case 3: + m |= (uint64_t) data[2] << 16; + /* fall through */ + case 2: + m |= (uint64_t) data[1] << 8; + /* fall through */ + case 1: + m |= (uint64_t) data[0]; + break; + case 0: + break; + } + + v3 ^= m; + ngx_sipround; + ngx_sipround; + v0 ^= m; + + v2 ^= 0xff; + ngx_sipround; + ngx_sipround; + ngx_sipround; + ngx_sipround; + + return v0 ^ v1 ^ v2 ^ v3; +} diff --git a/src/core/ngx_siphash.h b/src/core/ngx_siphash.h new file mode 100644 index 000000000..dd72a7889 --- /dev/null +++ b/src/core/ngx_siphash.h @@ -0,0 +1,18 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_SIPHASH_H_INCLUDED_ +#define _NGX_SIPHASH_H_INCLUDED_ + + +#include +#include + + +uint64_t ngx_siphash(uint64_t k0, uint64_t k1, u_char *data, size_t len); + + +#endif /* _NGX_SIPHASH_H_INCLUDED_ */ diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index 37cd0d287..191bc73c7 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -2298,11 +2298,10 @@ static ngx_int_t ngx_http_variable_request_id(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - u_char *id; + u_char *id; + uint64_t random_bytes[2]; -#if (NGX_OPENSSL) - u_char random_bytes[16]; -#endif + static uint64_t counter, key[2]; id = ngx_pnalloc(r->pool, 32); if (id == NULL) { @@ -2316,20 +2315,25 @@ ngx_http_variable_request_id(ngx_http_request_t *r, v->len = 32; v->data = id; + if (counter == 0) { #if (NGX_OPENSSL) - - if (RAND_bytes(random_bytes, 16) == 1) { - ngx_hex_dump(id, random_bytes, 16); - return NGX_OK; + if (RAND_bytes((u_char *) key, 16) != 1) +#endif + { + key[0] = ((uint64_t) ngx_random() << 32) | (uint32_t) ngx_random(); + key[1] = ((uint64_t) ngx_random() << 32) | (uint32_t) ngx_random(); + key[0] ^= (uint64_t) ngx_pid << 16; + key[1] ^= (uint64_t) ngx_time(); + } } - ngx_ssl_error(NGX_LOG_ERR, r->connection->log, 0, "RAND_bytes() failed"); + counter++; + random_bytes[0] = ngx_siphash(key[0], key[1], (u_char *) &counter, 8); -#endif + counter++; + random_bytes[1] = ngx_siphash(key[0], key[1], (u_char *) &counter, 8); - ngx_sprintf(id, "%08xD%08xD%08xD%08xD", - (uint32_t) ngx_random(), (uint32_t) ngx_random(), - (uint32_t) ngx_random(), (uint32_t) ngx_random()); + ngx_hex_dump(id, (u_char *) random_bytes, 16); return NGX_OK; }