[njs] Nodejs style crypto methods.
Dmitry Volyntsev
xeioex at nginx.com
Fri Mar 30 16:20:59 UTC 2018
details: http://hg.nginx.org/njs/rev/d3747fbfce39
branches:
changeset: 477:d3747fbfce39
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Fri Mar 30 18:50:38 2018 +0300
description:
Nodejs style crypto methods.
var crypto = require('crypto')
var hash = crypto.createHash(<alg>)
available algorithms: 'md5', 'sha1', 'sha256'.
hash.update(<data>)
hash.digest([<encoding>])
available encodings: 'hex', 'base64'.
var hmac = crypto.createHmac(<alg>, <key>)
available algorithms: 'md5', 'sha1', 'sha256'.
hmac.update(<data>)
hmac.digest([<encoding>])
available encodings: 'hex', 'base64'.
diffstat:
Makefile | 19 +
njs/njs_builtin.c | 17 +-
njs/njs_crypto.c | 713 ++++++++++++++++++++++++++++++++++++++++
njs/njs_crypto.h | 24 +
njs/njs_object.c | 12 +-
njs/njs_vm.c | 10 +
njs/njs_vm.h | 32 +-
njs/njscript.h | 1 +
njs/test/njs_interactive_test.c | 22 +
njs/test/njs_unit_test.c | 163 +++++++++
nxt/Makefile | 36 ++
nxt/nxt_md5.c | 270 +++++++++++++++
nxt/nxt_md5.h | 23 +
nxt/nxt_sha1.c | 298 ++++++++++++++++
nxt/nxt_sha1.h | 24 +
nxt/nxt_sha2.c | 320 +++++++++++++++++
nxt/nxt_sha2.h | 24 +
17 files changed, 1996 insertions(+), 12 deletions(-)
diffs (truncated from 2313 to 1000 lines):
diff -r be43fdd9579e -r d3747fbfce39 Makefile
--- a/Makefile Fri Mar 30 15:46:40 2018 +0300
+++ b/Makefile Fri Mar 30 18:50:38 2018 +0300
@@ -24,6 +24,7 @@ NXT_BUILDDIR = build
$(NXT_BUILDDIR)/njs_module.o \
$(NXT_BUILDDIR)/njs_event.o \
$(NXT_BUILDDIR)/njs_fs.o \
+ $(NXT_BUILDDIR)/njs_crypto.o \
$(NXT_BUILDDIR)/njs_extern.o \
$(NXT_BUILDDIR)/njs_variable.o \
$(NXT_BUILDDIR)/njs_builtin.o \
@@ -40,6 +41,9 @@ NXT_BUILDDIR = build
$(NXT_BUILDDIR)/nxt_lvlhsh.o \
$(NXT_BUILDDIR)/nxt_trace.o \
$(NXT_BUILDDIR)/nxt_random.o \
+ $(NXT_BUILDDIR)/nxt_md5.o \
+ $(NXT_BUILDDIR)/nxt_sha1.o \
+ $(NXT_BUILDDIR)/nxt_sha2.o \
$(NXT_BUILDDIR)/nxt_pcre.o \
$(NXT_BUILDDIR)/nxt_malloc.o \
$(NXT_BUILDDIR)/nxt_mem_cache_pool.o \
@@ -62,6 +66,7 @@ NXT_BUILDDIR = build
$(NXT_BUILDDIR)/njs_module.o \
$(NXT_BUILDDIR)/njs_event.o \
$(NXT_BUILDDIR)/njs_fs.o \
+ $(NXT_BUILDDIR)/njs_crypto.o \
$(NXT_BUILDDIR)/njs_extern.o \
$(NXT_BUILDDIR)/njs_variable.o \
$(NXT_BUILDDIR)/njs_builtin.o \
@@ -78,6 +83,9 @@ NXT_BUILDDIR = build
$(NXT_BUILDDIR)/nxt_lvlhsh.o \
$(NXT_BUILDDIR)/nxt_trace.o \
$(NXT_BUILDDIR)/nxt_random.o \
+ $(NXT_BUILDDIR)/nxt_md5.o \
+ $(NXT_BUILDDIR)/nxt_sha1.o \
+ $(NXT_BUILDDIR)/nxt_sha2.o \
$(NXT_BUILDDIR)/nxt_pcre.o \
$(NXT_BUILDDIR)/nxt_malloc.o \
$(NXT_BUILDDIR)/nxt_mem_cache_pool.o \
@@ -350,6 +358,17 @@ dist:
-I$(NXT_LIB) -Injs \
njs/njs_fs.c
+$(NXT_BUILDDIR)/njs_crypto.o: \
+ $(NXT_BUILDDIR)/libnxt.a \
+ njs/njscript.h \
+ njs/njs_vm.h \
+ njs/njs_crypto.h \
+ njs/njs_crypto.c \
+
+ $(NXT_CC) -c -o $(NXT_BUILDDIR)/njs_crypto.o $(NXT_CFLAGS) \
+ -I$(NXT_LIB) -Injs \
+ njs/njs_crypto.c
+
$(NXT_BUILDDIR)/njs_extern.o: \
$(NXT_BUILDDIR)/libnxt.a \
njs/njscript.h \
diff -r be43fdd9579e -r d3747fbfce39 njs/njs_builtin.c
--- a/njs/njs_builtin.c Fri Mar 30 15:46:40 2018 +0300
+++ b/njs/njs_builtin.c Fri Mar 30 18:50:38 2018 +0300
@@ -33,6 +33,7 @@
#include <njs_time.h>
#include <njs_module.h>
#include <njs_fs.h>
+#include <njs_crypto.h>
#include <string.h>
#include <stdio.h>
@@ -58,7 +59,8 @@ const njs_object_init_t *njs_object_i
const njs_object_init_t *njs_module_init[] = {
- &njs_fs_object_init /* fs */
+ &njs_fs_object_init, /* fs */
+ &njs_crypto_object_init /* crypto */
};
@@ -71,6 +73,8 @@ const njs_object_init_t *njs_prototype_
&njs_function_prototype_init,
&njs_regexp_prototype_init,
&njs_date_prototype_init,
+ &njs_hash_prototype_init,
+ &njs_hmac_prototype_init,
&njs_error_prototype_init,
&njs_eval_error_prototype_init,
&njs_internal_error_prototype_init,
@@ -91,6 +95,8 @@ const njs_object_init_t *njs_construc
&njs_function_constructor_init,
&njs_regexp_constructor_init,
&njs_date_constructor_init,
+ &njs_hash_constructor_init,
+ &njs_hmac_constructor_init,
&njs_error_constructor_init,
&njs_eval_error_constructor_init,
&njs_internal_error_constructor_init,
@@ -192,6 +198,12 @@ njs_builtin_objects_create(njs_vm_t *vm)
{ .date = { .time = NAN,
.object = { .type = NJS_DATE } } },
+ { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0),
+ .object = { .type = NJS_OBJECT } } },
+
+ { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0),
+ .object = { .type = NJS_OBJECT } } },
+
{ .object = { .type = NJS_OBJECT_ERROR } },
{ .object = { .type = NJS_OBJECT_EVAL_ERROR } },
{ .object = { .type = NJS_OBJECT_INTERNAL_ERROR } },
@@ -214,6 +226,9 @@ njs_builtin_objects_create(njs_vm_t *vm)
{ njs_regexp_constructor,
{ NJS_SKIP_ARG, NJS_STRING_ARG, NJS_STRING_ARG } },
{ njs_date_constructor, { 0 } },
+ { njs_hash_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } },
+ { njs_hmac_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG,
+ NJS_STRING_ARG } },
{ njs_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } },
{ njs_eval_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } },
{ njs_internal_error_constructor,
diff -r be43fdd9579e -r d3747fbfce39 njs/njs_crypto.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/njs/njs_crypto.c Fri Mar 30 18:50:38 2018 +0300
@@ -0,0 +1,713 @@
+
+/*
+ * Copyright (C) Dmitry Volyntsev
+ * Copyright (C) NGINX, Inc.
+ */
+
+#include <nxt_auto_config.h>
+#include <nxt_types.h>
+#include <nxt_clang.h>
+#include <nxt_string.h>
+#include <nxt_stub.h>
+#include <nxt_djb_hash.h>
+#include <nxt_array.h>
+#include <nxt_lvlhsh.h>
+#include <nxt_random.h>
+#include <nxt_md5.h>
+#include <nxt_sha1.h>
+#include <nxt_sha2.h>
+#include <nxt_mem_cache_pool.h>
+#include <njscript.h>
+#include <njs_vm.h>
+#include <njs_crypto.h>
+#include <njs_object.h>
+#include <njs_object_hash.h>
+#include <njs_string.h>
+#include <njs_function.h>
+#include <njs_error.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+
+typedef void (*njs_hash_init)(void *ctx);
+typedef void (*njs_hash_update)(void *ctx, const void *data, size_t size);
+typedef void (*njs_hash_final)(u_char *result, void *ctx);
+
+typedef njs_ret_t (*njs_digest_encode)(njs_vm_t *vm, njs_value_t *value,
+ const nxt_str_t *src);
+
+
+typedef struct {
+ nxt_str_t name;
+
+ size_t size;
+ njs_hash_init init;
+ njs_hash_update update;
+ njs_hash_final final;
+} njs_hash_alg_t;
+
+typedef struct {
+ union {
+ nxt_md5_t md5;
+ nxt_sha1_t sha1;
+ nxt_sha2_t sha2;
+ } u;
+
+ njs_hash_alg_t *alg;
+} njs_digest_t;
+
+typedef struct {
+ nxt_str_t key;
+ u_char opad[64];
+
+ union {
+ nxt_md5_t md5;
+ nxt_sha1_t sha1;
+ nxt_sha2_t sha2;
+ } u;
+
+ njs_hash_alg_t *alg;
+} njs_hmac_t;
+
+
+typedef struct {
+ nxt_str_t name;
+
+ njs_digest_encode encode;
+} njs_crypto_enc_t;
+
+
+static njs_hash_alg_t njs_hash_algorithms[] = {
+
+ {
+ nxt_string("md5"),
+ 16,
+ (njs_hash_init) nxt_md5_init,
+ (njs_hash_update) nxt_md5_update,
+ (njs_hash_final) nxt_md5_final
+ },
+
+ {
+ nxt_string("sha1"),
+ 20,
+ (njs_hash_init) nxt_sha1_init,
+ (njs_hash_update) nxt_sha1_update,
+ (njs_hash_final) nxt_sha1_final
+ },
+
+ {
+ nxt_string("sha256"),
+ 32,
+ (njs_hash_init) nxt_sha2_init,
+ (njs_hash_update) nxt_sha2_update,
+ (njs_hash_final) nxt_sha2_final
+ },
+
+ {
+ nxt_null_string,
+ 0,
+ NULL,
+ NULL,
+ NULL
+ }
+
+};
+
+static njs_crypto_enc_t njs_encodings[] = {
+
+ {
+ nxt_string("hex"),
+ njs_string_hex
+ },
+
+ {
+ nxt_string("base64"),
+ njs_string_base64
+ },
+
+ {
+ nxt_null_string,
+ NULL
+ }
+};
+
+
+static njs_hash_alg_t *njs_crypto_alg(njs_vm_t *vm, const nxt_str_t *name);
+static njs_crypto_enc_t *njs_crypto_encoding(njs_vm_t *vm,
+ const nxt_str_t *name);
+
+
+static njs_object_value_t *
+njs_crypto_object_value_alloc(njs_vm_t *vm, nxt_uint_t proto)
+{
+ njs_object_value_t *ov;
+
+ ov = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_object_value_t));
+
+ if (nxt_fast_path(ov != NULL)) {
+ nxt_lvlhsh_init(&ov->object.hash);
+ nxt_lvlhsh_init(&ov->object.shared_hash);
+ ov->object.type = NJS_OBJECT_VALUE;
+ ov->object.shared = 0;
+ ov->object.extensible = 1;
+
+ ov->object.__proto__ = &vm->prototypes[proto].object;
+ }
+
+ return ov;
+}
+
+
+static njs_ret_t
+njs_crypto_create_hash(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+ njs_index_t unused)
+{
+ nxt_str_t alg_name;
+ njs_digest_t *dgst;
+ njs_hash_alg_t *alg;
+ njs_object_value_t *hash;
+
+ if (nxt_slow_path(nargs < 2 || !njs_is_string(&args[1]))) {
+ njs_type_error(vm, "algorithm must be a string", NULL);
+ return NJS_ERROR;
+ }
+
+ njs_string_get(&args[1], &alg_name);
+
+ alg = njs_crypto_alg(vm, &alg_name);
+ if (nxt_slow_path(alg == NULL)) {
+ return NJS_ERROR;
+ }
+
+ hash = njs_crypto_object_value_alloc(vm, NJS_PROTOTYPE_CRYPTO_HASH);
+ if (nxt_slow_path(hash == NULL)) {
+ goto memory_error;
+ }
+
+ dgst = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_digest_t));
+ if (nxt_slow_path(dgst == NULL)) {
+ goto memory_error;
+ }
+
+ dgst->alg = alg;
+
+ alg->init(&dgst->u);
+
+ njs_value_data_set(&hash->value, dgst);
+
+ vm->retval.data.u.object_value = hash;
+ vm->retval.type = NJS_OBJECT_VALUE;
+ vm->retval.data.truth = 1;
+
+ return NJS_OK;
+
+memory_error:
+
+ njs_memory_error(vm);
+
+ return NJS_ERROR;
+}
+
+
+static njs_ret_t
+njs_hash_prototype_update(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+ njs_index_t unused)
+{
+ nxt_str_t data;
+ njs_digest_t *dgst;
+ njs_object_value_t *hash;
+
+ if (nxt_slow_path(nargs < 2 || !njs_is_string(&args[1]))) {
+ njs_type_error(vm, "data must be a string", NULL);
+ return NJS_ERROR;
+ }
+
+ if (nxt_slow_path(!njs_is_object_value(&args[0]))) {
+ njs_type_error(vm, "'this' is not an object_value", NULL);
+ return NJS_ERROR;
+ }
+
+ if (nxt_slow_path(!njs_is_data(&args[0].data.u.object_value->value))) {
+ njs_type_error(vm, "value of 'this' is not a data type", NULL);
+ return NJS_ERROR;
+ }
+
+ hash = args[0].data.u.object_value;
+
+ njs_string_get(&args[1], &data);
+
+ dgst = njs_value_data(&hash->value);
+ dgst->alg->update(&dgst->u, data.start, data.length);
+
+ vm->retval = args[0];
+
+ return NJS_OK;
+}
+
+
+static njs_ret_t
+njs_hash_prototype_digest(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+ njs_index_t unused)
+{
+ u_char digest[32], *p;
+ njs_ret_t ret;
+ nxt_str_t enc_name, str;
+ njs_digest_t *dgst;
+ njs_hash_alg_t *alg;
+ njs_crypto_enc_t *enc;
+ njs_object_value_t *hash;
+
+ if (nxt_slow_path(nargs > 1 && !njs_is_string(&args[1]))) {
+ njs_type_error(vm, "encoding must be a string", NULL);
+ return NJS_ERROR;
+ }
+
+ if (nxt_slow_path(!njs_is_object_value(&args[0]))) {
+ njs_type_error(vm, "'this' is not an object_value", NULL);
+ return NJS_ERROR;
+ }
+
+ if (nxt_slow_path(!njs_is_data(&args[0].data.u.object_value->value))) {
+ njs_type_error(vm, "value of 'this' is not a data type", NULL);
+ return NJS_ERROR;
+ }
+
+ enc = NULL;
+
+ if (nargs > 1) {
+ njs_string_get(&args[1], &enc_name);
+
+ enc = njs_crypto_encoding(vm, &enc_name);
+ if (nxt_slow_path(enc == NULL)) {
+ return NJS_ERROR;
+ }
+ }
+
+ hash = args[0].data.u.object_value;
+
+ dgst = njs_value_data(&hash->value);
+
+ if (nxt_slow_path(dgst->alg == NULL)) {
+ njs_error(vm, "Digest already called", NULL);
+ return NJS_ERROR;
+ }
+
+ alg = dgst->alg;
+
+ alg->final(digest, &dgst->u);
+
+ str.start = digest;
+ str.length = alg->size;
+
+ if (enc == NULL) {
+ p = njs_string_alloc(vm, &vm->retval, str.length, 0);
+
+ if (nxt_fast_path(p != NULL)) {
+ memcpy(p, str.start, str.length);
+ ret = NJS_OK;
+
+ } else {
+ ret = NJS_ERROR;
+ }
+
+ } else {
+ ret = enc->encode(vm, &vm->retval, &str);
+ }
+
+ dgst->alg = NULL;
+
+ return ret;
+}
+
+
+static njs_ret_t
+njs_hash_prototype_to_string(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+ njs_index_t unused)
+{
+ static const njs_value_t string = njs_string("[object Hash]");
+
+ vm->retval = string;
+
+ return NJS_OK;
+}
+
+
+static const njs_object_prop_t njs_hash_prototype_properties[] =
+{
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("name"),
+ .value = njs_string("Hash"),
+ },
+
+ {
+ .type = NJS_METHOD,
+ .name = njs_string("toString"),
+ .value = njs_native_function(njs_hash_prototype_to_string, 0, 0),
+ },
+
+ {
+ .type = NJS_METHOD,
+ .name = njs_string("update"),
+ .value = njs_native_function(njs_hash_prototype_update, 0,
+ NJS_OBJECT_ARG, NJS_SKIP_ARG),
+ },
+
+ {
+ .type = NJS_METHOD,
+ .name = njs_string("digest"),
+ .value = njs_native_function(njs_hash_prototype_digest, 0,
+ NJS_OBJECT_ARG, NJS_SKIP_ARG),
+ },
+};
+
+
+const njs_object_init_t njs_hash_prototype_init = {
+ nxt_string("Hash"),
+ njs_hash_prototype_properties,
+ nxt_nitems(njs_hash_prototype_properties),
+};
+
+
+njs_ret_t
+njs_hash_constructor(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused)
+{
+ return njs_crypto_create_hash(vm, args, nargs, unused);
+}
+
+
+const njs_object_init_t njs_hash_constructor_init = {
+ nxt_string("Hash"),
+ NULL,
+ 0,
+};
+
+
+static njs_ret_t
+njs_crypto_create_hmac(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+ njs_index_t unused)
+{
+ u_char digest[32], key_buf[64];
+ nxt_str_t alg_name, key;
+ nxt_uint_t i;
+ njs_hmac_t *ctx;
+ njs_hash_alg_t *alg;
+ njs_object_value_t *hmac;
+
+ if (nxt_slow_path(nargs < 2 || !njs_is_string(&args[1]))) {
+ njs_type_error(vm, "algorithm must be a string", NULL);
+ return NJS_ERROR;
+ }
+
+ if (nxt_slow_path(nargs < 3 || !njs_is_string(&args[2]))) {
+ njs_type_error(vm, "key must be a string", NULL);
+ return NJS_ERROR;
+ }
+
+ njs_string_get(&args[1], &alg_name);
+
+ alg = njs_crypto_alg(vm, &alg_name);
+ if (nxt_slow_path(alg == NULL)) {
+ return NJS_ERROR;
+ }
+
+ njs_string_get(&args[2], &key);
+
+ ctx = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_hmac_t));
+ if (nxt_slow_path(ctx == NULL)) {
+ goto memory_error;
+ }
+
+ ctx->alg = alg;
+
+ if (key.length > 64) {
+ alg->init(&ctx->u);
+ alg->update(&ctx->u, key.start, key.length);
+ alg->final(digest, &ctx->u);
+
+ memcpy(key_buf, digest, alg->size);
+ memset(key_buf + alg->size, 0, sizeof(key_buf) - alg->size);
+
+ } else if (key.length < alg->size) {
+
+ memcpy(key_buf, key.start, key.length);
+ memset(key_buf + key.length, 0, sizeof(key_buf) - key.length);
+
+ } else {
+ memcpy(key_buf, key.start, sizeof(key_buf));
+ }
+
+ for (i = 0; i < 64; i++) {
+ ctx->opad[i] = key_buf[i] ^ 0x5c;
+ }
+
+ for (i = 0; i < 64; i++) {
+ key_buf[i] ^= 0x36;
+ }
+
+ alg->init(&ctx->u);
+ alg->update(&ctx->u, key_buf, 64);
+
+ hmac = njs_crypto_object_value_alloc(vm, NJS_PROTOTYPE_CRYPTO_HMAC);
+ if (nxt_slow_path(hmac == NULL)) {
+ goto memory_error;
+ }
+
+ njs_value_data_set(&hmac->value, ctx);
+
+ vm->retval.data.u.object_value = hmac;
+ vm->retval.type = NJS_OBJECT_VALUE;
+ vm->retval.data.truth = 1;
+
+ return NJS_OK;
+
+memory_error:
+
+ njs_memory_error(vm);
+
+ return NJS_ERROR;
+}
+
+
+static njs_ret_t
+njs_hmac_prototype_update(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+ njs_index_t unused)
+{
+ nxt_str_t data;
+ njs_hmac_t *ctx;
+ njs_object_value_t *hmac;
+
+ if (nxt_slow_path(nargs < 2 || !njs_is_string(&args[1]))) {
+ njs_type_error(vm, "data must be a string", NULL);
+ return NJS_ERROR;
+ }
+
+ if (nxt_slow_path(!njs_is_object_value(&args[0]))) {
+ njs_type_error(vm, "'this' is not an object_value", NULL);
+ return NJS_ERROR;
+ }
+
+ if (nxt_slow_path(!njs_is_data(&args[0].data.u.object_value->value))) {
+ njs_type_error(vm, "value of 'this' is not a data type", NULL);
+ return NJS_ERROR;
+ }
+
+ hmac = args[0].data.u.object_value;
+
+ njs_string_get(&args[1], &data);
+
+ ctx = njs_value_data(&hmac->value);
+ ctx->alg->update(&ctx->u, data.start, data.length);
+
+ vm->retval = args[0];
+
+ return NJS_OK;
+}
+
+
+static njs_ret_t
+njs_hmac_prototype_digest(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+ njs_index_t unused)
+{
+ u_char hash1[32], digest[32], *p;
+ nxt_str_t enc_name, str;
+ njs_ret_t ret;
+ njs_hmac_t *ctx;
+ njs_hash_alg_t *alg;
+ njs_crypto_enc_t *enc;
+ njs_object_value_t *hmac;
+
+ if (nxt_slow_path(nargs > 1 && !njs_is_string(&args[1]))) {
+ njs_type_error(vm, "encoding must be a string", NULL);
+ return NJS_ERROR;
+ }
+
+ if (nxt_slow_path(!njs_is_object_value(&args[0]))) {
+ njs_type_error(vm, "'this' is not an object_value", NULL);
+ return NJS_ERROR;
+ }
+
+ if (nxt_slow_path(!njs_is_data(&args[0].data.u.object_value->value))) {
+ njs_type_error(vm, "value of 'this' is not a data type", NULL);
+ return NJS_ERROR;
+ }
+
+ enc = NULL;
+
+ if (nargs > 1) {
+ njs_string_get(&args[1], &enc_name);
+
+ enc = njs_crypto_encoding(vm, &enc_name);
+ if (nxt_slow_path(enc == NULL)) {
+ return NJS_ERROR;
+ }
+ }
+
+ hmac = args[0].data.u.object_value;
+
+ ctx = njs_value_data(&hmac->value);
+
+ if (nxt_slow_path(ctx->alg == NULL)) {
+ njs_error(vm, "Digest already called", NULL);
+ return NJS_ERROR;
+ }
+
+ alg = ctx->alg;
+
+ alg->final(hash1, &ctx->u);
+
+ alg->init(&ctx->u);
+ alg->update(&ctx->u, ctx->opad, 64);
+ alg->update(&ctx->u, hash1, alg->size);
+ alg->final(digest, &ctx->u);
+
+ str.start = digest;
+ str.length = alg->size;
+
+ if (enc == NULL) {
+ p = njs_string_alloc(vm, &vm->retval, str.length, 0);
+
+ if (nxt_fast_path(p != NULL)) {
+ memcpy(p, str.start, str.length);
+ ret = NJS_OK;
+
+ } else {
+ ret = NJS_ERROR;
+ }
+
+ } else {
+ ret = enc->encode(vm, &vm->retval, &str);
+ }
+
+ ctx->alg = NULL;
+
+ return ret;
+}
+
+
+static njs_ret_t
+njs_hmac_prototype_to_string(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+ njs_index_t unused)
+{
+ static const njs_value_t string = njs_string("[object Hmac]");
+
+ vm->retval = string;
+
+ return NJS_OK;
+}
+
+
+static const njs_object_prop_t njs_hmac_prototype_properties[] =
+{
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("name"),
+ .value = njs_string("Hmac"),
+ },
+
+ {
+ .type = NJS_METHOD,
+ .name = njs_string("toString"),
+ .value = njs_native_function(njs_hmac_prototype_to_string, 0, 0),
+ },
+
+ {
+ .type = NJS_METHOD,
+ .name = njs_string("update"),
+ .value = njs_native_function(njs_hmac_prototype_update, 0,
+ NJS_OBJECT_ARG, NJS_SKIP_ARG),
+ },
+
+ {
+ .type = NJS_METHOD,
+ .name = njs_string("digest"),
+ .value = njs_native_function(njs_hmac_prototype_digest, 0,
+ NJS_OBJECT_ARG, NJS_SKIP_ARG),
+ },
+};
+
+
+const njs_object_init_t njs_hmac_prototype_init = {
+ nxt_string("Hmac"),
+ njs_hmac_prototype_properties,
+ nxt_nitems(njs_hmac_prototype_properties),
+};
+
+
+njs_ret_t
+njs_hmac_constructor(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused)
+{
+ return njs_crypto_create_hmac(vm, args, nargs, unused);
+}
+
+
+const njs_object_init_t njs_hmac_constructor_init = {
+ nxt_string("Hmac"),
+ NULL,
+ 0,
+};
+
+
+static const njs_object_prop_t njs_crypto_object_properties[] =
+{
+ {
+ .type = NJS_METHOD,
+ .name = njs_string("createHash"),
+ .value = njs_native_function(njs_crypto_create_hash, 0,
+ NJS_SKIP_ARG),
+ },
+
+ {
+ .type = NJS_METHOD,
+ .name = njs_string("createHmac"),
+ .value = njs_native_function(njs_crypto_create_hmac, 0,
+ NJS_SKIP_ARG),
+ },
+
+};
+
+
+const njs_object_init_t njs_crypto_object_init = {
+ nxt_string("crypto"),
+ njs_crypto_object_properties,
+ nxt_nitems(njs_crypto_object_properties),
+};
+
+
+static njs_hash_alg_t *
+njs_crypto_alg(njs_vm_t *vm, const nxt_str_t *name)
+{
+ njs_hash_alg_t *e;
+
+ for (e = &njs_hash_algorithms[0]; e->name.length != 0; e++) {
+ if (nxt_strstr_eq(name, &e->name)) {
+ return e;
+ }
+ }
+
+ njs_type_error(vm, "not supported algorithm: '%.*s'",
+ (int) name->length, name->start);
+
+ return NULL;
+}
+
+
+static njs_crypto_enc_t *
+njs_crypto_encoding(njs_vm_t *vm, const nxt_str_t *name)
+{
+ njs_crypto_enc_t *e;
+
+ for (e = &njs_encodings[0]; e->name.length != 0; e++) {
+ if (nxt_strstr_eq(name, &e->name)) {
+ return e;
+ }
+ }
+
+ njs_type_error(vm, "Unknown digest encoding: '%.*s'",
+ (int) name->length, name->start);
+
+ return NULL;
+}
diff -r be43fdd9579e -r d3747fbfce39 njs/njs_crypto.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/njs/njs_crypto.h Fri Mar 30 18:50:38 2018 +0300
@@ -0,0 +1,24 @@
+
+/*
+ * Copyright (C) Dmitry Volyntsev
+ * Copyright (C) NGINX, Inc.
+ */
+
+#ifndef _NJS_CRYPTO_H_INCLUDED_
+#define _NJS_CRYPTO_H_INCLUDED_
+
+njs_ret_t njs_hash_constructor(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused);
+njs_ret_t njs_hmac_constructor(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused);
+
+extern const njs_object_init_t njs_crypto_object_init;
+
+extern const njs_object_init_t njs_hash_prototype_init;
+extern const njs_object_init_t njs_hmac_prototype_init;
+
+extern const njs_object_init_t njs_hash_constructor_init;
+extern const njs_object_init_t njs_hmac_constructor_init;
+
+
+#endif /* _NJS_CRYPTO_H_INCLUDED_ */
diff -r be43fdd9579e -r d3747fbfce39 njs/njs_object.c
--- a/njs/njs_object.c Fri Mar 30 15:46:40 2018 +0300
+++ b/njs/njs_object.c Fri Mar 30 18:50:38 2018 +0300
@@ -1332,6 +1332,10 @@ static const njs_value_t njs_object_num
njs_long_string("[object Number]");
static const njs_value_t njs_object_string_string =
njs_long_string("[object String]");
+static const njs_value_t njs_object_data_string =
+ njs_string("[object Data]");
+static const njs_value_t njs_object_exernal_string =
+ njs_long_string("[object External]");
static const njs_value_t njs_object_object_string =
njs_long_string("[object Object]");
static const njs_value_t njs_object_array_string =
@@ -1357,6 +1361,9 @@ static const njs_value_t njs_object_typ
njs_long_string("[object TypeError]");
static const njs_value_t njs_object_uri_error_string =
njs_long_string("[object URIError]");
+static const njs_value_t njs_object_object_value_string =
+ njs_long_string("[object ObjectValue]");
+
njs_ret_t
@@ -1375,8 +1382,8 @@ njs_object_prototype_to_string(njs_vm_t
&njs_object_number_string,
&njs_object_string_string,
- &njs_string_empty,
- &njs_object_function_string,
+ &njs_object_data_string,
+ &njs_object_exernal_string,
&njs_string_empty,
&njs_string_empty,
&njs_string_empty,
@@ -1404,6 +1411,7 @@ njs_object_prototype_to_string(njs_vm_t
&njs_object_syntax_error_string,
&njs_object_type_error_string,
&njs_object_uri_error_string,
+ &njs_object_object_value_string,
};
index = args[0].type;
diff -r be43fdd9579e -r d3747fbfce39 njs/njs_vm.c
--- a/njs/njs_vm.c Fri Mar 30 15:46:40 2018 +0300
+++ b/njs/njs_vm.c Fri Mar 30 18:50:38 2018 +0300
@@ -1036,6 +1036,7 @@ njs_property_query(njs_vm_t *vm, njs_pro
case NJS_OBJECT_SYNTAX_ERROR:
case NJS_OBJECT_TYPE_ERROR:
case NJS_OBJECT_URI_ERROR:
+ case NJS_OBJECT_VALUE:
obj = object->data.u.object;
break;
@@ -3650,6 +3651,15 @@ njs_value_number_set(njs_value_t *value,
}
+nxt_noinline void
+njs_value_data_set(njs_value_t *value, void *data)
+{
+ value->data.u.data = data;
+ value->type = NJS_DATA;
+ value->data.truth = 1;
+}
+
+
void
njs_value_error_set(njs_vm_t *vm, njs_value_t *value, const char *fmt, ...)
{
diff -r be43fdd9579e -r d3747fbfce39 njs/njs_vm.h
--- a/njs/njs_vm.h Fri Mar 30 15:46:40 2018 +0300
+++ b/njs/njs_vm.h Fri Mar 30 18:50:38 2018 +0300
@@ -76,7 +76,7 @@ typedef enum {
/* The order of the above type is used in njs_is_primitive(). */
- /* Reserved 0x05, */
+ NJS_DATA = 0x05,
/* The type is external code. */
NJS_EXTERNAL = 0x06,
@@ -90,7 +90,7 @@ typedef enum {
NJS_INVALID = 0x07,
/*
- * The object types have the fourth bit set. It is used in njs_is_object().
+ * The object types are >= NJS_OBJECT, this is used in njs_is_object().
* NJS_OBJECT_BOOLEAN, NJS_OBJECT_NUMBER, and NJS_OBJECT_STRING must be
* in the same order as NJS_BOOLEAN, NJS_NUMBER, and NJS_STRING. It is
* used in njs_primitive_prototype_index(). The order of object types
@@ -112,6 +112,7 @@ typedef enum {
NJS_OBJECT_SYNTAX_ERROR = 0x1d,
NJS_OBJECT_TYPE_ERROR = 0x1e,
NJS_OBJECT_URI_ERROR = 0x1f,
+ NJS_OBJECT_VALUE = 0x20,
} njs_value_type_t;
@@ -154,7 +155,7 @@ union njs_value_s {
* the maximum size of short string to 13.
*/
struct {
- njs_value_type_t type:8; /* 5 bits */
+ njs_value_type_t type:8; /* 6 bits */
/*
* The truth field is set during value assignment and then can be
* quickly tested by logical and conditional operations regardless
@@ -184,7 +185,7 @@ union njs_value_s {
} data;
struct {
- njs_value_type_t type:8; /* 5 bits */
+ njs_value_type_t type:8; /* 6 bits */
#define NJS_STRING_SHORT 14
#define NJS_STRING_LONG 15
@@ -196,7 +197,7 @@ union njs_value_s {
} short_string;
struct {
- njs_value_type_t type:8; /* 5 bits */
+ njs_value_type_t type:8; /* 6 bits */
uint8_t truth;
/* 0xff if data is external string. */
@@ -208,7 +209,7 @@ union njs_value_s {
} long_string;
struct {
- njs_value_type_t type:8; /* 5 bits */
+ njs_value_type_t type:8; /* 6 bits */
uint8_t truth;
uint16_t _spare;
@@ -217,7 +218,7 @@ union njs_value_s {
More information about the nginx-devel
mailing list