Skip to content

Loading…

Add cryptographically strong random string functions. #10

Merged
merged 1 commit into from

2 participants

@jeremywohl

(Note: I didn't update README, only README.markdown -- I assume you're using a Markdown to text converter?)

@agentzh
OpenResty member
@jeremywohl

Thoughts?

@agentzh
OpenResty member
@agentzh agentzh added a commit that referenced this pull request
@agentzh agentzh various coding style fixes in Jeremy Wohl's patch for cryptographical…
…ly strong random string functions in github pull request #10.
5441a7e
@agentzh agentzh added a commit that referenced this pull request
@agentzh agentzh config: added ngx_http_set_secure_random.h to the NGX_ADDON_DEPS vari…
…able value, which was added in github pull request #10.
658c235
@agentzh agentzh merged commit c11f17f into openresty:master
@agentzh
OpenResty member

I've merged your patch and also fixed some minor issues.

BTW, both README.markdown and README are automatically generated from doc/HttpSetMiscModule.wiki via the scripts in the agentzh/nginx-devel-utils project:

https://github.com/agentzh/nginx-devel-utils/

I just run the ngx-releng script at the top directory of our nginx module source trees. See its content for details:

https://github.com/agentzh/nginx-devel-utils/blob/master/ngx-releng

Thank you very much for your contributions!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 13, 2012
  1. @jeremywohl
Showing with 282 additions and 1 deletion.
  1. +56 −0 README.markdown
  2. +1 −1 config
  3. +31 −0 src/ngx_http_set_misc_module.c
  4. +90 −0 src/ngx_http_set_secure_random.c
  5. +9 −0 src/ngx_http_set_secure_random.h
  6. +95 −0 t/secure-random.t
