Commit 373e5aea authored by Geoff Simmons's avatar Geoff Simmons

Add the random_int() function.

parent 521844db
Pipeline #225 skipped
......@@ -169,6 +169,7 @@ CONTENTS
* VOID init(ENUM {INIT_SECMEM,DISABLE_SECMEM,FINISH}, BYTES)
* symmetric(ENUM {AES,AES128,RIJNDAEL,RIJNDAEL128,AES192,RIJNDAEL192,AES256,RIJNDAEL256}, ENUM {ECB,CFB,CBC,OFB,CTR}, ENUM {PKCS7,ISO7816,X923,NONE}, BLOB, BOOL, BOOL)
* BLOB random(PRIV_TASK, ENUM {STRONG,VERY_STRONG,NONCE}, BYTES)
* INT random_int(ENUM {STRONG,NONCE}, INT)
* STRING version()
* STRING gcrypt_version()
......@@ -596,6 +597,36 @@ Example::
unset resp.http.X-Msg;
}
.. _func_random_int:
random_int
----------
::
INT random_int(ENUM {STRONG,NONCE} quality, INT bound=0)
Returns a random integer, using the random number generator with the
quality level specified by the ENUM ``quality``. These are the same
levels that are described for the ``random()`` function above, except
that the ``VERY_STRONG`` level is not available.
If ``bound`` is less than or equal to 0, then the return value lies
within the entire possible range for an INT (positive or negative).
The default value of ``bound`` is 0.
If ``bound`` is greater than 0, then the return value lies between 0
(inclusive) and ``bound`` (exclusive). To get a random integer between
values ``min`` and ``max`` inclusive with the ``NONCE`` generator, use
this formula::
random_int(NONCE, (max - min) + 1) + min
Example::
# Assign a random group number from 0 to 99 to a request.
set req.http.X-Group = random_int(NONCE, 100);
.. _func_version:
version
......
......@@ -35,6 +35,36 @@ varnish v1 -vcl {
set resp.http.error
= blobcode.encode(HEXUC, gcrypt.random(n=1B));
set resp.http.strong-int = gcrypt.random_int(STRONG);
set resp.http.nonce-int = gcrypt.random_int(NONCE);
set resp.http.strong-int1 = gcrypt.random_int(STRONG, 1);
set resp.http.nonce-int2 = gcrypt.random_int(NONCE, 2);
set resp.http.strong-int3 = gcrypt.random_int(STRONG, 3);
set resp.http.nonce-int4 = gcrypt.random_int(NONCE, 4);
set resp.http.strong-int5 = gcrypt.random_int(STRONG, 5);
set resp.http.strong-int6 = gcrypt.random_int(STRONG, 6);
set resp.http.nonce-int7 = gcrypt.random_int(NONCE, 7);
set resp.http.strong-int8 = gcrypt.random_int(STRONG, 8);
set resp.http.nonce-int9 = gcrypt.random_int(NONCE, 9);
set resp.http.strong-int10 = gcrypt.random_int(STRONG, 10);
set resp.http.nonce-int1e2 = gcrypt.random_int(NONCE, 100);
set resp.http.strong-int1e3 = gcrypt.random_int(STRONG, 1000);
set resp.http.nonce-int1e4 = gcrypt.random_int(NONCE, 10000);
set resp.http.strong-int1e5 = gcrypt.random_int(STRONG, 100000);
set resp.http.strong-int1e6
= gcrypt.random_int(STRONG, 1000000);
set resp.http.nonce-int1e7
= gcrypt.random_int(NONCE, 10000000);
set resp.http.strong-int1e8
= gcrypt.random_int(STRONG, 100000000);
set resp.http.nonce-int1e9
= gcrypt.random_int(NONCE, 1000000000);
set resp.http.strong-int1e10
= gcrypt.random_int(STRONG, 10000000000);
return(deliver);
}
} -start
......@@ -51,6 +81,27 @@ client c1 {
expect resp.http.strong32-task-enum == resp.http.strong32
expect resp.http.strong32-task-n0-enum == resp.http.strong32
expect resp.http.error == ""
expect resp.http.strong-int ~ "^-?[[:digit:]]+$"
expect resp.http.nonce-int ~ "^-?[[:digit:]]+$"
expect resp.http.strong-int1 == "0"
expect resp.http.nonce-int2 ~ "^[01]$"
expect resp.http.strong-int3 ~ "^[012]$"
expect resp.http.nonce-int4 ~ "^[0123]$"
expect resp.http.strong-int5 ~ "^[01234]$"
expect resp.http.strong-int6 ~ "^[012345]$"
expect resp.http.nonce-int7 ~ "^[0123456]$"
expect resp.http.strong-int8 ~ "^[01234567]$"
expect resp.http.nonce-int9 ~ "^[012345678]$"
expect resp.http.strong-int10 ~ "^[0123456789]$"
expect resp.http.nonce-int1e2 ~ "^[[:digit:]]{1,2}$"
expect resp.http.strong-int1e3 ~ "^[[:digit:]]{1,3}$"
expect resp.http.nonce-int1e4 ~ "^[[:digit:]]{1,4}$"
expect resp.http.strong-int1e5 ~ "^[[:digit:]]{1,5}$"
expect resp.http.strong-int1e6 ~ "^[[:digit:]]{1,6}$"
expect resp.http.nonce-int1e7 ~ "^[[:digit:]]{1,7}$"
expect resp.http.strong-int1e8 ~ "^[[:digit:]]{1,8}$"
expect resp.http.nonce-int1e9 ~ "^[[:digit:]]{1,9}$"
expect resp.http.strong-int1e10 ~ "^[[:digit:]]{1,10}$"
} -run
logexpect l1 -v v1 -d 1 -q "VCL_Error" {
......
......@@ -34,6 +34,7 @@
#include <string.h>
#include <pthread.h>
#include <errno.h>
#include <stdint.h>
#include "vcl.h"
#include "cache/cache.h"
......@@ -641,6 +642,40 @@ vmod_symmetric_decrypt(VRT_CTX, struct vmod_gcrypt_symmetric *symmetric,
/* Function random */
static inline void
get_rnd(VCL_ENUM const restrict qualitys, void * const restrict p, size_t n)
{
switch(qualitys[0]) {
case 'N':
AZ(strcmp(qualitys + 1, "ONCE"));
gcry_create_nonce(p, n);
break;
case 'S':
AZ(strcmp(qualitys + 1, "TRONG"));
gcry_randomize(p, n, GCRY_STRONG_RANDOM);
break;
case 'V':
AZ(strcmp(qualitys + 1, "ERY_STRONG"));
gcry_randomize(p, n, GCRY_VERY_STRONG_RANDOM);
break;
default:
WRONG("Illegal quality enum");
}
}
#if 0
static uint64_t
rnd_bits(VCL_ENUM const qualitys, int n)
{
uint64_t r = 0;
int nbytes = (n + 7) / 8;
assert(n >= 0 && n <= 64);
get_rnd(qualitys, (uint8_t *)&r + (8 - nbytes), nbytes);
return r >> (64 - n);
}
#endif
VCL_BLOB
vmod_random(VRT_CTX, struct vmod_priv *rnd_task, VCL_ENUM qualitys, VCL_BYTES n)
{
......@@ -666,6 +701,7 @@ vmod_random(VRT_CTX, struct vmod_priv *rnd_task, VCL_ENUM qualitys, VCL_BYTES n)
ERR(ctx, "in gcrypt.random(): quality ENUM is NULL");
return NULL;
}
snap = WS_Snapshot(ctx->ws);
if ((rnd_blob = WS_Alloc(ctx->ws, sizeof(*rnd_blob))) == NULL) {
ERRNOMEM(ctx, "in gcrypt.random(), allocating space for return "
......@@ -678,22 +714,7 @@ vmod_random(VRT_CTX, struct vmod_priv *rnd_task, VCL_ENUM qualitys, VCL_BYTES n)
"random bytes", n);
return NULL;
}
switch(qualitys[0]) {
case 'N':
AZ(strcmp(qualitys + 1, "ONCE"));
gcry_create_nonce(rnd_blob->priv, n);
break;
case 'S':
AZ(strcmp(qualitys + 1, "TRONG"));
gcry_randomize(rnd_blob->priv, n, GCRY_STRONG_RANDOM);
break;
case 'V':
AZ(strcmp(qualitys + 1, "ERY_STRONG"));
gcry_randomize(rnd_blob->priv, n, GCRY_VERY_STRONG_RANDOM);
break;
default:
WRONG("Illegal quality enum");
}
get_rnd(qualitys, rnd_blob->priv, n);
rnd_blob->len = n;
rnd_blob->free = NULL;
rnd_task->priv = rnd_blob;
......@@ -702,6 +723,42 @@ vmod_random(VRT_CTX, struct vmod_priv *rnd_task, VCL_ENUM qualitys, VCL_BYTES n)
return rnd_blob;
}
VCL_INT
vmod_random_int(VRT_CTX, VCL_ENUM qualitys, VCL_INT bound)
{
VCL_INT r, mask;
unsigned nbytes = 0;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
AN(qualitys);
assert(qualitys[0] != 'V');
if (bound <= 0) {
get_rnd(qualitys, &r, sizeof(VCL_INT));
return r;
}
for (r = bound; r > 0; r >>= 8)
nbytes++;
assert(nbytes <= sizeof(VCL_INT));
get_rnd(qualitys, &r, nbytes);
mask = bound - 1;
if ((bound & mask) == 0)
/* bound is a power of 2 */
return r & mask;
/*
* Adapted from java.util.Random.nextInt -- reject values that
* would lead to a non-uniform distribution when the range of INT
* is not evenly divisible by bound.
*/
for (VCL_INT u = r; u - (r = u % bound) + mask < 0;
get_rnd(qualitys, &u, nbytes))
;
return r;
}
VCL_STRING
vmod_version(VRT_CTX __attribute__((unused)))
{
......
......@@ -539,6 +539,29 @@ Example::
unset resp.http.X-Msg;
}
$Function INT random_int(ENUM {STRONG, NONCE} quality, INT bound=0)
Returns a random integer, using the random number generator with the
quality level specified by the ENUM ``quality``. These are the same
levels that are described for the ``random()`` function above, except
that the ``VERY_STRONG`` level is not available.
If ``bound`` is less than or equal to 0, then the return value lies
within the entire possible range for an INT (positive or negative).
The default value of ``bound`` is 0.
If ``bound`` is greater than 0, then the return value lies between 0
(inclusive) and ``bound`` (exclusive). To get a random integer between
values ``min`` and ``max`` inclusive with the ``NONCE`` generator, use
this formula::
random_int(NONCE, (max - min) + 1) + min
Example::
# Assign a random group number from 0 to 99 to a request.
set req.http.X-Group = random_int(NONCE, 100);
$Function STRING version()
Returns the version string for this VMOD.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment