From: Dmitry Volyntsev Date: Tue, 24 Mar 2026 01:46:02 +0000 (-0700) Subject: Crypto: switched to OpenSSL EVP for hashing. X-Git-Tag: 0.9.7~8 X-Git-Url: http://www.kaiwu.me/postgresql/commit/static/gitweb.js?a=commitdiff_plain;h=3185ce819be0eadbaea1b602c6aa72108fdc32cd;p=njs.git Crypto: switched to OpenSSL EVP for hashing. Previously, the crypto module used built-in software implementations for a limited set of hash algorithms (md5, sha1, sha256). This prevented users from using algorithms like sha384, sha512, and sha3 family, even when the underlying OpenSSL library supported them. The change replaces built-in hash implementations with OpenSSL EVP_MD_CTX for createHash() and HMAC_CTX for createHmac(), following the webcrypto module. Algorithm lookup now uses EVP_get_digestbyname(), making any digest supported by the linked OpenSSL available to JavaScript code. The module now requires OpenSSL and is conditionally compiled, same as the webcrypto module. Builds without OpenSSL (--no-openssl) will no longer have the crypto module available. Tested with OpenSSL 3.0, OpenSSL 1.1.1w, LibreSSL 3.9.2, and BoringSSL. SHA-3 tests are skipped when the SSL library does not support them (e.g. BoringSSL). This closes #1037 feature request on Github. --- diff --git a/auto/modules b/auto/modules index 421ab2cf..d207cc35 100644 --- a/auto/modules +++ b/auto/modules @@ -7,16 +7,13 @@ njs_module_srcs=src/njs_buffer.c . auto/module -njs_module_name=njs_crypto_module -njs_module_incs= -njs_module_srcs="external/njs_crypto_module.c \ - external/njs_md5.c \ - external/njs_sha1.c \ - external/njs_sha2.c" +if [ $NJS_OPENSSL = YES -a $NJS_HAVE_OPENSSL = YES ]; then + njs_module_name=njs_crypto_module + njs_module_incs= + njs_module_srcs=external/njs_crypto_module.c -. auto/module + . auto/module -if [ $NJS_OPENSSL = YES -a $NJS_HAVE_OPENSSL = YES ]; then njs_module_name=njs_webcrypto_module njs_module_incs= njs_module_srcs=external/njs_webcrypto_module.c diff --git a/auto/qjs_modules b/auto/qjs_modules index 03501d7d..c7e3d708 100644 --- a/auto/qjs_modules +++ b/auto/qjs_modules @@ -7,11 +7,13 @@ njs_module_srcs=src/qjs_buffer.c . auto/qjs_module -njs_module_name=qjs_crypto_module -njs_module_incs= -njs_module_srcs=external/qjs_crypto_module.c +if [ $NJS_OPENSSL = YES -a $NJS_HAVE_OPENSSL = YES ]; then + njs_module_name=qjs_crypto_module + njs_module_incs= + njs_module_srcs=external/qjs_crypto_module.c -. auto/qjs_module + . auto/qjs_module +fi njs_module_name=qjs_fs_module njs_module_incs= diff --git a/external/njs_crypto_module.c b/external/njs_crypto_module.c index cdbb4b30..aff99b5a 100644 --- a/external/njs_crypto_module.c +++ b/external/njs_crypto_module.c @@ -8,49 +8,30 @@ #include #include #include -#include "njs_hash.h" +#include "njs_openssl.h" -typedef void (*njs_hash_init)(njs_hash_t *ctx); -typedef void (*njs_hash_update)(njs_hash_t *ctx, const void *data, size_t size); -typedef void (*njs_hash_final)(u_char result[32], njs_hash_t *ctx); - typedef njs_int_t (*njs_digest_encode)(njs_vm_t *vm, njs_value_t *value, const njs_str_t *src); typedef struct { - njs_str_t name; - - size_t size; - njs_hash_init init; - njs_hash_update update; - njs_hash_final final; -} njs_hash_alg_t; - -typedef struct { - njs_hash_t ctx; - njs_hash_alg_t *alg; + EVP_MD_CTX *ctx; } njs_digest_t; typedef struct { - u_char opad[64]; - njs_hash_t ctx; - njs_hash_alg_t *alg; + HMAC_CTX *ctx; } njs_hmac_t; typedef struct { njs_str_t name; - njs_digest_encode encode; } njs_crypto_enc_t; -static njs_hash_alg_t *njs_crypto_algorithm(njs_vm_t *vm, - njs_value_t *value); -static njs_crypto_enc_t *njs_crypto_encoding(njs_vm_t *vm, - njs_value_t *value); +static const EVP_MD *njs_crypto_algorithm(njs_vm_t *vm, njs_value_t *value); +static njs_crypto_enc_t *njs_crypto_encoding(njs_vm_t *vm, njs_value_t *value); static njs_int_t njs_buffer_digest(njs_vm_t *vm, njs_value_t *value, const njs_str_t *src); static njs_int_t njs_crypto_create_hash(njs_vm_t *vm, njs_value_t *args, @@ -64,44 +45,10 @@ static njs_int_t njs_hash_prototype_copy(njs_vm_t *vm, njs_value_t *args, static njs_int_t njs_crypto_create_hmac(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval); -static njs_int_t njs_crypto_init(njs_vm_t *vm); - - -static njs_hash_alg_t njs_hash_algorithms[] = { - - { - njs_str("md5"), - 16, - njs_md5_init, - njs_md5_update, - njs_md5_final - }, - - { - njs_str("sha1"), - 20, - njs_sha1_init, - njs_sha1_update, - njs_sha1_final - }, - - { - njs_str("sha256"), - 32, - njs_sha2_init, - njs_sha2_update, - njs_sha2_final - }, - - { - njs_null_str, - 0, - NULL, - NULL, - NULL - } +static void njs_crypto_cleanup_digest(void *data); +static void njs_crypto_cleanup_hmac(void *data); -}; +static njs_int_t njs_crypto_init(njs_vm_t *vm); static njs_crypto_enc_t njs_encodings[] = { @@ -283,11 +230,12 @@ static njs_int_t njs_crypto_create_hash(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { - njs_digest_t *dgst; - njs_hash_alg_t *alg; + njs_digest_t *dgst; + const EVP_MD *md; + njs_mp_cleanup_t *cln; - alg = njs_crypto_algorithm(vm, njs_arg(args, nargs, 1)); - if (njs_slow_path(alg == NULL)) { + md = njs_crypto_algorithm(vm, njs_arg(args, nargs, 1)); + if (njs_slow_path(md == NULL)) { return NJS_ERROR; } @@ -297,9 +245,26 @@ njs_crypto_create_hash(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_ERROR; } - dgst->alg = alg; + dgst->ctx = njs_evp_md_ctx_new(); + if (njs_slow_path(dgst->ctx == NULL)) { + njs_vm_memory_error(vm); + return NJS_ERROR; + } - alg->init(&dgst->ctx); + cln = njs_mp_cleanup_add(njs_vm_memory_pool(vm), 0); + if (njs_slow_path(cln == NULL)) { + njs_evp_md_ctx_free(dgst->ctx); + njs_vm_memory_error(vm); + return NJS_ERROR; + } + + cln->handler = njs_crypto_cleanup_digest; + cln->data = dgst; + + if (EVP_DigestInit_ex(dgst->ctx, md, NULL) <= 0) { + njs_vm_internal_error(vm, "EVP_DigestInit_ex() failed"); + return NJS_ERROR; + } return njs_vm_external_create(vm, retval, njs_crypto_hash_proto_id, dgst, 0); @@ -327,7 +292,7 @@ njs_hash_prototype_update(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_ERROR; } - if (njs_slow_path(dgst->alg == NULL)) { + if (njs_slow_path(dgst->ctx == NULL)) { njs_vm_error(vm, "Digest already called"); return NJS_ERROR; } @@ -341,7 +306,7 @@ njs_hash_prototype_update(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_ERROR; } - if (njs_slow_path(ctx->alg == NULL)) { + if (njs_slow_path(ctx->ctx == NULL)) { njs_vm_error(vm, "Digest already called"); return NJS_ERROR; } @@ -377,10 +342,16 @@ njs_hash_prototype_update(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } if (!hmac) { - dgst->alg->update(&dgst->ctx, data.start, data.length); + if (EVP_DigestUpdate(dgst->ctx, data.start, data.length) <= 0) { + njs_vm_internal_error(vm, "EVP_DigestUpdate() failed"); + return NJS_ERROR; + } } else { - ctx->alg->update(&ctx->ctx, data.start, data.length); + if (HMAC_Update(ctx->ctx, data.start, data.length) <= 0) { + njs_vm_internal_error(vm, "HMAC_Update() failed"); + return NJS_ERROR; + } } njs_value_assign(retval, this); @@ -397,9 +368,9 @@ njs_hash_prototype_digest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_hmac_t *ctx; njs_value_t *this; njs_digest_t *dgst; - njs_hash_alg_t *alg; + unsigned int len; njs_crypto_enc_t *enc; - u_char hash1[32], digest[32]; + u_char digest[EVP_MAX_MD_SIZE]; this = njs_argument(args, 0); @@ -410,7 +381,7 @@ njs_hash_prototype_digest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_ERROR; } - if (njs_slow_path(dgst->alg == NULL)) { + if (njs_slow_path(dgst->ctx == NULL)) { goto exception; } @@ -423,7 +394,7 @@ njs_hash_prototype_digest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_ERROR; } - if (njs_slow_path(ctx->alg == NULL)) { + if (njs_slow_path(ctx->ctx == NULL)) { goto exception; } @@ -436,23 +407,26 @@ njs_hash_prototype_digest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, } if (!hmac) { - alg = dgst->alg; - alg->final(digest, &dgst->ctx); - dgst->alg = NULL; + if (EVP_DigestFinal_ex(dgst->ctx, digest, &len) <= 0) { + njs_vm_internal_error(vm, "EVP_DigestFinal_ex() failed"); + return NJS_ERROR; + } + + njs_evp_md_ctx_free(dgst->ctx); + dgst->ctx = NULL; } else { - alg = ctx->alg; - alg->final(hash1, &ctx->ctx); + if (HMAC_Final(ctx->ctx, digest, &len) <= 0) { + njs_vm_internal_error(vm, "HMAC_Final() failed"); + return NJS_ERROR; + } - alg->init(&ctx->ctx); - alg->update(&ctx->ctx, ctx->opad, 64); - alg->update(&ctx->ctx, hash1, alg->size); - alg->final(digest, &ctx->ctx); - ctx->alg = NULL; + njs_hmac_ctx_free(ctx->ctx); + ctx->ctx = NULL; } str.start = digest; - str.length = alg->size; + str.length = len; return enc->encode(vm, retval, &str); @@ -468,7 +442,8 @@ static njs_int_t njs_hash_prototype_copy(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { - njs_digest_t *dgst, *copy; + njs_digest_t *dgst, *copy; + njs_mp_cleanup_t *cln; dgst = njs_vm_external(vm, njs_crypto_hash_proto_id, njs_argument(args, 0)); if (njs_slow_path(dgst == NULL)) { @@ -476,7 +451,7 @@ njs_hash_prototype_copy(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_ERROR; } - if (njs_slow_path(dgst->alg == NULL)) { + if (njs_slow_path(dgst->ctx == NULL)) { njs_vm_error(vm, "Digest already called"); return NJS_ERROR; } @@ -487,7 +462,26 @@ njs_hash_prototype_copy(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_ERROR; } - memcpy(copy, dgst, sizeof(njs_digest_t)); + copy->ctx = njs_evp_md_ctx_new(); + if (njs_slow_path(copy->ctx == NULL)) { + njs_vm_memory_error(vm); + return NJS_ERROR; + } + + cln = njs_mp_cleanup_add(njs_vm_memory_pool(vm), 0); + if (njs_slow_path(cln == NULL)) { + njs_evp_md_ctx_free(copy->ctx); + njs_vm_memory_error(vm); + return NJS_ERROR; + } + + cln->handler = njs_crypto_cleanup_digest; + cln->data = copy; + + if (EVP_MD_CTX_copy_ex(copy->ctx, dgst->ctx) <= 0) { + njs_vm_internal_error(vm, "EVP_MD_CTX_copy_ex() failed"); + return NJS_ERROR; + } return njs_vm_external_create(vm, retval, njs_crypto_hash_proto_id, copy, 0); @@ -500,16 +494,15 @@ njs_crypto_create_hmac(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, { njs_int_t ret; njs_str_t key; - njs_uint_t i; njs_hmac_t *ctx; njs_value_t *value; - njs_hash_alg_t *alg; + const EVP_MD *md; + njs_mp_cleanup_t *cln; njs_opaque_value_t result; const njs_buffer_encoding_t *enc; - u_char digest[32], key_buf[64]; - alg = njs_crypto_algorithm(vm, njs_arg(args, nargs, 1)); - if (njs_slow_path(alg == NULL)) { + md = njs_crypto_algorithm(vm, njs_arg(args, nargs, 1)); + if (njs_slow_path(md == NULL)) { return NJS_ERROR; } @@ -546,43 +539,37 @@ njs_crypto_create_hmac(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_ERROR; } - ctx->alg = alg; - - if (key.length > sizeof(key_buf)) { - alg->init(&ctx->ctx); - alg->update(&ctx->ctx, key.start, key.length); - alg->final(digest, &ctx->ctx); - - memcpy(key_buf, digest, alg->size); - njs_explicit_memzero(key_buf + alg->size, sizeof(key_buf) - alg->size); - - } else { - memcpy(key_buf, key.start, key.length); - njs_explicit_memzero(key_buf + key.length, - sizeof(key_buf) - key.length); + ctx->ctx = njs_hmac_ctx_new(); + if (njs_slow_path(ctx->ctx == NULL)) { + njs_vm_memory_error(vm); + return NJS_ERROR; } - for (i = 0; i < 64; i++) { - ctx->opad[i] = key_buf[i] ^ 0x5c; + cln = njs_mp_cleanup_add(njs_vm_memory_pool(vm), 0); + if (njs_slow_path(cln == NULL)) { + njs_hmac_ctx_free(ctx->ctx); + njs_vm_memory_error(vm); + return NJS_ERROR; } - for (i = 0; i < 64; i++) { - key_buf[i] ^= 0x36; - } + cln->handler = njs_crypto_cleanup_hmac; + cln->data = ctx; - alg->init(&ctx->ctx); - alg->update(&ctx->ctx, key_buf, 64); + if (HMAC_Init_ex(ctx->ctx, key.start, (int) key.length, md, NULL) <= 0) { + njs_vm_internal_error(vm, "HMAC_Init_ex() failed"); + return NJS_ERROR; + } return njs_vm_external_create(vm, retval, njs_crypto_hmac_proto_id, ctx, 0); } -static njs_hash_alg_t * +static const EVP_MD * njs_crypto_algorithm(njs_vm_t *vm, njs_value_t *value) { - njs_str_t name; - njs_hash_alg_t *e; + njs_str_t name; + const EVP_MD *md; if (njs_slow_path(!njs_value_is_string(value))) { njs_vm_type_error(vm, "algorithm must be a string"); @@ -591,15 +578,18 @@ njs_crypto_algorithm(njs_vm_t *vm, njs_value_t *value) njs_value_string_get(vm, value, &name); - for (e = &njs_hash_algorithms[0]; e->name.length != 0; e++) { - if (njs_strstr_eq(&name, &e->name)) { - return e; - } + if (njs_slow_path(njs_strlen(name.start) != name.length)) { + njs_vm_type_error(vm, "not supported algorithm: \"%V\"", &name); + return NULL; } - njs_vm_type_error(vm, "not supported algorithm: \"%V\"", &name); + md = EVP_get_digestbyname((const char *) name.start); + if (njs_slow_path(md == NULL)) { + njs_vm_type_error(vm, "not supported algorithm: \"%V\"", &name); + return NULL; + } - return NULL; + return md; } @@ -639,6 +629,30 @@ njs_buffer_digest(njs_vm_t *vm, njs_value_t *value, const njs_str_t *src) } +static void +njs_crypto_cleanup_digest(void *data) +{ + njs_digest_t *dgst = data; + + if (dgst->ctx != NULL) { + njs_evp_md_ctx_free(dgst->ctx); + dgst->ctx = NULL; + } +} + + +static void +njs_crypto_cleanup_hmac(void *data) +{ + njs_hmac_t *ctx = data; + + if (ctx->ctx != NULL) { + njs_hmac_ctx_free(ctx->ctx); + ctx->ctx = NULL; + } +} + + static njs_int_t njs_crypto_init(njs_vm_t *vm) { diff --git a/external/njs_hash.h b/external/njs_hash.h deleted file mode 100644 index acc5e457..00000000 --- a/external/njs_hash.h +++ /dev/null @@ -1,32 +0,0 @@ - -/* - * Copyright (C) Dmitry Volyntsev - * Copyright (C) NGINX, Inc. - */ - - -#ifndef _NJS_HASH_H_INCLUDED_ -#define _NJS_HASH_H_INCLUDED_ - - -typedef struct { - uint64_t bytes; - uint32_t a, b, c, d, e, f, g, h; - u_char buffer[64]; -} njs_hash_t; - - -NJS_EXPORT void njs_md5_init(njs_hash_t *ctx); -NJS_EXPORT void njs_md5_update(njs_hash_t *ctx, const void *data, size_t size); -NJS_EXPORT void njs_md5_final(u_char result[32], njs_hash_t *ctx); - -NJS_EXPORT void njs_sha1_init(njs_hash_t *ctx); -NJS_EXPORT void njs_sha1_update(njs_hash_t *ctx, const void *data, size_t size); -NJS_EXPORT void njs_sha1_final(u_char result[32], njs_hash_t *ctx); - -NJS_EXPORT void njs_sha2_init(njs_hash_t *ctx); -NJS_EXPORT void njs_sha2_update(njs_hash_t *ctx, const void *data, size_t size); -NJS_EXPORT void njs_sha2_final(u_char result[32], njs_hash_t *ctx); - - -#endif /* _NJS_HASH_H_INCLUDED_ */ diff --git a/external/njs_md5.c b/external/njs_md5.c deleted file mode 100644 index dfd9d53e..00000000 --- a/external/njs_md5.c +++ /dev/null @@ -1,270 +0,0 @@ - -/* - * An internal implementation, based on Alexander Peslyak's - * public domain implementation: - * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 - */ - - -#include -#include -#include -#include -#include "njs_hash.h" - - -static const u_char *njs_md5_body(njs_hash_t *ctx, const u_char *data, - size_t size); - - -void -njs_md5_init(njs_hash_t *ctx) -{ - ctx->a = 0x67452301; - ctx->b = 0xefcdab89; - ctx->c = 0x98badcfe; - ctx->d = 0x10325476; - - ctx->bytes = 0; -} - - -void -njs_md5_update(njs_hash_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) njs_md5_body(ctx, ctx->buffer, 64); - } - - if (size >= 64) { - data = njs_md5_body(ctx, data, size & ~(size_t) 0x3f); - size &= 0x3f; - } - - memcpy(ctx->buffer, data, size); -} - - -void -njs_md5_final(u_char result[32], njs_hash_t *ctx) -{ - size_t used, free; - - used = (size_t) (ctx->bytes & 0x3f); - - ctx->buffer[used++] = 0x80; - - free = 64 - used; - - if (free < 8) { - njs_memzero(&ctx->buffer[used], free); - (void) njs_md5_body(ctx, ctx->buffer, 64); - used = 0; - free = 64; - } - - njs_memzero(&ctx->buffer[used], 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) njs_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); - - njs_explicit_memzero(ctx, 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 * -njs_md5_body(njs_hash_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; -} diff --git a/external/njs_openssl.h b/external/njs_openssl.h index 98cd72f8..c68f330b 100644 --- a/external/njs_openssl.h +++ b/external/njs_openssl.h @@ -46,6 +46,37 @@ #endif +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) +#define njs_hmac_ctx_new() HMAC_CTX_new() +#define njs_hmac_ctx_free(_ctx) HMAC_CTX_free(_ctx) +#else + +njs_inline HMAC_CTX * +njs_hmac_ctx_new(void) +{ + HMAC_CTX *ctx; + + ctx = OPENSSL_malloc(sizeof(HMAC_CTX)); + if (ctx != NULL) { + HMAC_CTX_init(ctx); + } + + return ctx; +} + + +njs_inline void +njs_hmac_ctx_free(HMAC_CTX *ctx) +{ + if (ctx != NULL) { + HMAC_CTX_cleanup(ctx); + OPENSSL_free(ctx); + } +} + +#endif + + #define njs_bio_new_mem_buf(b, len) BIO_new_mem_buf((void *) b, len) diff --git a/external/njs_sha1.c b/external/njs_sha1.c deleted file mode 100644 index e5ca6ee9..00000000 --- a/external/njs_sha1.c +++ /dev/null @@ -1,298 +0,0 @@ - -/* - * Copyright (C) Maxim Dounin - * Copyright (C) NGINX, Inc. - * - * An internal SHA1 implementation. - */ - - -#include -#include -#include -#include -#include "njs_hash.h" - - -static const u_char *njs_sha1_body(njs_hash_t *ctx, const u_char *data, - size_t size); - - -void -njs_sha1_init(njs_hash_t *ctx) -{ - ctx->a = 0x67452301; - ctx->b = 0xefcdab89; - ctx->c = 0x98badcfe; - ctx->d = 0x10325476; - ctx->e = 0xc3d2e1f0; - - ctx->bytes = 0; -} - - -void -njs_sha1_update(njs_hash_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) njs_sha1_body(ctx, ctx->buffer, 64); - } - - if (size >= 64) { - data = njs_sha1_body(ctx, data, size & ~(size_t) 0x3f); - size &= 0x3f; - } - - memcpy(ctx->buffer, data, size); -} - - -void -njs_sha1_final(u_char result[32], njs_hash_t *ctx) -{ - size_t used, free; - - used = (size_t) (ctx->bytes & 0x3f); - - ctx->buffer[used++] = 0x80; - - free = 64 - used; - - if (free < 8) { - njs_memzero(&ctx->buffer[used], free); - (void) njs_sha1_body(ctx, ctx->buffer, 64); - used = 0; - free = 64; - } - - njs_memzero(&ctx->buffer[used], 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) njs_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; - - njs_explicit_memzero(ctx, 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 * -njs_sha1_body(njs_hash_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]; - njs_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; -} diff --git a/external/njs_sha2.c b/external/njs_sha2.c deleted file mode 100644 index 2e146347..00000000 --- a/external/njs_sha2.c +++ /dev/null @@ -1,320 +0,0 @@ - -/* - * Copyright (C) Dmitry Volyntsev - * Copyright (C) NGINX, Inc. - * - * An internal SHA2 implementation. - */ - - -#include -#include -#include -#include -#include "njs_hash.h" - - -static const u_char *njs_sha2_body(njs_hash_t *ctx, const u_char *data, - size_t size); - - -void -njs_sha2_init(njs_hash_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 -njs_sha2_update(njs_hash_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) njs_sha2_body(ctx, ctx->buffer, 64); - } - - if (size >= 64) { - data = njs_sha2_body(ctx, data, size & ~(size_t) 0x3f); - size &= 0x3f; - } - - memcpy(ctx->buffer, data, size); -} - - -void -njs_sha2_final(u_char result[32], njs_hash_t *ctx) -{ - size_t used, free; - - used = (size_t) (ctx->bytes & 0x3f); - - ctx->buffer[used++] = 0x80; - - free = 64 - used; - - if (free < 8) { - njs_memzero(&ctx->buffer[used], free); - (void) njs_sha2_body(ctx, ctx->buffer, 64); - used = 0; - free = 64; - } - - njs_memzero(&ctx->buffer[used], 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) njs_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; - - njs_explicit_memzero(ctx, 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 * -njs_sha2_body(njs_hash_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]; - njs_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; -} diff --git a/external/qjs_crypto_module.c b/external/qjs_crypto_module.c index 2b1bb26b..9d8510e7 100644 --- a/external/qjs_crypto_module.c +++ b/external/qjs_crypto_module.c @@ -5,33 +5,17 @@ */ #include -#include "njs_hash.h" - -typedef void (*qjs_hash_init)(njs_hash_t *ctx); -typedef void (*qjs_hash_update)(njs_hash_t *ctx, const void *data, size_t size); -typedef void (*qjs_hash_final)(u_char result[32], njs_hash_t *ctx); +#include "njs_openssl.h" typedef JSValue (*qjs_digest_encode)(JSContext *cx, const njs_str_t *src); typedef struct { - njs_str_t name; - - size_t size; - qjs_hash_init init; - qjs_hash_update update; - qjs_hash_final final; -} qjs_hash_alg_t; - -typedef struct { - njs_hash_t ctx; - qjs_hash_alg_t *alg; + EVP_MD_CTX *ctx; } qjs_digest_t; typedef struct { - u_char opad[64]; - njs_hash_t ctx; - qjs_hash_alg_t *alg; + HMAC_CTX *ctx; } qjs_hmac_t; @@ -42,7 +26,7 @@ typedef struct { } qjs_crypto_enc_t; -static qjs_hash_alg_t *qjs_crypto_algorithm(JSContext *cx, JSValueConst val); +static const EVP_MD *qjs_crypto_algorithm(JSContext *cx, JSValueConst val); static qjs_crypto_enc_t *qjs_crypto_encoding(JSContext *cx, JSValueConst val); static JSValue qjs_buffer_digest(JSContext *cx, const njs_str_t *src); static JSValue qjs_crypto_create_hash(JSContext *cx, JSValueConst this_val, @@ -61,43 +45,6 @@ static int qjs_crypto_module_init(JSContext *cx, JSModuleDef *m); static JSModuleDef * qjs_crypto_init(JSContext *cx, const char *module_name); -static qjs_hash_alg_t qjs_hash_algorithms[] = { - - { - njs_str("md5"), - 16, - njs_md5_init, - njs_md5_update, - njs_md5_final - }, - - { - njs_str("sha1"), - 20, - njs_sha1_init, - njs_sha1_update, - njs_sha1_final - }, - - { - njs_str("sha256"), - 32, - njs_sha2_init, - njs_sha2_update, - njs_sha2_final - }, - - { - njs_null_str, - 0, - NULL, - NULL, - NULL - } - -}; - - static qjs_crypto_enc_t qjs_encodings[] = { { @@ -173,12 +120,12 @@ static JSValue qjs_crypto_create_hash(JSContext *cx, JSValueConst this_val, int argc, JSValueConst *argv) { - JSValue obj; - qjs_digest_t *dgst; - qjs_hash_alg_t *alg; + JSValue obj; + qjs_digest_t *dgst; + const EVP_MD *md; - alg = qjs_crypto_algorithm(cx, argv[0]); - if (alg == NULL) { + md = qjs_crypto_algorithm(cx, argv[0]); + if (md == NULL) { return JS_EXCEPTION; } @@ -187,11 +134,22 @@ qjs_crypto_create_hash(JSContext *cx, JSValueConst this_val, int argc, return JS_ThrowOutOfMemory(cx); } - dgst->alg = alg; - alg->init(&dgst->ctx); + dgst->ctx = njs_evp_md_ctx_new(); + if (dgst->ctx == NULL) { + js_free(cx, dgst); + return JS_ThrowOutOfMemory(cx); + } + + if (EVP_DigestInit_ex(dgst->ctx, md, NULL) <= 0) { + njs_evp_md_ctx_free(dgst->ctx); + js_free(cx, dgst); + JS_ThrowInternalError(cx, "EVP_DigestInit_ex() failed"); + return JS_EXCEPTION; + } obj = JS_NewObjectClass(cx, QJS_CORE_CLASS_CRYPTO_HASH); if (JS_IsException(obj)) { + njs_evp_md_ctx_free(dgst->ctx); js_free(cx, dgst); return obj; } @@ -207,26 +165,22 @@ qjs_hash_prototype_update(JSContext *cx, JSValueConst this_val, int argc, JSValueConst *argv, int hmac) { njs_str_t str, content; - njs_hash_t *uctx; qjs_hmac_t *hctx; qjs_bytes_t bytes; qjs_digest_t *dgst; const qjs_buffer_encoding_t *enc; - void (*update)(njs_hash_t *ctx, const void *data, size_t size); - if (!hmac) { dgst = JS_GetOpaque2(cx, this_val, QJS_CORE_CLASS_CRYPTO_HASH); if (dgst == NULL) { return JS_ThrowTypeError(cx, "\"this\" is not a hash object"); } - if (dgst->alg == NULL) { + if (dgst->ctx == NULL) { return JS_ThrowTypeError(cx, "Digest already called"); } - update = dgst->alg->update; - uctx = &dgst->ctx; + hctx = NULL; } else { hctx = JS_GetOpaque2(cx, this_val, QJS_CORE_CLASS_CRYPTO_HMAC); @@ -234,12 +188,11 @@ qjs_hash_prototype_update(JSContext *cx, JSValueConst this_val, int argc, return JS_ThrowTypeError(cx, "\"this\" is not a hmac object"); } - if (hctx->alg == NULL) { + if (hctx->ctx == NULL) { return JS_ThrowTypeError(cx, "Digest already called"); } - update = hctx->alg->update; - uctx = &hctx->ctx; + dgst = NULL; } if (JS_IsString(argv[0])) { @@ -263,18 +216,49 @@ qjs_hash_prototype_update(JSContext *cx, JSValueConst this_val, int argc, if (enc->decode(cx, &str, &content) != 0) { JS_FreeCString(cx, (const char *) str.start); - JS_FreeCString(cx, (const char *) content.start); + js_free(cx, content.start); return JS_EXCEPTION; } JS_FreeCString(cx, (const char *) str.start); - update(uctx, content.start, content.length); + if (!hmac) { + if (EVP_DigestUpdate(dgst->ctx, content.start, content.length) + <= 0) + { + js_free(cx, content.start); + JS_ThrowInternalError(cx, "EVP_DigestUpdate() failed"); + return JS_EXCEPTION; + } + + } else { + if (HMAC_Update(hctx->ctx, content.start, content.length) <= 0) + { + js_free(cx, content.start); + JS_ThrowInternalError(cx, "HMAC_Update() failed"); + return JS_EXCEPTION; + } + } + js_free(cx, content.start); } else { - update(uctx, str.start, str.length); - JS_FreeCString(cx, (const char *) str.start); + if (!hmac) { + if (EVP_DigestUpdate(dgst->ctx, str.start, str.length) <= 0) { + JS_FreeCString(cx, (const char *) str.start); + JS_ThrowInternalError(cx, "EVP_DigestUpdate() failed"); + return JS_EXCEPTION; + } + + } else { + if (HMAC_Update(hctx->ctx, str.start, str.length) <= 0) { + JS_FreeCString(cx, (const char *) str.start); + JS_ThrowInternalError(cx, "HMAC_Update() failed"); + return JS_EXCEPTION; + } + } + + JS_FreeCString(cx, (const char *) str.start); } } else if (qjs_is_typed_array(cx, argv[0])) { @@ -282,7 +266,18 @@ qjs_hash_prototype_update(JSContext *cx, JSValueConst this_val, int argc, return JS_EXCEPTION; } - update(uctx, bytes.start, bytes.length); + if (!hmac) { + if (EVP_DigestUpdate(dgst->ctx, bytes.start, bytes.length) <= 0) { + JS_ThrowInternalError(cx, "EVP_DigestUpdate() failed"); + return JS_EXCEPTION; + } + + } else { + if (HMAC_Update(hctx->ctx, bytes.start, bytes.length) <= 0) { + JS_ThrowInternalError(cx, "HMAC_Update() failed"); + return JS_EXCEPTION; + } + } } else { return JS_ThrowTypeError(cx, @@ -298,11 +293,11 @@ qjs_hash_prototype_digest(JSContext *cx, JSValueConst this_val, int argc, JSValueConst *argv, int hmac) { njs_str_t str; + unsigned int len; qjs_hmac_t *hctx; qjs_digest_t *dgst; - qjs_hash_alg_t *alg; qjs_crypto_enc_t *enc; - u_char hash1[32],digest[32]; + u_char digest[EVP_MAX_MD_SIZE]; if (!hmac) { dgst = JS_GetOpaque2(cx, this_val, QJS_CORE_CLASS_CRYPTO_HASH); @@ -310,14 +305,17 @@ qjs_hash_prototype_digest(JSContext *cx, JSValueConst this_val, int argc, return JS_ThrowTypeError(cx, "\"this\" is not a hash object"); } - alg = dgst->alg; - if (alg == NULL) { + if (dgst->ctx == NULL) { return JS_ThrowTypeError(cx, "Digest already called"); } - dgst->alg = NULL; + if (EVP_DigestFinal_ex(dgst->ctx, digest, &len) <= 0) { + JS_ThrowInternalError(cx, "EVP_DigestFinal_ex() failed"); + return JS_EXCEPTION; + } - alg->final(digest, &dgst->ctx); + njs_evp_md_ctx_free(dgst->ctx); + dgst->ctx = NULL; } else { hctx = JS_GetOpaque2(cx, this_val, QJS_CORE_CLASS_CRYPTO_HMAC); @@ -325,23 +323,21 @@ qjs_hash_prototype_digest(JSContext *cx, JSValueConst this_val, int argc, return JS_ThrowTypeError(cx, "\"this\" is not a hmac object"); } - alg = hctx->alg; - if (alg == NULL) { + if (hctx->ctx == NULL) { return JS_ThrowTypeError(cx, "Digest already called"); } - hctx->alg = NULL; - - alg->final(hash1, &hctx->ctx); + if (HMAC_Final(hctx->ctx, digest, &len) <= 0) { + JS_ThrowInternalError(cx, "HMAC_Final() failed"); + return JS_EXCEPTION; + } - alg->init(&hctx->ctx); - alg->update(&hctx->ctx, hctx->opad, 64); - alg->update(&hctx->ctx, hash1, alg->size); - alg->final(digest, &hctx->ctx); + njs_hmac_ctx_free(hctx->ctx); + hctx->ctx = NULL; } str.start = digest; - str.length = alg->size; + str.length = len; if (argc == 0) { return qjs_buffer_digest(cx, &str); @@ -368,7 +364,7 @@ qjs_hash_prototype_copy(JSContext *cx, JSValueConst this_val, int argc, return JS_EXCEPTION; } - if (dgst->alg == NULL) { + if (dgst->ctx == NULL) { return JS_ThrowTypeError(cx, "Digest already called"); } @@ -377,10 +373,22 @@ qjs_hash_prototype_copy(JSContext *cx, JSValueConst this_val, int argc, return JS_ThrowOutOfMemory(cx); } - memcpy(copy, dgst, sizeof(qjs_digest_t)); + copy->ctx = njs_evp_md_ctx_new(); + if (copy->ctx == NULL) { + js_free(cx, copy); + return JS_ThrowOutOfMemory(cx); + } + + if (EVP_MD_CTX_copy_ex(copy->ctx, dgst->ctx) <= 0) { + njs_evp_md_ctx_free(copy->ctx); + js_free(cx, copy); + JS_ThrowInternalError(cx, "EVP_MD_CTX_copy_ex() failed"); + return JS_EXCEPTION; + } obj = JS_NewObjectClass(cx, QJS_CORE_CLASS_CRYPTO_HASH); if (JS_IsException(obj)) { + njs_evp_md_ctx_free(copy->ctx); js_free(cx, copy); return obj; } @@ -395,17 +403,15 @@ static JSValue qjs_crypto_create_hmac(JSContext *cx, JSValueConst this_val, int argc, JSValueConst *argv) { - int i; - JS_BOOL key_is_string; - JSValue obj; - njs_str_t key; - qjs_hmac_t *hmac; - qjs_bytes_t bytes; - qjs_hash_alg_t *alg; - u_char digest[32], key_buf[64]; - - alg = qjs_crypto_algorithm(cx, argv[0]); - if (alg == NULL) { + JS_BOOL key_is_string; + JSValue obj; + njs_str_t key; + qjs_hmac_t *hmac; + qjs_bytes_t bytes; + const EVP_MD *md; + + md = qjs_crypto_algorithm(cx, argv[0]); + if (md == NULL) { return JS_EXCEPTION; } @@ -438,38 +444,34 @@ qjs_crypto_create_hmac(JSContext *cx, JSValueConst this_val, int argc, return JS_ThrowOutOfMemory(cx); } - hmac->alg = alg; + hmac->ctx = njs_hmac_ctx_new(); + if (hmac->ctx == NULL) { + js_free(cx, hmac); + if (key_is_string) { + JS_FreeCString(cx, (const char *) key.start); + } - if (key.length > sizeof(key_buf)) { - alg->init(&hmac->ctx); - alg->update(&hmac->ctx, key.start, key.length); - alg->final(digest, &hmac->ctx); + return JS_ThrowOutOfMemory(cx); + } - memcpy(key_buf, digest, alg->size); - memset(key_buf + alg->size, 0, sizeof(key_buf) - alg->size); + if (HMAC_Init_ex(hmac->ctx, key.start, (int) key.length, md, NULL) <= 0) { + njs_hmac_ctx_free(hmac->ctx); + js_free(cx, hmac); + if (key_is_string) { + JS_FreeCString(cx, (const char *) key.start); + } - } else { - memcpy(key_buf, key.start, key.length); - memset(key_buf + key.length, 0, sizeof(key_buf) - key.length); + JS_ThrowInternalError(cx, "HMAC_Init_ex() failed"); + return JS_EXCEPTION; } if (key_is_string) { JS_FreeCString(cx, (const char *) key.start); } - for (i = 0; i < 64; i++) { - hmac->opad[i] = key_buf[i] ^ 0x5c; - } - - for (i = 0; i < 64; i++) { - key_buf[i] ^= 0x36; - } - - alg->init(&hmac->ctx); - alg->update(&hmac->ctx, key_buf, 64); - obj = JS_NewObjectClass(cx, QJS_CORE_CLASS_CRYPTO_HMAC); if (JS_IsException(obj)) { + njs_hmac_ctx_free(hmac->ctx); js_free(cx, hmac); return obj; } @@ -487,6 +489,10 @@ qjs_hash_finalizer(JSRuntime *rt, JSValue val) dgst = JS_GetOpaque(val, QJS_CORE_CLASS_CRYPTO_HASH); if (dgst != NULL) { + if (dgst->ctx != NULL) { + njs_evp_md_ctx_free(dgst->ctx); + } + js_free_rt(rt, dgst); } } @@ -499,39 +505,44 @@ qjs_hmac_finalizer(JSRuntime *rt, JSValue val) hmac = JS_GetOpaque(val, QJS_CORE_CLASS_CRYPTO_HMAC); if (hmac != NULL) { + if (hmac->ctx != NULL) { + njs_hmac_ctx_free(hmac->ctx); + } + js_free_rt(rt, hmac); } } -static qjs_hash_alg_t * +static const EVP_MD * qjs_crypto_algorithm(JSContext *cx, JSValueConst val) { - njs_str_t name; - qjs_hash_alg_t *a, *alg; + size_t len; + const char *name; + const EVP_MD *md; - name.start = (u_char *) JS_ToCStringLen(cx, &name.length, val); - if (name.start == NULL) { + name = JS_ToCStringLen(cx, &len, val); + if (name == NULL) { JS_ThrowTypeError(cx, "algorithm must be a string"); return NULL; } - alg = NULL; - - for (a = &qjs_hash_algorithms[0]; a->name.start != NULL; a++) { - if (njs_strstr_eq(&name, &a->name)) { - alg = a; - break; - } + if (njs_strlen(name) != len) { + JS_FreeCString(cx, name); + JS_ThrowTypeError(cx, "not supported algorithm"); + return NULL; } - JS_FreeCString(cx, (const char *) name.start); + md = EVP_get_digestbyname(name); - if (alg == NULL) { + JS_FreeCString(cx, name); + + if (md == NULL) { JS_ThrowTypeError(cx, "not supported algorithm"); + return NULL; } - return alg; + return md; } diff --git a/nginx/config b/nginx/config index f54234a8..0d91ae12 100644 --- a/nginx/config +++ b/nginx/config @@ -113,13 +113,15 @@ fi if [ $NJS_OPENSSL != NO ]; then NJS_OPENSSL_LIB=OPENSSL have=NJS_HAVE_OPENSSL . auto/have + NJS_SRCS="$NJS_SRCS $ngx_addon_dir/../external/njs_crypto_module.c" NJS_SRCS="$NJS_SRCS $ngx_addon_dir/../external/njs_webcrypto_module.c" if [ "$NJS_HAVE_QUICKJS" = "YES" ]; then + NJS_SRCS="$NJS_SRCS $ngx_addon_dir/../external/qjs_crypto_module.c" NJS_SRCS="$NJS_SRCS $ngx_addon_dir/../external/qjs_webcrypto_module.c" fi - echo " enabled webcrypto module" + echo " enabled crypto and webcrypto modules" fi if [ $NJS_LIBXSLT != NO ]; then diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index c9f77cdd..30b7ba1b 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -21740,20 +21740,23 @@ static njs_unit_test_t njs_shared_test[] = " at require (native)\n" " at main (:1)\n") }, + { njs_str("import cr from 'unknown'"), + njs_str("Error: Cannot load module \"unknown\"") }, + +#if (NJS_HAVE_OPENSSL) + { njs_str("var cr = require('crypto'); cr.createHash"), njs_str("[object Function]") }, { njs_str("var cr = require('crypto'); cr.createHash('md5')"), njs_str("[object Hash]") }, - { njs_str("import cr from 'unknown'"), - njs_str("Error: Cannot load module \"unknown\"") }, - { njs_str("import cr from 'crypto'; cr.createHash"), njs_str("[object Function]") }, { njs_str("import cr from 'crypto'; cr.createHash('md5')"), njs_str("[object Hash]") }, +#endif { njs_str("var fs = require('fs'); fs.a = 1; fs.a"), njs_str("1") }, @@ -22291,6 +22294,7 @@ static njs_unit_test_t njs_backtraces_test[] = " at require (native)\n" " at main (:1)\n") }, +#if (NJS_HAVE_OPENSSL) { njs_str("require('crypto').createHash('sha')"), njs_str("TypeError: not supported algorithm: \"sha\"\n" " at createHash (native)\n" @@ -22312,6 +22316,7 @@ static njs_unit_test_t njs_backtraces_test[] = njs_str("TypeError: data is not a string or Buffer-like object\n" " at update (native)\n" " at main (:1)\n") }, +#endif { njs_str("function f(o) {function f_in(o) {return o.a.a};" " return f_in(o)};" diff --git a/test/crypto.t.mjs b/test/crypto.t.mjs index ad237d88..e0cc6f12 100644 --- a/test/crypto.t.mjs +++ b/test/crypto.t.mjs @@ -5,6 +5,15 @@ flags: [async] import cr from 'crypto'; +function has_algorithm(alg) { + try { + cr.createHash(alg).digest(); + return true; + } catch (e) { + return false; + } +} + let createHash_tsuite = { name: "createHash tests", skip: () => !cr.createHash, @@ -166,6 +175,37 @@ let createHash_tsuite = { { hash: 'sha256', data: [Buffer.from('XABX').subarray(1,3)], digest: 'base64url', expected: "OBZPvRdgPXP2lri01yZk1zW7anyIV3aH_SrjP9aWQVM" }, + { hash: 'sha384', data: [], digest: 'hex', + expected: "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b" }, + { hash: 'sha384', data: ['AB'], digest: 'hex', + expected: "4f9179c7b48de00c642b3782c3f9435bf21bde99cbf9ca13b6c3f1e58fff9064ad47464da97e6277c7f438d8f5a91d6b" }, + { hash: 'sha384', data: ['A', 'B'], digest: 'hex', + expected: "4f9179c7b48de00c642b3782c3f9435bf21bde99cbf9ca13b6c3f1e58fff9064ad47464da97e6277c7f438d8f5a91d6b" }, + + { hash: 'sha512', data: [], digest: 'hex', + expected: "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" }, + { hash: 'sha512', data: ['AB'], digest: 'hex', + expected: "71edc062331872ff3c13c77d98f4af0e8e27bb360d03690558beab6711f9733e5dc7f114b7af58cfbcd6360575873c09a667a9af749dc912e4ca276a7dfee5d3" }, + { hash: 'sha512', data: ['A', 'B'], digest: 'hex', + expected: "71edc062331872ff3c13c77d98f4af0e8e27bb360d03690558beab6711f9733e5dc7f114b7af58cfbcd6360575873c09a667a9af749dc912e4ca276a7dfee5d3" }, + + { hash: 'sha3-256', skip: () => !has_algorithm('sha3-256'), + data: [], digest: 'hex', + expected: "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a" }, + { hash: 'sha3-256', skip: () => !has_algorithm('sha3-256'), + data: ['AB'], digest: 'hex', + expected: "21f29d555c7c5f9e5859a7984c0b2f8ccad9d5245fbe6c4703fd75c0922d7735" }, + { hash: 'sha3-256', skip: () => !has_algorithm('sha3-256'), + data: ['A', 'B'], digest: 'hex', + expected: "21f29d555c7c5f9e5859a7984c0b2f8ccad9d5245fbe6c4703fd75c0922d7735" }, + + { hash: 'sha3-512', skip: () => !has_algorithm('sha3-512'), + data: [], digest: 'hex', + expected: "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26" }, + { hash: 'sha3-512', skip: () => !has_algorithm('sha3-512'), + data: ['AB'], digest: 'hex', + expected: "fcc802621fee9efe4d8ee032d886f75431edb29d480e945d8f0efb1c0ad419bf9b652fca1fa1f5af0f5b4a74f76a6e86b00dbfbec7dcf00e3f4ef34840e9b720" }, + { hash: 'sha1', hash_value(hash) { var Hash = cr.createHash(hash).constructor; @@ -390,6 +430,23 @@ let createHmac_tsuite = { { hash: 'sha256', key: 'A'.repeat(100), data: ['AB'], digest: 'hex', expected: "5647b6c429701ff512f0f18232b4507065d2376ca8899a816a0a6e721bf8ddcc" }, + { hash: 'sha384', key: '', data: [], digest: 'hex', + expected: "6c1f2ee938fad2e24bd91298474382ca218c75db3d83e114b3d4367776d14d3551289e75e8209cd4b792302840234adc" }, + { hash: 'sha384', key: '', data: ['AB'], digest: 'hex', + expected: "0145ec85556f28b82b49d7bd8c3373312d95c308b758e3bd3cd972f8ab9d0ea9245f60ef5b994ec936eb42c6fc7ca033" }, + { hash: 'sha384', key: Buffer.from('secret'), data: ['AB'], digest: 'hex', + expected: "afb6653433bc3b3e570fa9c7f0fa1f40d070af21085d7292ce8c93c4a280c2c91b1da980c39a3738361458c75a8c6f64" }, + + { hash: 'sha512', key: '', data: [], digest: 'hex', + expected: "b936cee86c9f87aa5d3c6f2e84cb5a4239a5fe50480a6ec66b70ab5b1f4ac6730c6c515421b327ec1d69402e53dfb49ad7381eb067b338fd7b0cb22247225d47" }, + { hash: 'sha512', key: '', data: ['AB'], digest: 'hex', + expected: "8bf9155a8dbd563d879ecb5ad27e7b9e8e30ab98c138802594bedd9d839ddecb85443fdc64e18274311975b4ec1c5dd5dc41a6e7530cf34ea3d6545cf5844501" }, + { hash: 'sha512', key: Buffer.from('secret'), data: ['AB'], digest: 'hex', + expected: "1169372f39b4ea921bed3cff6d029c0be7116bf2966098b9923d0730e9bd569e2f52e65f63c3adebe988b0be174fd42578b1536f1f1b8b46a1382da55e27de9d" }, + + { hash: 'sha512', key: 'A'.repeat(200), data: ['AB'], digest: 'hex', + expected: "d64ea04999cba0f2f167f471569129f9b3105a2e099fb883be3cdee452b38cf7c34d1705b83caaaf784dd4e63703a328d9a5167b03dd059d516b386ff86d5a40" }, + { hash: 'sha1', hmac_value(hash, key) { var Hmac = cr.createHmac(hash, key).constructor;