View
56 README.markdown
@@ -771,6 +771,62 @@ For now, there's no way to configure a custom random generator seed.
Behind the scene, it makes use of the standard C function `rand()`.
+set_secure_random_alphanum
+--------------------------
+**syntax:** *set_secure_random_alphanum $res <length>*
+
+**default:** *no*
+
+**context:** *location, location if*
+
+**phase:** *rewrite*
+
+Generates a cryptographically-strong random string `<length>` characters long with the alphabet [a-zA-Z0-9].
+
+`<length>` may be between 1 and 64, inclusive.
+
+For instance,
+
+
+ location /test {
+ set_secure_random_alphanum $res 32;
+
+ echo $res;
+ }
+
+
+then request `GET /test` will output a string like "ivVVRP2DGaAqDmdf3Rv4ZDJ7k0gOfASz".
+
+This function depends on the presence of the "/dev/urandom" device, available on most UNIX-like systems.
+
+set_secure_random_lcalpha
+-------------------------
+**syntax:** *set_secure_random_lcalpha $res &lt;length&gt;*
+
+**default:** *no*
+
+**context:** *location, location if*
+
+**phase:** *rewrite*
+
+Generates a cryptographically-strong random string `<length>` characters long with the alphabet [a-z].
+
+`<length>` may be between 1 and 64, inclusive.
+
+For instance,
+
+
+ location /test {
+ set_secure_random_lcalpha $res 32;
+
+ echo $res;
+ }
+
+
+then request `GET /test` will output a string like "kcuxcddktffsippuekhshdaclaquiusj".
+
+This function depends on the presence of the "/dev/urandom" device, available on most UNIX-like systems.
+
set_local_today
---------------
**syntax:** *set_local_today $dst*
View
2 config
@@ -7,7 +7,7 @@ fi
ngx_addon_name=ngx_http_set_misc_module
HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_set_misc_module"
-NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/src/ngx_http_set_base32.c $ngx_addon_dir/src/ngx_http_set_default_value.c $ngx_addon_dir/src/ngx_http_set_hashed_upstream.c $ngx_addon_dir/src/ngx_http_set_quote_sql.c $ngx_addon_dir/src/ngx_http_set_quote_json.c $ngx_addon_dir/src/ngx_http_set_unescape_uri.c $ngx_addon_dir/src/ngx_http_set_misc_module.c $ngx_addon_dir/src/ngx_http_set_escape_uri.c $ngx_addon_dir/src/ngx_http_set_hash.c $ngx_addon_dir/src/ngx_http_set_local_today.c $ngx_addon_dir/src/ngx_http_set_hex.c $ngx_addon_dir/src/ngx_http_set_base64.c $ngx_addon_dir/src/ngx_http_set_random.c"
+NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/src/ngx_http_set_base32.c $ngx_addon_dir/src/ngx_http_set_default_value.c $ngx_addon_dir/src/ngx_http_set_hashed_upstream.c $ngx_addon_dir/src/ngx_http_set_quote_sql.c $ngx_addon_dir/src/ngx_http_set_quote_json.c $ngx_addon_dir/src/ngx_http_set_unescape_uri.c $ngx_addon_dir/src/ngx_http_set_misc_module.c $ngx_addon_dir/src/ngx_http_set_escape_uri.c $ngx_addon_dir/src/ngx_http_set_hash.c $ngx_addon_dir/src/ngx_http_set_local_today.c $ngx_addon_dir/src/ngx_http_set_hex.c $ngx_addon_dir/src/ngx_http_set_base64.c $ngx_addon_dir/src/ngx_http_set_random.c $ngx_addon_dir/src/ngx_http_set_secure_random.c"
NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_addon_dir/src/ddebug.h $ngx_addon_dir/src/ngx_http_set_default_value.h $ngx_addon_dir/src/ngx_http_set_hashed_upstream.h $ngx_addon_dir/src/ngx_http_set_quote_sql.h $ngx_addon_dir/src/ngx_http_set_quote_json.h $ngx_addon_dir/src/ngx_http_set_unescape_uri.h $ngx_addon_dir/src/ngx_http_set_escape_uri.h $ngx_addon_dir/src/ngx_http_set_hash.h $ngx_addon_dir/src/ngx_http_set_local_today.h $ngx_addon_dir/src/ngx_http_set_hex.h $ngx_addon_dir/src/ngx_http_set_base64.h $ngx_addon_dir/src/ngx_http_set_random.h $ngx_addon_dir/src/ngx_http_set_misc_module.h"
if [ $USE_OPENSSL = YES ]; then
View
31 src/ngx_http_set_misc_module.c
@@ -20,6 +20,7 @@
#include "ngx_http_set_hmac.h"
#endif
#include "ngx_http_set_random.h"
+#include "ngx_http_set_secure_random.h"
#define NGX_UNESCAPE_URI_COMPONENT 0
@@ -151,6 +152,20 @@ static ndk_set_var_t ngx_http_set_misc_set_random_filter = {
NULL
};
+static ndk_set_var_t ngx_http_set_misc_set_secure_random_alphanum_filter = {
+ NDK_SET_VAR_VALUE,
+ ngx_http_set_misc_set_secure_random_alphanum,
+ 1,
+ NULL
+};
+
+static ndk_set_var_t ngx_http_set_misc_set_secure_random_lcalpha_filter = {
+ NDK_SET_VAR_VALUE,
+ ngx_http_set_misc_set_secure_random_lcalpha,
+ 1,
+ NULL
+};
+
static ngx_command_t ngx_http_set_misc_commands[] = {
{ ngx_string ("set_encode_base64"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF
@@ -322,6 +337,22 @@ static ngx_command_t ngx_http_set_misc_commands[] = {
0,
&ngx_http_set_misc_set_random_filter
},
+ { ngx_string ("set_secure_random_alphanum"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF
+ |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12,
+ ndk_set_var_value,
+ 0,
+ 0,
+ &ngx_http_set_misc_set_secure_random_alphanum_filter
+ },
+ { ngx_string ("set_secure_random_lcalpha"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF
+ |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12,
+ ndk_set_var_value,
+ 0,
+ 0,
+ &ngx_http_set_misc_set_secure_random_lcalpha_filter
+ },
ngx_null_command
};
View
90 src/ngx_http_set_secure_random.c
@@ -0,0 +1,90 @@
+#ifndef DDEBUG
+#define DDEBUG 0
+#endif
+#include "ddebug.h"
+
+#include <ndk.h>
+#include "ngx_http_set_secure_random.h"
+#include <stdlib.h>
+
+const int MAX_RANDOM_STRING = 64;
+
+const int ALPHANUM = 1;
+const int LCALPHA = 2;
+
+ngx_int_t
+ngx_http_set_misc_set_secure_random_common(int alphabet_type, ngx_http_request_t *r,
+ ngx_str_t *res, ngx_http_variable_value_t *v);
+
+ngx_int_t
+ngx_http_set_misc_set_secure_random_alphanum(ngx_http_request_t *r,
+ ngx_str_t *res, ngx_http_variable_value_t *v)
+{
+ return ngx_http_set_misc_set_secure_random_common(ALPHANUM, r, res, v);
+}
+
+ngx_int_t
+ngx_http_set_misc_set_secure_random_lcalpha(ngx_http_request_t *r,
+ ngx_str_t *res, ngx_http_variable_value_t *v)
+{
+ return ngx_http_set_misc_set_secure_random_common(LCALPHA, r, res, v);
+}
+
+ngx_int_t
+ngx_http_set_misc_set_secure_random_common(int alphabet_type, ngx_http_request_t *r,
+ ngx_str_t *res, ngx_http_variable_value_t *v)
+{
+ static u_char alphabet[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ u_char entropy[MAX_RANDOM_STRING];
+ u_char output[MAX_RANDOM_STRING];
+ ngx_int_t length, fd, i;
+ ssize_t n;
+
+
+ length = ngx_atoi(v->data, v->len);
+ if (length == NGX_ERROR || length < 1 || length > MAX_RANDOM_STRING) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "set_random: bad \"length\" argument: %v", v);
+ return NGX_ERROR;
+ }
+
+ fd = ngx_open_file("/dev/urandom", NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
+ if (fd == -1) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "set_secure_random: could not open /dev/urandom");
+ return NGX_ERROR;
+ }
+
+ n = ngx_read_fd(fd, entropy, length);
+ if (n != length) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "set_secure_random: could not read all %d byte(s) from /dev/urandom", length);
+ return NGX_ERROR;
+ }
+
+ ngx_close_file(fd);
+
+ for (i = 0; i < length; i++) {
+ if (alphabet_type == LCALPHA) {
+ output[i] = entropy[i] % 26 + 'a';
+ } else {
+ output[i] = alphabet[ entropy[i] % (sizeof alphabet - 1) ];
+ }
+ }
+
+ res->data = ngx_palloc(r->pool, length);
+ if (res->data == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(res->data, output, length);
+
+ res->len = length;
+
+ /* Set all required params */
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+
+ return NGX_OK;
+}
View
9 src/ngx_http_set_secure_random.h
@@ -0,0 +1,9 @@
+#include <ngx_core.h>
+#include <ngx_config.h>
+#include <ngx_http.h>
+
+ngx_int_t ngx_http_set_misc_set_secure_random_alphanum(ngx_http_request_t *r,
+ ngx_str_t *res, ngx_http_variable_value_t *v);
+
+ngx_int_t ngx_http_set_misc_set_secure_random_lcalpha(ngx_http_request_t *r,
+ ngx_str_t *res, ngx_http_variable_value_t *v);
View
95 t/secure-random.t
@@ -0,0 +1,95 @@
+# vi:filetype=perl
+
+use Test::Nginx::Socket;
+
+repeat_each(100);
+
+plan tests => repeat_each() * 2 * blocks();
+
+no_long_string();
+
+run_tests();
+
+#no_diff();
+
+__DATA__
+
+=== TEST 1: a 32-character alphanum
+--- config
+ location /alphanum {
+ set_secure_random_alphanum $res 32;
+
+ echo $res;
+ }
+--- request
+ GET /alphanum
+--- response_body_like: ^[a-zA-Z0-9]{32}$
+
+=== TEST 2: a 16-character alphanum
+--- config
+ location /alphanum {
+ set_secure_random_alphanum $res 16;
+
+ echo $res;
+ }
+--- request
+ GET /alphanum
+--- response_body_like: ^[a-zA-Z0-9]{16}$
+
+=== TEST 3: a 1-character alphanum
+--- config
+ location /alphanum {
+ set_secure_random_alphanum $res 1;
+
+ echo $res;
+ }
+--- request
+ GET /alphanum
+--- response_body_like: ^[a-zA-Z0-9]{1}$
+
+=== TEST 4: length less than <= 0 should fail
+--- config
+ location /alphanum {
+ set_secure_random_alphanum $res 0;
+
+ echo $res;
+ }
+--- request
+ GET /alphanum
+--- response_body_like: 500 Internal Server Error
+--- error_code: 500
+
+=== TEST 5: length less than <= 0 should fail
+--- config
+ location /alphanum {
+ set_secure_random_alphanum $res -4;
+
+ echo $res;
+ }
+--- request
+ GET /alphanum
+--- response_body_like: 500 Internal Server Error
+--- error_code: 500
+
+=== TEST 6: non-numeric length should fail
+--- config
+ location /alphanum {
+ set_secure_random_alphanum $res bob;
+
+ echo $res;
+ }
+--- request
+ GET /alphanum
+--- response_body_like: 500 Internal Server Error
+--- error_code: 500
+
+=== TEST 7: a 16-character lcalpha
+--- config
+ location /lcalpha {
+ set_secure_random_lcalpha $res 16;
+
+ echo $res;
+ }
+--- request
+ GET /lcalpha
+--- response_body_like: ^[a-z]{16}$
Something went wrong with that request. Please try again.