$(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 \
$(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 \
$(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 \
$(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 \
-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 \
#include <njs_time.h>
#include <njs_module.h>
#include <njs_fs.h>
+#include <njs_crypto.h>
#include <string.h>
#include <stdio.h>
const njs_object_init_t *njs_module_init[] = {
- &njs_fs_object_init /* fs */
+ &njs_fs_object_init, /* fs */
+ &njs_crypto_object_init /* crypto */
};
&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,
&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,
{ .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 } },
{ 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,
--- /dev/null
+
+/*
+ * 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;
+}
--- /dev/null
+
+/*
+ * 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_ */
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 =
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
&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,
&njs_object_syntax_error_string,
&njs_object_type_error_string,
&njs_object_uri_error_string,
+ &njs_object_object_value_string,
};
index = args[0].type;
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;
}
+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, ...)
{
/* 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,
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
NJS_OBJECT_SYNTAX_ERROR = 0x1d,
NJS_OBJECT_TYPE_ERROR = 0x1e,
NJS_OBJECT_URI_ERROR = 0x1f,
+ NJS_OBJECT_VALUE = 0x20,
} njs_value_type_t;
* 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
} 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
} 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. */
} 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;
const njs_extern_t *proto;
} external;
- njs_value_type_t type:8; /* 5 bits */
+ njs_value_type_t type:8; /* 6 bits */
};
((value)->type <= NJS_STRING)
+#define njs_is_data(value) \
+ ((value)->type == NJS_DATA)
+
+
#define njs_is_object(value) \
- (((value)->type & NJS_OBJECT) != 0)
+ ((value)->type >= NJS_OBJECT)
+
+
+#define njs_is_object_value(value) \
+ ((value)->type == NJS_OBJECT_VALUE)
#define njs_object_value_type(type) \
NJS_PROTOTYPE_FUNCTION,
NJS_PROTOTYPE_REGEXP,
NJS_PROTOTYPE_DATE,
+ NJS_PROTOTYPE_CRYPTO_HASH,
+ NJS_PROTOTYPE_CRYPTO_HMAC,
NJS_PROTOTYPE_ERROR,
NJS_PROTOTYPE_EVAL_ERROR,
NJS_PROTOTYPE_INTERNAL_ERROR,
NJS_CONSTRUCTOR_FUNCTION = NJS_PROTOTYPE_FUNCTION,
NJS_CONSTRUCTOR_REGEXP = NJS_PROTOTYPE_REGEXP,
NJS_CONSTRUCTOR_DATE = NJS_PROTOTYPE_DATE,
+ NJS_CONSTRUCTOR_CRYPTO_HASH = NJS_PROTOTYPE_CRYPTO_HASH,
+ NJS_CONSTRUCTOR_CRYPTO_HMAC = NJS_PROTOTYPE_CRYPTO_HMAC,
NJS_CONSTRUCTOR_ERROR = NJS_PROTOTYPE_ERROR,
NJS_CONSTRUCTOR_EVAL_ERROR = NJS_PROTOTYPE_EVAL_ERROR,
NJS_CONSTRUCTOR_INTERNAL_ERROR = NJS_PROTOTYPE_INTERNAL_ERROR,
enum njs_module_e {
NJS_MODULE_FS = 0,
-#define NJS_MODULE_MAX (NJS_MODULE_FS + 1)
+ NJS_MODULE_CRYPTO,
+#define NJS_MODULE_MAX (NJS_MODULE_CRYPTO + 1)
};
NXT_EXPORT void njs_value_void_set(njs_value_t *value);
NXT_EXPORT void njs_value_boolean_set(njs_value_t *value, int yn);
NXT_EXPORT void njs_value_number_set(njs_value_t *value, double num);
+NXT_EXPORT void njs_value_data_set(njs_value_t *value, void *data);
NXT_EXPORT void njs_value_error_set(njs_vm_t *vm, njs_value_t *value,
const char *fmt, ...);
" at setTimeout (native)\n"
" at main (native)\n") },
+ { nxt_string("require('crypto').createHash('sha')" ENTER),
+ nxt_string("TypeError: not supported algorithm: 'sha'\n"
+ " at crypto.createHash (native)\n"
+ " at main (native)\n") },
+
+ { nxt_string("var h = require('crypto').createHash('sha1')" ENTER
+ "h.update([])" ENTER),
+ nxt_string("TypeError: data must be a string\n"
+ " at Hash.prototype.update (native)\n"
+ " at main (native)\n") },
+
+ { nxt_string("require('crypto').createHmac('sha1', [])" ENTER),
+ nxt_string("TypeError: key must be a string\n"
+ " at crypto.createHmac (native)\n"
+ " at main (native)\n") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha1', 'secret')" ENTER
+ "h.update([])" ENTER),
+ nxt_string("TypeError: data must be a string\n"
+ " at Hmac.prototype.update (native)\n"
+ " at main (native)\n") },
+
{ nxt_string("function f(o) {function f_in(o) {return o.a.a};"
" return f_in(o)}; f({})" ENTER),
nxt_string("TypeError: cannot get property 'a' of undefined\n"
"fs.writeFileSync('/njs_unknown_path', '', true)"),
nxt_string("TypeError: Unknown options type (a string or object required)") },
+ /* require('crypto').createHash() */
+
+ { nxt_string("require('crypto').createHash('sha1')"),
+ nxt_string("[object Hash]") },
+
+ { nxt_string("var h = require('crypto').createHash('md5');"
+ "h.update('AB').digest('hex')"),
+ nxt_string("b86fc6b051f63d73de262d4c34e3a0a9") },
+
+ { nxt_string("var h = require('crypto').createHash('sha1');"
+ "h.update('A').update('B').digest('hex')"),
+ nxt_string("06d945942aa26a61be18c3e22bf19bbca8dd2b5d") },
+
+ { nxt_string("var h = require('crypto').createHash('sha1');"
+ "h.update('AB').digest('hex')"),
+ nxt_string("06d945942aa26a61be18c3e22bf19bbca8dd2b5d") },
+
+ { nxt_string("var h = require('crypto').createHash('sha1');"
+ "h.update('AB').digest().toString('hex')"),
+ nxt_string("06d945942aa26a61be18c3e22bf19bbca8dd2b5d") },
+
+ { nxt_string("var h = require('crypto').createHash('sha1');"
+ "h.update('AB').digest('base64')"),
+ nxt_string("BtlFlCqiamG+GMPiK/GbvKjdK10=") },
+
+ { nxt_string("var h = require('crypto').createHash('sha1');"
+ "h.update('AB').digest().toString('base64')"),
+ nxt_string("BtlFlCqiamG+GMPiK/GbvKjdK10=") },
+
+ { nxt_string("var h = require('crypto').createHash('sha1');"
+ "h.update('abc'.repeat(100)).digest('hex')"),
+ nxt_string("c95466320eaae6d19ee314ae4f135b12d45ced9a") },
+
+ { nxt_string("var h = require('crypto').createHash('sha256');"
+ "h.update('A').update('B').digest('hex')"),
+ nxt_string("38164fbd17603d73f696b8b4d72664d735bb6a7c88577687fd2ae33fd6964153") },
+
+ { nxt_string("var h = require('crypto').createHash('sha256');"
+ "h.update('AB').digest('hex')"),
+ nxt_string("38164fbd17603d73f696b8b4d72664d735bb6a7c88577687fd2ae33fd6964153") },
+
+ { nxt_string("var h = require('crypto').createHash('sha256');"
+ "h.update('abc'.repeat(100)).digest('hex')"),
+ nxt_string("d9f5aeb06abebb3be3f38adec9a2e3b94228d52193be923eb4e24c9b56ee0930") },
+
+ { nxt_string("var h = require('crypto').createHash()"),
+ nxt_string("TypeError: algorithm must be a string") },
+
+ { nxt_string("var h = require('crypto').createHash([])"),
+ nxt_string("TypeError: algorithm must be a string") },
+
+ { nxt_string("var h = require('crypto').createHash('sha512')"),
+ nxt_string("TypeError: not supported algorithm: 'sha512'") },
+
+ { nxt_string("var h = require('crypto').createHash('sha1');"
+ "h.update()"),
+ nxt_string("TypeError: data must be a string") },
+
+ { nxt_string("var h = require('crypto').createHash('sha1');"
+ "h.update({})"),
+ nxt_string("TypeError: data must be a string") },
+
+ { nxt_string("var h = require('crypto').createHash('sha1');"
+ "h.update('A').digest('latin1')"),
+ nxt_string("TypeError: Unknown digest encoding: 'latin1'") },
+
+ { nxt_string("var h = require('crypto').createHash('sha1');"
+ "h.update('A').digest('hex'); h.digest('hex')"),
+ nxt_string("Error: Digest already called") },
+
+ /* require('crypto').createHash() */
+
+ { nxt_string("require('crypto').createHmac('sha1', '')"),
+ nxt_string("[object Hmac]") },
+
+ { nxt_string("var h = require('crypto').createHmac('md5', '');"
+ "h.digest('hex')"),
+ nxt_string("74e6f7298a9c2d168935f58c001bad88") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha1', '');"
+ "h.digest('hex')"),
+ nxt_string("fbdb1d1b18aa6c08324b7d64b71fb76370690e1d") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha1', '');"
+ "h.digest().toString('hex')"),
+ nxt_string("fbdb1d1b18aa6c08324b7d64b71fb76370690e1d") },
+
+ { nxt_string("var h = require('crypto').createHmac('md5', 'secret key');"
+ "h.update('AB').digest('hex')"),
+ nxt_string("9c72728915eb26620a5caeafd0063b29") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha1', 'secret key');"
+ "h.update('A').update('B').digest('hex')"),
+ nxt_string("adc60e03459c4bae7cf4eb6d9730003e9490b22f") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha1', 'secret key');"
+ "h.update('AB').digest('hex')"),
+ nxt_string("adc60e03459c4bae7cf4eb6d9730003e9490b22f") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha1', 'secret key');"
+ "h.update('AB').digest('base64')"),
+ nxt_string("rcYOA0WcS6589OttlzAAPpSQsi8=") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha1', 'secret key');"
+ "h.update('AB').digest().toString('base64')"),
+ nxt_string("rcYOA0WcS6589OttlzAAPpSQsi8=") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha1', 'secret key');"
+ "h.update('abc'.repeat(100)).digest('hex')"),
+ nxt_string("b105ad6921e4c54d3fa0a9ec3f7f0ee9bd2c659d") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha1', 'A'.repeat(64));"
+ "h.update('AB').digest('hex')"),
+ nxt_string("400ce530816c6b3247e2959f3982a12aaf58c0c9") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha1', 'A'.repeat(100));"
+ "h.update('AB').digest('hex')"),
+ nxt_string("670e7cdebae6392797e000e79e51d3b6589d8fad") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha256', '');"
+ "h.digest('hex')"),
+ nxt_string("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha256', 'secret key');"
+ "h.update('A').update('B').digest('hex')"),
+ nxt_string("46085184b3b45a13d838bf71a0ce03675dab30931e0f1f68fa636ea65fdb286d") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha256', 'secret key');"
+ "h.update('AB').digest('hex')"),
+ nxt_string("46085184b3b45a13d838bf71a0ce03675dab30931e0f1f68fa636ea65fdb286d") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha256', 'A'.repeat(64));"
+ "h.update('AB').digest('hex')"),
+ nxt_string("ee9dce43b12eb3e865614ad9c1a8d4fad4b6eac2b64647bd24cd192888d3f367") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha256', 'A'.repeat(100));"
+ "h.update('AB').digest('hex')"),
+ nxt_string("5647b6c429701ff512f0f18232b4507065d2376ca8899a816a0a6e721bf8ddcc") },
+
+ { nxt_string("var h = require('crypto').createHmac('md5', 'secret key');"
+ "h.update('abc'.repeat(100)).digest('hex')"),
+ nxt_string("5dd706af43536f8c9c83e7ea55b1a5a2") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha1', 'secret key');"
+ "h.update('abc'.repeat(100)).digest('hex')"),
+ nxt_string("b105ad6921e4c54d3fa0a9ec3f7f0ee9bd2c659d") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha256', 'secret key');"
+ "h.update('abc'.repeat(100)).digest('hex')"),
+ nxt_string("f6550d398ce350ee8d94a0f44f2cf6b9bc8d316ae4625fb4434f22980a276bac") },
+
+ { nxt_string("var h = require('crypto').createHmac()"),
+ nxt_string("TypeError: algorithm must be a string") },
+
+ { nxt_string("var h = require('crypto').createHmac([])"),
+ nxt_string("TypeError: algorithm must be a string") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha512', '')"),
+ nxt_string("TypeError: not supported algorithm: 'sha512'") },
+
+ { nxt_string("var h = require('crypto').createHmac('sha1', [])"),
+ nxt_string("TypeError: key must be a string") },
+
/* setTimeout(). */
{ nxt_string("setTimeout()"),
$(NXT_BUILDDIR)/nxt_rbtree.o \
$(NXT_BUILDDIR)/nxt_lvlhsh.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_trace.o \
$(NXT_BUILDDIR)/nxt_rbtree.o \
$(NXT_BUILDDIR)/nxt_lvlhsh.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_trace.o \
-I$(NXT_LIB) \
$(NXT_LIB)/nxt_random.c
+$(NXT_BUILDDIR)/nxt_md5.o: \
+ $(NXT_LIB)/nxt_types.h \
+ $(NXT_LIB)/nxt_clang.h \
+ $(NXT_LIB)/nxt_md5.h \
+ $(NXT_LIB)/nxt_md5.c \
+
+ $(NXT_CC) -c -o $(NXT_BUILDDIR)/nxt_md5.o $(NXT_CFLAGS) \
+ -I$(NXT_LIB) \
+ $(NXT_LIB)/nxt_md5.c
+
+$(NXT_BUILDDIR)/nxt_sha1.o: \
+ $(NXT_LIB)/nxt_types.h \
+ $(NXT_LIB)/nxt_clang.h \
+ $(NXT_LIB)/nxt_sha1.h \
+ $(NXT_LIB)/nxt_sha1.c \
+
+ $(NXT_CC) -c -o $(NXT_BUILDDIR)/nxt_sha1.o $(NXT_CFLAGS) \
+ -I$(NXT_LIB) \
+ $(NXT_LIB)/nxt_sha1.c
+
+$(NXT_BUILDDIR)/nxt_sha2.o: \
+ $(NXT_LIB)/nxt_types.h \
+ $(NXT_LIB)/nxt_clang.h \
+ $(NXT_LIB)/nxt_sha2.h \
+ $(NXT_LIB)/nxt_sha2.c \
+
+ $(NXT_CC) -c -o $(NXT_BUILDDIR)/nxt_sha2.o $(NXT_CFLAGS) \
+ -I$(NXT_LIB) \
+ $(NXT_LIB)/nxt_sha2.c
+
$(NXT_BUILDDIR)/nxt_pcre.o: \
$(NXT_LIB)/nxt_types.h \
$(NXT_LIB)/nxt_clang.h \
--- /dev/null
+
+/*
+ * An internal implementation, based on Alexander Peslyak's
+ * public domain implementation:
+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ */
+
+
+#include <nxt_auto_config.h>
+#include <nxt_types.h>
+#include <nxt_clang.h>
+#include <nxt_md5.h>
+#include <string.h>
+
+
+static const u_char *nxt_md5_body(nxt_md5_t *ctx, const u_char *data,
+ size_t size);
+
+
+void
+nxt_md5_init(nxt_md5_t *ctx)
+{
+ ctx->a = 0x67452301;
+ ctx->b = 0xefcdab89;
+ ctx->c = 0x98badcfe;
+ ctx->d = 0x10325476;
+
+ ctx->bytes = 0;
+}
+
+
+void
+nxt_md5_update(nxt_md5_t *ctx, const void *data, size_t size)
+{
+ size_t used, free;
+
+ used = (size_t) (ctx->bytes & 0x3f);
+ ctx->bytes += size;
+
+ if (used) {
+ free = 64 - used;
+
+ if (size < free) {
+ memcpy(&ctx->buffer[used], data, size);
+ return;
+ }
+
+ memcpy(&ctx->buffer[used], data, free);
+ data = (u_char *) data + free;
+ size -= free;
+ (void) nxt_md5_body(ctx, ctx->buffer, 64);
+ }
+
+ if (size >= 64) {
+ data = nxt_md5_body(ctx, data, size & ~(size_t) 0x3f);
+ size &= 0x3f;
+ }
+
+ memcpy(ctx->buffer, data, size);
+}
+
+
+void
+nxt_md5_final(u_char result[16], nxt_md5_t *ctx)
+{
+ size_t used, free;
+
+ used = (size_t) (ctx->bytes & 0x3f);
+
+ ctx->buffer[used++] = 0x80;
+
+ free = 64 - used;
+
+ if (free < 8) {
+ memset(&ctx->buffer[used], 0, free);
+ (void) nxt_md5_body(ctx, ctx->buffer, 64);
+ used = 0;
+ free = 64;
+ }
+
+ memset(&ctx->buffer[used], 0, free - 8);
+
+ ctx->bytes <<= 3;
+ ctx->buffer[56] = (u_char) ctx->bytes;
+ ctx->buffer[57] = (u_char) (ctx->bytes >> 8);
+ ctx->buffer[58] = (u_char) (ctx->bytes >> 16);
+ ctx->buffer[59] = (u_char) (ctx->bytes >> 24);
+ ctx->buffer[60] = (u_char) (ctx->bytes >> 32);
+ ctx->buffer[61] = (u_char) (ctx->bytes >> 40);
+ ctx->buffer[62] = (u_char) (ctx->bytes >> 48);
+ ctx->buffer[63] = (u_char) (ctx->bytes >> 56);
+
+ (void) nxt_md5_body(ctx, ctx->buffer, 64);
+
+ result[0] = (u_char) ctx->a;
+ result[1] = (u_char) (ctx->a >> 8);
+ result[2] = (u_char) (ctx->a >> 16);
+ result[3] = (u_char) (ctx->a >> 24);
+ result[4] = (u_char) ctx->b;
+ result[5] = (u_char) (ctx->b >> 8);
+ result[6] = (u_char) (ctx->b >> 16);
+ result[7] = (u_char) (ctx->b >> 24);
+ result[8] = (u_char) ctx->c;
+ result[9] = (u_char) (ctx->c >> 8);
+ result[10] = (u_char) (ctx->c >> 16);
+ result[11] = (u_char) (ctx->c >> 24);
+ result[12] = (u_char) ctx->d;
+ result[13] = (u_char) (ctx->d >> 8);
+ result[14] = (u_char) (ctx->d >> 16);
+ result[15] = (u_char) (ctx->d >> 24);
+
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+
+/*
+ * The basic MD5 functions.
+ *
+ * F and G are optimized compared to their RFC 1321 definitions for
+ * architectures that lack an AND-NOT instruction, just like in
+ * Colin Plumb's implementation.
+ */
+
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+
+/*
+ * The MD5 transformation for all four rounds.
+ */
+
+#define STEP(f, a, b, c, d, x, t, s) \
+ (a) += f((b), (c), (d)) + (x) + (t); \
+ (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
+ (a) += (b)
+
+/*
+ * SET() reads 4 input bytes in little-endian byte order and stores them
+ * in a properly aligned word in host byte order.
+ */
+
+#define SET(n) \
+ (block[n] = \
+ ( (uint32_t) p[n * 4] \
+ | ((uint32_t) p[n * 4 + 1] << 8) \
+ | ((uint32_t) p[n * 4 + 2] << 16) \
+ | ((uint32_t) p[n * 4 + 3] << 24))) \
+
+#define GET(n) block[n]
+
+
+/*
+ * This processes one or more 64-byte data blocks, but does not update
+ * the bit counters. There are no alignment requirements.
+ */
+
+static const u_char *
+nxt_md5_body(nxt_md5_t *ctx, const u_char *data, size_t size)
+{
+ uint32_t a, b, c, d;
+ uint32_t saved_a, saved_b, saved_c, saved_d;
+ const u_char *p;
+ uint32_t block[16];
+
+ p = data;
+
+ a = ctx->a;
+ b = ctx->b;
+ c = ctx->c;
+ d = ctx->d;
+
+ do {
+ saved_a = a;
+ saved_b = b;
+ saved_c = c;
+ saved_d = d;
+
+ /* Round 1 */
+
+ STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7);
+ STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12);
+ STEP(F, c, d, a, b, SET(2), 0x242070db, 17);
+ STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22);
+ STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7);
+ STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12);
+ STEP(F, c, d, a, b, SET(6), 0xa8304613, 17);
+ STEP(F, b, c, d, a, SET(7), 0xfd469501, 22);
+ STEP(F, a, b, c, d, SET(8), 0x698098d8, 7);
+ STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12);
+ STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17);
+ STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22);
+ STEP(F, a, b, c, d, SET(12), 0x6b901122, 7);
+ STEP(F, d, a, b, c, SET(13), 0xfd987193, 12);
+ STEP(F, c, d, a, b, SET(14), 0xa679438e, 17);
+ STEP(F, b, c, d, a, SET(15), 0x49b40821, 22);
+
+ /* Round 2 */
+
+ STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5);
+ STEP(G, d, a, b, c, GET(6), 0xc040b340, 9);
+ STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14);
+ STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20);
+ STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5);
+ STEP(G, d, a, b, c, GET(10), 0x02441453, 9);
+ STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14);
+ STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20);
+ STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5);
+ STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9);
+ STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14);
+ STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20);
+ STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5);
+ STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9);
+ STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14);
+ STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20);
+
+ /* Round 3 */
+
+ STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4);
+ STEP(H, d, a, b, c, GET(8), 0x8771f681, 11);
+ STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16);
+ STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23);
+ STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4);
+ STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11);
+ STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16);
+ STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23);
+ STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4);
+ STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11);
+ STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16);
+ STEP(H, b, c, d, a, GET(6), 0x04881d05, 23);
+ STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4);
+ STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11);
+ STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16);
+ STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23);
+
+ /* Round 4 */
+
+ STEP(I, a, b, c, d, GET(0), 0xf4292244, 6);
+ STEP(I, d, a, b, c, GET(7), 0x432aff97, 10);
+ STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15);
+ STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21);
+ STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6);
+ STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10);
+ STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15);
+ STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21);
+ STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6);
+ STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10);
+ STEP(I, c, d, a, b, GET(6), 0xa3014314, 15);
+ STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21);
+ STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6);
+ STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10);
+ STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15);
+ STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21);
+
+ a += saved_a;
+ b += saved_b;
+ c += saved_c;
+ d += saved_d;
+
+ p += 64;
+
+ } while (size -= 64);
+
+ ctx->a = a;
+ ctx->b = b;
+ ctx->c = c;
+ ctx->d = d;
+
+ return p;
+}
--- /dev/null
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NXT_MD5_H_INCLUDED_
+#define _NXT_MD5_H_INCLUDED_
+
+
+typedef struct {
+ uint64_t bytes;
+ uint32_t a, b, c, d;
+ u_char buffer[64];
+} nxt_md5_t;
+
+
+NXT_EXPORT void nxt_md5_init(nxt_md5_t *ctx);
+NXT_EXPORT void nxt_md5_update(nxt_md5_t *ctx, const void *data, size_t size);
+NXT_EXPORT void nxt_md5_final(u_char result[16], nxt_md5_t *ctx);
+
+#endif /* _NXT_MD5_H_INCLUDED_ */
--- /dev/null
+
+/*
+ * Copyright (C) Maxim Dounin
+ * Copyright (C) NGINX, Inc.
+ *
+ * An internal SHA1 implementation.
+ */
+
+
+#include <nxt_auto_config.h>
+#include <nxt_types.h>
+#include <nxt_clang.h>
+#include <nxt_sha1.h>
+#include <string.h>
+
+
+static const u_char *nxt_sha1_body(nxt_sha1_t *ctx, const u_char *data,
+ size_t size);
+
+
+void
+nxt_sha1_init(nxt_sha1_t *ctx)
+{
+ ctx->a = 0x67452301;
+ ctx->b = 0xefcdab89;
+ ctx->c = 0x98badcfe;
+ ctx->d = 0x10325476;
+ ctx->e = 0xc3d2e1f0;
+
+ ctx->bytes = 0;
+}
+
+
+void
+nxt_sha1_update(nxt_sha1_t *ctx, const void *data, size_t size)
+{
+ size_t used, free;
+
+ used = (size_t) (ctx->bytes & 0x3f);
+ ctx->bytes += size;
+
+ if (used) {
+ free = 64 - used;
+
+ if (size < free) {
+ memcpy(&ctx->buffer[used], data, size);
+ return;
+ }
+
+ memcpy(&ctx->buffer[used], data, free);
+ data = (u_char *) data + free;
+ size -= free;
+ (void) nxt_sha1_body(ctx, ctx->buffer, 64);
+ }
+
+ if (size >= 64) {
+ data = nxt_sha1_body(ctx, data, size & ~(size_t) 0x3f);
+ size &= 0x3f;
+ }
+
+ memcpy(ctx->buffer, data, size);
+}
+
+
+void
+nxt_sha1_final(u_char result[20], nxt_sha1_t *ctx)
+{
+ size_t used, free;
+
+ used = (size_t) (ctx->bytes & 0x3f);
+
+ ctx->buffer[used++] = 0x80;
+
+ free = 64 - used;
+
+ if (free < 8) {
+ memset(&ctx->buffer[used], 0, free);
+ (void) nxt_sha1_body(ctx, ctx->buffer, 64);
+ used = 0;
+ free = 64;
+ }
+
+ memset(&ctx->buffer[used], 0, free - 8);
+
+ ctx->bytes <<= 3;
+ ctx->buffer[56] = (u_char) (ctx->bytes >> 56);
+ ctx->buffer[57] = (u_char) (ctx->bytes >> 48);
+ ctx->buffer[58] = (u_char) (ctx->bytes >> 40);
+ ctx->buffer[59] = (u_char) (ctx->bytes >> 32);
+ ctx->buffer[60] = (u_char) (ctx->bytes >> 24);
+ ctx->buffer[61] = (u_char) (ctx->bytes >> 16);
+ ctx->buffer[62] = (u_char) (ctx->bytes >> 8);
+ ctx->buffer[63] = (u_char) ctx->bytes;
+
+ (void) nxt_sha1_body(ctx, ctx->buffer, 64);
+
+ result[0] = (u_char) (ctx->a >> 24);
+ result[1] = (u_char) (ctx->a >> 16);
+ result[2] = (u_char) (ctx->a >> 8);
+ result[3] = (u_char) ctx->a;
+ result[4] = (u_char) (ctx->b >> 24);
+ result[5] = (u_char) (ctx->b >> 16);
+ result[6] = (u_char) (ctx->b >> 8);
+ result[7] = (u_char) ctx->b;
+ result[8] = (u_char) (ctx->c >> 24);
+ result[9] = (u_char) (ctx->c >> 16);
+ result[10] = (u_char) (ctx->c >> 8);
+ result[11] = (u_char) ctx->c;
+ result[12] = (u_char) (ctx->d >> 24);
+ result[13] = (u_char) (ctx->d >> 16);
+ result[14] = (u_char) (ctx->d >> 8);
+ result[15] = (u_char) ctx->d;
+ result[16] = (u_char) (ctx->e >> 24);
+ result[17] = (u_char) (ctx->e >> 16);
+ result[18] = (u_char) (ctx->e >> 8);
+ result[19] = (u_char) ctx->e;
+
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+
+/*
+ * Helper functions.
+ */
+
+#define ROTATE(bits, word) (((word) << (bits)) | ((word) >> (32 - (bits))))
+
+#define F1(b, c, d) (((b) & (c)) | ((~(b)) & (d)))
+#define F2(b, c, d) ((b) ^ (c) ^ (d))
+#define F3(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d)))
+
+#define STEP(f, a, b, c, d, e, w, t) \
+ temp = ROTATE(5, (a)) + f((b), (c), (d)) + (e) + (w) + (t); \
+ (e) = (d); \
+ (d) = (c); \
+ (c) = ROTATE(30, (b)); \
+ (b) = (a); \
+ (a) = temp;
+
+
+/*
+ * GET() reads 4 input bytes in big-endian byte order and returns
+ * them as uint32_t.
+ */
+
+#define GET(n) \
+ ( ((uint32_t) p[n * 4 + 3]) \
+ | ((uint32_t) p[n * 4 + 2] << 8) \
+ | ((uint32_t) p[n * 4 + 1] << 16) \
+ | ((uint32_t) p[n * 4] << 24))
+
+
+/*
+ * This processes one or more 64-byte data blocks, but does not update
+ * the bit counters. There are no alignment requirements.
+ */
+
+static const u_char *
+nxt_sha1_body(nxt_sha1_t *ctx, const u_char *data, size_t size)
+{
+ uint32_t a, b, c, d, e, temp;
+ uint32_t saved_a, saved_b, saved_c, saved_d, saved_e;
+ uint32_t words[80];
+ nxt_uint_t i;
+ const u_char *p;
+
+ p = data;
+
+ a = ctx->a;
+ b = ctx->b;
+ c = ctx->c;
+ d = ctx->d;
+ e = ctx->e;
+
+ do {
+ saved_a = a;
+ saved_b = b;
+ saved_c = c;
+ saved_d = d;
+ saved_e = e;
+
+ /* Load data block into the words array */
+
+ for (i = 0; i < 16; i++) {
+ words[i] = GET(i);
+ }
+
+ for (i = 16; i < 80; i++) {
+ words[i] = ROTATE(1, words[i - 3]
+ ^ words[i - 8]
+ ^ words[i - 14]
+ ^ words[i - 16]);
+ }
+
+ /* Transformations */
+
+ STEP(F1, a, b, c, d, e, words[0], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[1], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[2], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[3], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[4], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[5], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[6], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[7], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[8], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[9], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[10], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[11], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[12], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[13], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[14], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[15], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[16], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[17], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[18], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[19], 0x5a827999);
+
+ STEP(F2, a, b, c, d, e, words[20], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[21], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[22], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[23], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[24], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[25], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[26], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[27], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[28], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[29], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[30], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[31], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[32], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[33], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[34], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[35], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[36], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[37], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[38], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[39], 0x6ed9eba1);
+
+ STEP(F3, a, b, c, d, e, words[40], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[41], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[42], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[43], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[44], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[45], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[46], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[47], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[48], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[49], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[50], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[51], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[52], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[53], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[54], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[55], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[56], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[57], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[58], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[59], 0x8f1bbcdc);
+
+ STEP(F2, a, b, c, d, e, words[60], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[61], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[62], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[63], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[64], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[65], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[66], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[67], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[68], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[69], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[70], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[71], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[72], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[73], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[74], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[75], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[76], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[77], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[78], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[79], 0xca62c1d6);
+
+ a += saved_a;
+ b += saved_b;
+ c += saved_c;
+ d += saved_d;
+ e += saved_e;
+
+ p += 64;
+
+ } while (size -= 64);
+
+ ctx->a = a;
+ ctx->b = b;
+ ctx->c = c;
+ ctx->d = d;
+ ctx->e = e;
+
+ return p;
+}
--- /dev/null
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) NGINX, Inc.
+ */
+
+
+#ifndef _NXT_SHA1_H_INCLUDED_
+#define _NXT_SHA1_H_INCLUDED_
+
+
+typedef struct {
+ uint64_t bytes;
+ uint32_t a, b, c, d, e;
+ u_char buffer[64];
+} nxt_sha1_t;
+
+
+NXT_EXPORT void nxt_sha1_init(nxt_sha1_t *ctx);
+NXT_EXPORT void nxt_sha1_update(nxt_sha1_t *ctx, const void *data, size_t size);
+NXT_EXPORT void nxt_sha1_final(u_char result[20], nxt_sha1_t *ctx);
+
+
+#endif /* _NXT_SHA1_H_INCLUDED_ */
--- /dev/null
+
+/*
+ * Copyright (C) Dmitry Volyntsev
+ * Copyright (C) NGINX, Inc.
+ *
+ * An internal SHA2 implementation.
+ */
+
+
+#include <nxt_auto_config.h>
+#include <nxt_types.h>
+#include <nxt_clang.h>
+#include <nxt_sha2.h>
+#include <string.h>
+
+
+static const u_char *nxt_sha2_body(nxt_sha2_t *ctx, const u_char *data,
+ size_t size);
+
+
+void
+nxt_sha2_init(nxt_sha2_t *ctx)
+{
+ ctx->a = 0x6a09e667;
+ ctx->b = 0xbb67ae85;
+ ctx->c = 0x3c6ef372;
+ ctx->d = 0xa54ff53a;
+ ctx->e = 0x510e527f;
+ ctx->f = 0x9b05688c;
+ ctx->g = 0x1f83d9ab;
+ ctx->h = 0x5be0cd19;
+
+ ctx->bytes = 0;
+}
+
+
+void
+nxt_sha2_update(nxt_sha2_t *ctx, const void *data, size_t size)
+{
+ size_t used, free;
+
+ used = (size_t) (ctx->bytes & 0x3f);
+ ctx->bytes += size;
+
+ if (used) {
+ free = 64 - used;
+
+ if (size < free) {
+ memcpy(&ctx->buffer[used], data, size);
+ return;
+ }
+
+ memcpy(&ctx->buffer[used], data, free);
+ data = (u_char *) data + free;
+ size -= free;
+ (void) nxt_sha2_body(ctx, ctx->buffer, 64);
+ }
+
+ if (size >= 64) {
+ data = nxt_sha2_body(ctx, data, size & ~(size_t) 0x3f);
+ size &= 0x3f;
+ }
+
+ memcpy(ctx->buffer, data, size);
+}
+
+
+void
+nxt_sha2_final(u_char result[32], nxt_sha2_t *ctx)
+{
+ size_t used, free;
+
+ used = (size_t) (ctx->bytes & 0x3f);
+
+ ctx->buffer[used++] = 0x80;
+
+ free = 64 - used;
+
+ if (free < 8) {
+ memset(&ctx->buffer[used], 0, free);
+ (void) nxt_sha2_body(ctx, ctx->buffer, 64);
+ used = 0;
+ free = 64;
+ }
+
+ memset(&ctx->buffer[used], 0, free - 8);
+
+ ctx->bytes <<= 3;
+ ctx->buffer[56] = (u_char) (ctx->bytes >> 56);
+ ctx->buffer[57] = (u_char) (ctx->bytes >> 48);
+ ctx->buffer[58] = (u_char) (ctx->bytes >> 40);
+ ctx->buffer[59] = (u_char) (ctx->bytes >> 32);
+ ctx->buffer[60] = (u_char) (ctx->bytes >> 24);
+ ctx->buffer[61] = (u_char) (ctx->bytes >> 16);
+ ctx->buffer[62] = (u_char) (ctx->bytes >> 8);
+ ctx->buffer[63] = (u_char) ctx->bytes;
+
+ (void) nxt_sha2_body(ctx, ctx->buffer, 64);
+
+ result[0] = (u_char) (ctx->a >> 24);
+ result[1] = (u_char) (ctx->a >> 16);
+ result[2] = (u_char) (ctx->a >> 8);
+ result[3] = (u_char) ctx->a;
+ result[4] = (u_char) (ctx->b >> 24);
+ result[5] = (u_char) (ctx->b >> 16);
+ result[6] = (u_char) (ctx->b >> 8);
+ result[7] = (u_char) ctx->b;
+ result[8] = (u_char) (ctx->c >> 24);
+ result[9] = (u_char) (ctx->c >> 16);
+ result[10] = (u_char) (ctx->c >> 8);
+ result[11] = (u_char) ctx->c;
+ result[12] = (u_char) (ctx->d >> 24);
+ result[13] = (u_char) (ctx->d >> 16);
+ result[14] = (u_char) (ctx->d >> 8);
+ result[15] = (u_char) ctx->d;
+ result[16] = (u_char) (ctx->e >> 24);
+ result[17] = (u_char) (ctx->e >> 16);
+ result[18] = (u_char) (ctx->e >> 8);
+ result[19] = (u_char) ctx->e;
+ result[20] = (u_char) (ctx->f >> 24);
+ result[21] = (u_char) (ctx->f >> 16);
+ result[22] = (u_char) (ctx->f >> 8);
+ result[23] = (u_char) ctx->f;
+ result[24] = (u_char) (ctx->g >> 24);
+ result[25] = (u_char) (ctx->g >> 16);
+ result[26] = (u_char) (ctx->g >> 8);
+ result[27] = (u_char) ctx->g;
+ result[28] = (u_char) (ctx->h >> 24);
+ result[29] = (u_char) (ctx->h >> 16);
+ result[30] = (u_char) (ctx->h >> 8);
+ result[31] = (u_char) ctx->h;
+
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+
+/*
+ * Helper functions.
+ */
+
+#define ROTATE(bits, word) (((word) >> (bits)) | ((word) << (32 - (bits))))
+
+#define S0(a) (ROTATE(2, a) ^ ROTATE(13, a) ^ ROTATE(22, a))
+#define S1(e) (ROTATE(6, e) ^ ROTATE(11, e) ^ ROTATE(25, e))
+#define CH(e, f, g) (((e) & (f)) ^ ((~(e)) & (g)))
+#define MAJ(a, b, c) (((a) & (b)) ^ ((a) & (c)) ^ ((b) & (c)))
+
+#define STEP(a, b, c, d, e, f, g, h, w, k) \
+ temp1 = (h) + S1(e) + CH(e, f, g) + (k) + (w); \
+ temp2 = S0(a) + MAJ(a, b, c); \
+ (h) = (g); \
+ (g) = (f); \
+ (f) = (e); \
+ (e) = (d) + temp1; \
+ (d) = (c); \
+ (c) = (b); \
+ (b) = (a); \
+ (a) = temp1 + temp2;
+
+
+/*
+ * GET() reads 4 input bytes in big-endian byte order and returns
+ * them as uint32_t.
+ */
+
+#define GET(n) \
+ ( ((uint32_t) p[n * 4 + 3]) \
+ | ((uint32_t) p[n * 4 + 2] << 8) \
+ | ((uint32_t) p[n * 4 + 1] << 16) \
+ | ((uint32_t) p[n * 4] << 24))
+
+
+/*
+ * This processes one or more 64-byte data blocks, but does not update
+ * the bit counters. There are no alignment requirements.
+ */
+
+static const u_char *
+nxt_sha2_body(nxt_sha2_t *ctx, const u_char *data, size_t size)
+{
+ uint32_t a, b, c, d, e, f, g, h, s0, s1, temp1, temp2;
+ uint32_t saved_a, saved_b, saved_c, saved_d, saved_e, saved_f,
+ saved_g, saved_h;
+ uint32_t words[64];
+ nxt_uint_t i;
+ const u_char *p;
+
+ p = data;
+
+ a = ctx->a;
+ b = ctx->b;
+ c = ctx->c;
+ d = ctx->d;
+ e = ctx->e;
+ f = ctx->f;
+ g = ctx->g;
+ h = ctx->h;
+
+ do {
+ saved_a = a;
+ saved_b = b;
+ saved_c = c;
+ saved_d = d;
+ saved_e = e;
+ saved_f = f;
+ saved_g = g;
+ saved_h = h;
+
+ /* Load data block into the words array */
+
+ for (i = 0; i < 16; i++) {
+ words[i] = GET(i);
+ }
+
+ for (i = 16; i < 64; i++) {
+ s0 = ROTATE(7, words[i - 15])
+ ^ ROTATE(18, words[i - 15])
+ ^ (words[i - 15] >> 3);
+
+ s1 = ROTATE(17, words[i - 2])
+ ^ ROTATE(19, words[i - 2])
+ ^ (words[i - 2] >> 10);
+
+ words[i] = words[i - 16] + s0 + words[i - 7] + s1;
+ }
+
+ /* Transformations */
+
+ STEP(a, b, c, d, e, f, g, h, words[0], 0x428a2f98);
+ STEP(a, b, c, d, e, f, g, h, words[1], 0x71374491);
+ STEP(a, b, c, d, e, f, g, h, words[2], 0xb5c0fbcf);
+ STEP(a, b, c, d, e, f, g, h, words[3], 0xe9b5dba5);
+ STEP(a, b, c, d, e, f, g, h, words[4], 0x3956c25b);
+ STEP(a, b, c, d, e, f, g, h, words[5], 0x59f111f1);
+ STEP(a, b, c, d, e, f, g, h, words[6], 0x923f82a4);
+ STEP(a, b, c, d, e, f, g, h, words[7], 0xab1c5ed5);
+ STEP(a, b, c, d, e, f, g, h, words[8], 0xd807aa98);
+ STEP(a, b, c, d, e, f, g, h, words[9], 0x12835b01);
+ STEP(a, b, c, d, e, f, g, h, words[10], 0x243185be);
+ STEP(a, b, c, d, e, f, g, h, words[11], 0x550c7dc3);
+ STEP(a, b, c, d, e, f, g, h, words[12], 0x72be5d74);
+ STEP(a, b, c, d, e, f, g, h, words[13], 0x80deb1fe);
+ STEP(a, b, c, d, e, f, g, h, words[14], 0x9bdc06a7);
+ STEP(a, b, c, d, e, f, g, h, words[15], 0xc19bf174);
+
+ STEP(a, b, c, d, e, f, g, h, words[16], 0xe49b69c1);
+ STEP(a, b, c, d, e, f, g, h, words[17], 0xefbe4786);
+ STEP(a, b, c, d, e, f, g, h, words[18], 0x0fc19dc6);
+ STEP(a, b, c, d, e, f, g, h, words[19], 0x240ca1cc);
+ STEP(a, b, c, d, e, f, g, h, words[20], 0x2de92c6f);
+ STEP(a, b, c, d, e, f, g, h, words[21], 0x4a7484aa);
+ STEP(a, b, c, d, e, f, g, h, words[22], 0x5cb0a9dc);
+ STEP(a, b, c, d, e, f, g, h, words[23], 0x76f988da);
+ STEP(a, b, c, d, e, f, g, h, words[24], 0x983e5152);
+ STEP(a, b, c, d, e, f, g, h, words[25], 0xa831c66d);
+ STEP(a, b, c, d, e, f, g, h, words[26], 0xb00327c8);
+ STEP(a, b, c, d, e, f, g, h, words[27], 0xbf597fc7);
+ STEP(a, b, c, d, e, f, g, h, words[28], 0xc6e00bf3);
+ STEP(a, b, c, d, e, f, g, h, words[29], 0xd5a79147);
+ STEP(a, b, c, d, e, f, g, h, words[30], 0x06ca6351);
+ STEP(a, b, c, d, e, f, g, h, words[31], 0x14292967);
+
+ STEP(a, b, c, d, e, f, g, h, words[32], 0x27b70a85);
+ STEP(a, b, c, d, e, f, g, h, words[33], 0x2e1b2138);
+ STEP(a, b, c, d, e, f, g, h, words[34], 0x4d2c6dfc);
+ STEP(a, b, c, d, e, f, g, h, words[35], 0x53380d13);
+ STEP(a, b, c, d, e, f, g, h, words[36], 0x650a7354);
+ STEP(a, b, c, d, e, f, g, h, words[37], 0x766a0abb);
+ STEP(a, b, c, d, e, f, g, h, words[38], 0x81c2c92e);
+ STEP(a, b, c, d, e, f, g, h, words[39], 0x92722c85);
+ STEP(a, b, c, d, e, f, g, h, words[40], 0xa2bfe8a1);
+ STEP(a, b, c, d, e, f, g, h, words[41], 0xa81a664b);
+ STEP(a, b, c, d, e, f, g, h, words[42], 0xc24b8b70);
+ STEP(a, b, c, d, e, f, g, h, words[43], 0xc76c51a3);
+ STEP(a, b, c, d, e, f, g, h, words[44], 0xd192e819);
+ STEP(a, b, c, d, e, f, g, h, words[45], 0xd6990624);
+ STEP(a, b, c, d, e, f, g, h, words[46], 0xf40e3585);
+ STEP(a, b, c, d, e, f, g, h, words[47], 0x106aa070);
+
+ STEP(a, b, c, d, e, f, g, h, words[48], 0x19a4c116);
+ STEP(a, b, c, d, e, f, g, h, words[49], 0x1e376c08);
+ STEP(a, b, c, d, e, f, g, h, words[50], 0x2748774c);
+ STEP(a, b, c, d, e, f, g, h, words[51], 0x34b0bcb5);
+ STEP(a, b, c, d, e, f, g, h, words[52], 0x391c0cb3);
+ STEP(a, b, c, d, e, f, g, h, words[53], 0x4ed8aa4a);
+ STEP(a, b, c, d, e, f, g, h, words[54], 0x5b9cca4f);
+ STEP(a, b, c, d, e, f, g, h, words[55], 0x682e6ff3);
+ STEP(a, b, c, d, e, f, g, h, words[56], 0x748f82ee);
+ STEP(a, b, c, d, e, f, g, h, words[57], 0x78a5636f);
+ STEP(a, b, c, d, e, f, g, h, words[58], 0x84c87814);
+ STEP(a, b, c, d, e, f, g, h, words[59], 0x8cc70208);
+ STEP(a, b, c, d, e, f, g, h, words[60], 0x90befffa);
+ STEP(a, b, c, d, e, f, g, h, words[61], 0xa4506ceb);
+ STEP(a, b, c, d, e, f, g, h, words[62], 0xbef9a3f7);
+ STEP(a, b, c, d, e, f, g, h, words[63], 0xc67178f2);
+
+ a += saved_a;
+ b += saved_b;
+ c += saved_c;
+ d += saved_d;
+ e += saved_e;
+ f += saved_f;
+ g += saved_g;
+ h += saved_h;
+
+ p += 64;
+
+ } while (size -= 64);
+
+ ctx->a = a;
+ ctx->b = b;
+ ctx->c = c;
+ ctx->d = d;
+ ctx->e = e;
+ ctx->f = f;
+ ctx->g = g;
+ ctx->h = h;
+
+ return p;
+}
--- /dev/null
+
+/*
+ * Copyright (C) Dmitry Volyntsev
+ * Copyright (C) NGINX, Inc.
+ */
+
+
+#ifndef _NXT_SHA2_H_INCLUDED_
+#define _NXT_SHA2_H_INCLUDED_
+
+
+typedef struct {
+ uint64_t bytes;
+ uint32_t a, b, c, d, e, f, g, h;
+ u_char buffer[64];
+} nxt_sha2_t;
+
+
+NXT_EXPORT void nxt_sha2_init(nxt_sha2_t *ctx);
+NXT_EXPORT void nxt_sha2_update(nxt_sha2_t *ctx, const void *data, size_t size);
+NXT_EXPORT void nxt_sha2_final(u_char result[32], nxt_sha2_t *ctx);
+
+
+#endif /* _NXT_SHA2_H_INCLUDED_ */