diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 13:19:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 13:20:02 +0000 |
commit | 58daab21cd043e1dc37024a7f99b396788372918 (patch) | |
tree | 96771e43bb69f7c1c2b0b4f7374cb74d7866d0cb /web/server/h2o/libh2o/deps/mruby-digest | |
parent | Releasing debian version 1.43.2-1. (diff) | |
download | netdata-58daab21cd043e1dc37024a7f99b396788372918.tar.xz netdata-58daab21cd043e1dc37024a7f99b396788372918.zip |
Merging upstream version 1.44.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'web/server/h2o/libh2o/deps/mruby-digest')
-rw-r--r-- | web/server/h2o/libh2o/deps/mruby-digest/.gitignore | 5 | ||||
-rw-r--r-- | web/server/h2o/libh2o/deps/mruby-digest/.travis.yml | 2 | ||||
-rw-r--r-- | web/server/h2o/libh2o/deps/mruby-digest/Makefile | 14 | ||||
-rw-r--r-- | web/server/h2o/libh2o/deps/mruby-digest/README.md | 55 | ||||
-rw-r--r-- | web/server/h2o/libh2o/deps/mruby-digest/mrbgem.rake | 4 | ||||
-rw-r--r-- | web/server/h2o/libh2o/deps/mruby-digest/mrblib/digest.rb | 46 | ||||
-rw-r--r-- | web/server/h2o/libh2o/deps/mruby-digest/run_test.rb | 28 | ||||
-rw-r--r-- | web/server/h2o/libh2o/deps/mruby-digest/src/digest.c | 1007 | ||||
-rw-r--r-- | web/server/h2o/libh2o/deps/mruby-digest/src/picohash.h | 751 | ||||
-rw-r--r-- | web/server/h2o/libh2o/deps/mruby-digest/test/digest.rb | 203 |
10 files changed, 2115 insertions, 0 deletions
diff --git a/web/server/h2o/libh2o/deps/mruby-digest/.gitignore b/web/server/h2o/libh2o/deps/mruby-digest/.gitignore new file mode 100644 index 000000000..55ef3162f --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/.gitignore @@ -0,0 +1,5 @@ +gem_* +gem-* +mrb-*.a +src/*.o +/tmp diff --git a/web/server/h2o/libh2o/deps/mruby-digest/.travis.yml b/web/server/h2o/libh2o/deps/mruby-digest/.travis.yml new file mode 100644 index 000000000..ffe227284 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/.travis.yml @@ -0,0 +1,2 @@ +script: + - "ruby run_test.rb all test" diff --git a/web/server/h2o/libh2o/deps/mruby-digest/Makefile b/web/server/h2o/libh2o/deps/mruby-digest/Makefile new file mode 100644 index 000000000..21f8afe00 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/Makefile @@ -0,0 +1,14 @@ +GEM := mruby-digest + +include $(MAKEFILE_4_GEM) + +GEM_C_FILES := $(wildcard $(SRC_DIR)/*.c) +GEM_OBJECTS := $(patsubst %.c, %.o, $(GEM_C_FILES)) + +GEM_RB_FILES := $(wildcard $(MRB_DIR)/*.rb) + +gem-all : $(GEM_OBJECTS) gem-c-and-rb-files + +gem-clean : gem-clean-c-and-rb-files + +gem-test : gem-test-c-and-rb-files diff --git a/web/server/h2o/libh2o/deps/mruby-digest/README.md b/web/server/h2o/libh2o/deps/mruby-digest/README.md new file mode 100644 index 000000000..2ae6552c8 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/README.md @@ -0,0 +1,55 @@ +mruby-digest +========= + +This library is a fork of [github.com/iij/mruby-digest](https://github.com/iij/mruby-digest). +Unlike the original, this fork does not have any dependencies; it uses [picohash](https://github.com/kazuho/picohash) - a public domain library for hash calculation. + +## Features + +Message Digest and HMAC classes are available. They are compatible with CRuby's ones. + +- Digest::MD5, Digest::RMD160, Digest::SHA1, Digest::SHA256, Digest::SHA384 and + Digest::SHA512 + - Note: some of them are not available if libcrypto.a does not support them on your system. +- Digest::HMAC + +## Install + - add conf.gem line to `build_config.rb` + +```ruby +MRuby::Build.new do |conf| + + # ... (snip) ... + + conf.gem :git => 'https://github.com/iij/mruby-digest.git' +end +``` + +## Usage +```ruby +Digest::MD5.digest('ruby') +Digest::MD5.hexdigest('ruby') +``` + +## License + +Copyright (c) 2012-2015 Internet Initiative Japan Inc., Kazuho Oku + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/web/server/h2o/libh2o/deps/mruby-digest/mrbgem.rake b/web/server/h2o/libh2o/deps/mruby-digest/mrbgem.rake new file mode 100644 index 000000000..9324f169b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/mrbgem.rake @@ -0,0 +1,4 @@ +MRuby::Gem::Specification.new('mruby-digest') do |spec| + spec.license = 'MIT' + spec.authors = 'Internet Initiative Japan Inc.' +end diff --git a/web/server/h2o/libh2o/deps/mruby-digest/mrblib/digest.rb b/web/server/h2o/libh2o/deps/mruby-digest/mrblib/digest.rb new file mode 100644 index 000000000..7779f54b9 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/mrblib/digest.rb @@ -0,0 +1,46 @@ +if Object.const_defined? :Digest +module Digest + class Base + def self.digest(data) + self.new.update(data).digest + end + def self.file(path) + self.new.update(File.open(path).read) + end + def self.hexdigest(data) + self.new.update(data).hexdigest + end + def ==(other) + if other.kind_of? String + self.hexdigest == other + else + self.digest == other.digest + end + end + def file(path) + self.update(File.open(path).read) + end + def hexdigest! + x = self.hexdigest + self.reset + x + end + + alias length digest_length + alias size digest_length + alias to_s hexdigest + alias << update + end + + class HMAC + def self.digest(data, key, digest) + self.new(key, digest).update(data).digest + end + def self.hexdigest(data, key, digest) + self.new(key, digest).update(data).hexdigest + end + + alias << update + end +end +end diff --git a/web/server/h2o/libh2o/deps/mruby-digest/run_test.rb b/web/server/h2o/libh2o/deps/mruby-digest/run_test.rb new file mode 100644 index 000000000..3401ed86c --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/run_test.rb @@ -0,0 +1,28 @@ +#!/usr/bin/env ruby +# +# mrbgems test runner +# + +gemname = File.basename(File.dirname(File.expand_path __FILE__)) + +if __FILE__ == $0 + repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby' + build_args = ARGV + build_args = ['all', 'test'] if build_args.nil? or build_args.empty? + + Dir.mkdir 'tmp' unless File.exist?('tmp') + unless File.exist?(dir) + system "git clone #{repository} #{dir}" + end + + exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}]) +end + +MRuby::Build.new do |conf| + toolchain :gcc + enable_debug + enable_test + conf.gembox 'default' + + conf.gem File.expand_path(File.dirname(__FILE__)) +end diff --git a/web/server/h2o/libh2o/deps/mruby-digest/src/digest.c b/web/server/h2o/libh2o/deps/mruby-digest/src/digest.c new file mode 100644 index 000000000..634376d96 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/src/digest.c @@ -0,0 +1,1007 @@ +/* +** digest.c - Digest and subclasses +** +** See Copyright Notice in mruby.h +*/ + +#include "mruby.h" + +#define USE_DIGEST_PICOHASH + +#if !defined(USE_DIGEST_PICOHASH) +#elif defined(__APPLE__) +#define USE_DIGEST_OSX_COMMONCRYPTO +#else +#define USE_DIGEST_OPENSSL +#endif + +#if defined(USE_DIGEST_PICOHASH) +#include "picohash.h" +#elif defined(USE_DIGEST_OPENSSL) +#include <openssl/evp.h> +#include <openssl/hmac.h> +#include <openssl/sha.h> +#elif defined(USE_DIGEST_OSX_COMMONCRYPTO) +#include <CommonCrypto/CommonDigest.h> +#include <CommonCrypto/CommonHMAC.h> +#else +#error "define USE_DIGEST_PICOHASH or USE_DIGEST_OPENSSL or USE_DIGEST_OSX_COMMONCRYPTO" +#endif +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include "mruby/array.h" +#include "mruby/class.h" +#include "mruby/data.h" +#include "mruby/string.h" +#include "mruby/variable.h" + +#define TYPESYM "__type__" + + +/* + * library-independent layer API + */ +enum { + MD_TYPE_MD5, + MD_TYPE_RMD160, + MD_TYPE_SHA1, + MD_TYPE_SHA256, + MD_TYPE_SHA384, + MD_TYPE_SHA512, +}; + +struct mrb_md; +struct mrb_hmac; + +static void lib_init(void); +static int lib_md_block_length(const struct mrb_md *); +static mrb_value lib_md_digest(mrb_state *, const struct mrb_md *); +static mrb_value lib_md_digest_bang(mrb_state *, struct mrb_md *); +static int lib_md_digest_length(const struct mrb_md *); +static void lib_md_free(mrb_state *, void *); +static void lib_md_init(mrb_state *, struct mrb_md *, int); +static void lib_md_init_copy(mrb_state *, struct mrb_md *, struct mrb_md *); +static void lib_md_reset(mrb_state *, struct mrb_md *); +static void lib_md_update(mrb_state *, struct mrb_md *, unsigned char *, mrb_int); + +static mrb_value lib_hmac_digest(mrb_state *, const struct mrb_hmac *); +static int lib_hmac_block_length(const struct mrb_hmac *); +static int lib_hmac_digest_length(const struct mrb_hmac *); +static void lib_hmac_free(mrb_state *, void *); +static void lib_hmac_init(mrb_state *, struct mrb_hmac *, int, const unsigned char *, mrb_int); +static void lib_hmac_update(mrb_state *, struct mrb_hmac *, unsigned char *, mrb_int); + + +#if defined(USE_DIGEST_PICOHASH) + +#define HAVE_MD5 +#define HAVE_SHA1 + +struct mrb_md { + picohash_ctx_t ctx; +}; + +struct mrb_hmac { + picohash_ctx_t ctx; +}; + +static void +lib_md_free(mrb_state *mrb, void *ptr) +{ + struct mrb_md *md = ptr; + if (md != NULL) + mrb_free(mrb, md); +} + +static void +lib_hmac_free(mrb_state *mrb, void *ptr) +{ + struct mrb_hmac *hmac = ptr; + if (hmac != NULL) + mrb_free(mrb, hmac); +} + +static struct mrb_data_type mrb_md_type = { "MD", lib_md_free }; +static struct mrb_data_type mrb_hmac_type = { "HMAC", lib_hmac_free }; + +static void +lib_init(void) +{ +} + +static int +lib_md_block_length(const struct mrb_md *md) +{ + return (int)md->ctx.block_length; +} + +static mrb_value +lib_md_digest(mrb_state *mrb, const struct mrb_md *md) +{ + picohash_ctx_t ctx; + unsigned char mdstr[PICOHASH_MAX_DIGEST_LENGTH]; + + ctx = md->ctx; + picohash_final(&ctx, mdstr); + return mrb_str_new(mrb, (char *)mdstr, ctx.digest_length); +} + +static mrb_value +lib_md_digest_bang(mrb_state *mrb, struct mrb_md *md) +{ + unsigned char mdstr[PICOHASH_MAX_DIGEST_LENGTH]; + + picohash_final(&md->ctx, mdstr); + picohash_reset(&md->ctx); + return mrb_str_new(mrb, (char *)mdstr, md->ctx.digest_length); +} + +static int +lib_md_digest_length(const struct mrb_md *md) +{ + return md->ctx.digest_length; +} + +static void (*md_type_md(int type))(picohash_ctx_t *) +{ + switch (type) { + case MD_TYPE_MD5: return picohash_init_md5; + case MD_TYPE_SHA1: return picohash_init_sha1; + default: return NULL; + } +} + +static void +lib_md_init(mrb_state *mrb, struct mrb_md *md, int type) +{ + void (*ctor)(picohash_ctx_t *) = md_type_md(type); + if (ctor == NULL) + mrb_raise(mrb, E_NOTIMP_ERROR, "not supported"); + ctor(&md->ctx); +} + +static void +lib_md_init_copy(mrb_state *mrb, struct mrb_md *mdnew, struct mrb_md *mdold) +{ + mdnew->ctx = mdold->ctx; + picohash_reset(&mdnew->ctx); +} + +static void +lib_md_reset(mrb_state *mrb, struct mrb_md *md) +{ + picohash_reset(&md->ctx); +} + +static void +lib_md_update(mrb_state *mrb, struct mrb_md *md, unsigned char *str, mrb_int len) +{ +#if MRB_INT_MAX > SIZE_MAX + if (len > SIZE_MAX) + mrb_raise(mrb, E_ARGUMENT_ERROR, "too long string (not supported yet)"); +#endif + picohash_update(&md->ctx, str, len); +} + +static mrb_value +lib_hmac_digest(mrb_state *mrb, const struct mrb_hmac *hmac) +{ + picohash_ctx_t ctx; + unsigned char mdstr[PICOHASH_MAX_DIGEST_LENGTH]; + + ctx = hmac->ctx; + picohash_final(&ctx, mdstr); + return mrb_str_new(mrb, (char *)mdstr, ctx.digest_length); +} + +static int +lib_hmac_block_length(const struct mrb_hmac *hmac) +{ + return hmac->ctx.block_length; +} + +static int +lib_hmac_digest_length(const struct mrb_hmac *hmac) +{ + return hmac->ctx.digest_length; +} + +static void +lib_hmac_init(mrb_state *mrb, struct mrb_hmac *hmac, int type, const unsigned char *key, mrb_int keylen) +{ + void (*ctor)(picohash_ctx_t *) = md_type_md(type); + +#if MRB_INT_MAX > SIZE_MAX + if (keylen > SIZE_MAX) + mrb_raise(mrb, E_ARGUMENT_ERROR, "too long key"); +#endif + if (ctor == NULL) + mrb_raise(mrb, E_NOTIMP_ERROR, "not supported"); + picohash_init_hmac(&hmac->ctx, ctor, key, keylen); +} + +static void +lib_hmac_update(mrb_state *mrb, struct mrb_hmac *hmac, unsigned char *data, mrb_int len) +{ +#if MRB_INT_MAX > SIZE_MAX + if (len > SIZE_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "too long string (not supported yet)"); + } +#endif + picohash_update(&hmac->ctx, data, len); +} + +#elif defined(USE_DIGEST_OPENSSL) +/* + * OpenSSL Implementation + */ + +#define HAVE_MD5 + +#ifndef OPENSSL_NO_RIPEMD +#define HAVE_RMD160 +#endif + +#define HAVE_SHA1 +#ifdef SHA256_DIGEST_LENGTH +#define HAVE_SHA256 +#endif +#ifdef SHA512_DIGEST_LENGTH +#define HAVE_SHA384 +#define HAVE_SHA512 +#endif + +struct mrb_md { + EVP_MD_CTX *ctx; +}; + +struct mrb_hmac { + HMAC_CTX ctx; + const EVP_MD *md; +}; + +static void +lib_md_free(mrb_state *mrb, void *ptr) +{ + struct mrb_md *md = ptr; + + if (md != NULL) { + if (md->ctx != NULL) { + EVP_MD_CTX_destroy(md->ctx); + } + mrb_free(mrb, md); + } +} + +static void +lib_hmac_free(mrb_state *mrb, void *ptr) +{ + struct mrb_hmac *hmac = ptr; + + if (hmac != NULL) { + HMAC_CTX_cleanup(&hmac->ctx); + mrb_free(mrb, hmac); + } +} + +static struct mrb_data_type mrb_md_type = { "MD", lib_md_free }; +static struct mrb_data_type mrb_hmac_type = { "HMAC", lib_hmac_free }; + +static void +lib_init(void) +{ + OpenSSL_add_all_digests(); +} + +static int +lib_md_block_length(const struct mrb_md *md) +{ + return EVP_MD_CTX_block_size(md->ctx); +} + +static mrb_value +lib_md_digest(mrb_state *mrb, const struct mrb_md *md) +{ + EVP_MD_CTX ctx; + unsigned int mdlen; + unsigned char mdstr[EVP_MAX_MD_SIZE]; + + EVP_MD_CTX_copy(&ctx, md->ctx); + EVP_DigestFinal(&ctx, mdstr, &mdlen); + return mrb_str_new(mrb, (char *)mdstr, mdlen); +} + +static mrb_value +lib_md_digest_bang(mrb_state *mrb, struct mrb_md *md) +{ + unsigned int mdlen; + unsigned char mdstr[EVP_MAX_MD_SIZE]; + + EVP_DigestFinal_ex(md->ctx, mdstr, &mdlen); + EVP_DigestInit_ex(md->ctx, EVP_MD_CTX_md(md->ctx), NULL); + return mrb_str_new(mrb, (char *)mdstr, mdlen); +} + +static int +lib_md_digest_length(const struct mrb_md *md) +{ + return EVP_MD_CTX_size(md->ctx); +} + +const EVP_MD * +md_type_md(int type) +{ + switch (type) { + case MD_TYPE_MD5: return EVP_md5(); +#ifdef HAVE_RMD160 + case MD_TYPE_RMD160: return EVP_ripemd160(); +#endif + case MD_TYPE_SHA1: return EVP_sha1(); +#ifdef HAVE_SHA256 + case MD_TYPE_SHA256: return EVP_sha256(); +#endif +#ifdef HAVE_SHA512 + case MD_TYPE_SHA384: return EVP_sha384(); + case MD_TYPE_SHA512: return EVP_sha512(); +#endif + default: return NULL; + } +} + +static void +lib_md_init(mrb_state *mrb, struct mrb_md *md, int type) +{ + const EVP_MD *evpmd; + + md->ctx = NULL; + evpmd = md_type_md(type); + if (!evpmd) { + mrb_raise(mrb, E_NOTIMP_ERROR, "not supported"); + } + md->ctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(md->ctx, evpmd, NULL); +} + +static void +lib_md_init_copy(mrb_state *mrb, struct mrb_md *mdnew, struct mrb_md *mdold) +{ + mdnew->ctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(mdnew->ctx, EVP_MD_CTX_md(mdold->ctx), NULL); +} + +static void +lib_md_reset(mrb_state *mrb, struct mrb_md *md) +{ + //EVP_MD_CTX_init(&md->ctx); + EVP_DigestInit_ex(md->ctx, EVP_MD_CTX_md(md->ctx), NULL); +} + +static void +lib_md_update(mrb_state *mrb, struct mrb_md *md, unsigned char *str, mrb_int len) +{ +#if MRB_INT_MAX > SIZE_MAX + if (len > SIZE_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "too long string (not supported yet)"); + } +#endif + EVP_DigestUpdate(md->ctx, str, len); +} + +static mrb_value +lib_hmac_digest(mrb_state *mrb, const struct mrb_hmac *hmac) +{ + HMAC_CTX ctx; + unsigned int mdlen; + unsigned char mdstr[EVP_MAX_MD_SIZE]; + + memcpy(&ctx, &hmac->ctx, sizeof(ctx)); + HMAC_Final(&ctx, mdstr, &mdlen); + return mrb_str_new(mrb, (char *)mdstr, mdlen); +} + +static int +lib_hmac_block_length(const struct mrb_hmac *hmac) +{ + return EVP_MD_block_size(hmac->md); +} + +static int +lib_hmac_digest_length(const struct mrb_hmac *hmac) +{ + return EVP_MD_size(hmac->md); +} + +static void +lib_hmac_init(mrb_state *mrb, struct mrb_hmac *hmac, int type, const unsigned char *key, mrb_int keylen) +{ +#if MRB_INT_MAX > INT_MAX + if (keylen > INT_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "too long key"); + } +#endif + hmac->md = md_type_md(type); + HMAC_CTX_init(&hmac->ctx); + HMAC_Init_ex(&hmac->ctx, key, keylen, hmac->md, NULL); +} + +static void +lib_hmac_update(mrb_state *mrb, struct mrb_hmac *hmac, unsigned char *data, mrb_int len) +{ +#if MRB_INT_MAX > INT_MAX + if (len > INT_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "too long string (not supported yet)"); + } +#endif + HMAC_Update(&hmac->ctx, data, len); +} + +#elif defined(USE_DIGEST_OSX_COMMONCRYPTO) +/* + * Mac OS X CommonCrypto Implementation + */ + +#define HAVE_MD5 +/* #define HAVE_RMD160 */ +#define HAVE_SHA1 +#define HAVE_SHA256 +#define HAVE_SHA384 +#define HAVE_SHA512 + +struct mrb_md { + int type; + void *ctx; + int ctx_size; +}; + +struct mrb_hmac { + int type; + CCHmacContext ctx; +}; + +static int +md_ctx_size(int type) +{ + switch (type) { + case MD_TYPE_MD5: return sizeof(CC_MD5_CTX); + case MD_TYPE_SHA1: return sizeof(CC_SHA1_CTX); + case MD_TYPE_SHA256: return sizeof(CC_SHA256_CTX); + case MD_TYPE_SHA384: return sizeof(CC_SHA512_CTX); /* ! */ + case MD_TYPE_SHA512: return sizeof(CC_SHA512_CTX); + default: return 0; + } +} + +static void +lib_md_free(mrb_state *mrb, void *ptr) +{ + struct mrb_md *md = ptr; + + memset(md->ctx, 0, md_ctx_size(md->type)); + mrb_free(mrb, md->ctx); + mrb_free(mrb, md); +} + +static void +lib_hmac_free(mrb_state *mrb, void *ptr) +{ + struct mrb_hmac *hmac = ptr; + + memset(&hmac->ctx, 0, sizeof(hmac->ctx)); + mrb_free(mrb, hmac); +} + +static struct mrb_data_type mrb_md_type = { "MD", lib_md_free }; +static struct mrb_data_type mrb_hmac_type = { "HMAC", lib_hmac_free }; + +#define MAX_DIGEST_LENGTH CC_SHA512_DIGEST_LENGTH + +union ctx_union { + CC_MD5_CTX md5; + CC_SHA1_CTX sha1; + CC_SHA256_CTX sha256; + /* we don't have CC_SHA384_CTX! */ + CC_SHA512_CTX sha512; +}; + +static void +lib_init(void) +{ +} + +static int +md_block_length(int type) +{ + switch (type) { + case MD_TYPE_MD5: return CC_MD5_BLOCK_BYTES; + case MD_TYPE_SHA1: return CC_SHA1_BLOCK_BYTES; + case MD_TYPE_SHA256: return CC_SHA256_BLOCK_BYTES; + case MD_TYPE_SHA384: return CC_SHA384_BLOCK_BYTES; + case MD_TYPE_SHA512: return CC_SHA512_BLOCK_BYTES; + default: return 0; + } +} + +static int +lib_md_block_length(const struct mrb_md *md) +{ + return md_block_length(md->type); +} + +static void +md_init(int type, void *ctxp) +{ + switch (type) { + case MD_TYPE_MD5: CC_MD5_Init(ctxp); break; + case MD_TYPE_SHA1: CC_SHA1_Init(ctxp); break; + case MD_TYPE_SHA256: CC_SHA256_Init(ctxp); break; + case MD_TYPE_SHA384: CC_SHA384_Init(ctxp); break; + case MD_TYPE_SHA512: CC_SHA512_Init(ctxp); break; + default: break; + } +} + +static void +md_final(int type, unsigned char *str, void *ctx) +{ + switch (type) { + case MD_TYPE_MD5: CC_MD5_Final(str, ctx); break; + case MD_TYPE_SHA1: CC_SHA1_Final(str, ctx); break; + case MD_TYPE_SHA256: CC_SHA256_Final(str, ctx); break; + case MD_TYPE_SHA384: CC_SHA384_Final(str, ctx); break; + case MD_TYPE_SHA512: CC_SHA512_Final(str, ctx); break; + default: break; + } +} + +static int +md_digest_length(int type) +{ + switch (type) { + case MD_TYPE_MD5: return 16; + case MD_TYPE_SHA1: return 20; + case MD_TYPE_SHA256: return 32; + case MD_TYPE_SHA384: return 48; + case MD_TYPE_SHA512: return 64; + default: return 0; + } +} + +static mrb_value +lib_md_digest(mrb_state *mrb, const struct mrb_md *md) +{ + union ctx_union ctx; + unsigned char mdstr[MAX_DIGEST_LENGTH]; + + memcpy(&ctx, md->ctx, md_ctx_size(md->type)); + md_final(md->type, mdstr, &ctx); + return mrb_str_new(mrb, (char *)mdstr, md_digest_length(md->type)); +} + +static mrb_value +lib_md_digest_bang(mrb_state *mrb, struct mrb_md *md) +{ + unsigned char mdstr[MAX_DIGEST_LENGTH]; + + md_final(md->type, mdstr, md->ctx); + md_init(md->type, md->ctx); + return mrb_str_new(mrb, (char *)mdstr, md_digest_length(md->type)); +} + +static int +lib_md_digest_length(const struct mrb_md *md) +{ + return md_digest_length(md->type); +} + +static void +lib_md_init(mrb_state *mrb, struct mrb_md *md, int type) +{ + int ctxsize; + + ctxsize = md_ctx_size(type); + if (ctxsize == 0) { + mrb_raise(mrb, E_NOTIMP_ERROR, "not supported"); + } + md->type = type; + md->ctx = NULL; + md->ctx = mrb_malloc(mrb, ctxsize); + md_init(type, md->ctx); +} + +static void +lib_md_init_copy(mrb_state *mrb, struct mrb_md *mdnew, struct mrb_md *mdold) +{ + lib_md_init(mrb, mdnew, mdold->type); +} + +static void +lib_md_reset(mrb_state *mrb, struct mrb_md *md) +{ + md_init(md->type, md->ctx); +} + +static void +lib_md_update(mrb_state *mrb, struct mrb_md *md, unsigned char *data, mrb_int len) +{ + if (sizeof(len) > sizeof(CC_LONG)) { + if (len != (CC_LONG)len) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "too long string (not supported yet)"); + } + } + switch (md->type) { + case MD_TYPE_MD5: CC_MD5_Update(md->ctx, data, len); break; + case MD_TYPE_SHA1: CC_SHA1_Update(md->ctx, data, len); break; + case MD_TYPE_SHA256: CC_SHA256_Update(md->ctx, data, len); break; + case MD_TYPE_SHA384: CC_SHA384_Update(md->ctx, data, len); break; + case MD_TYPE_SHA512: CC_SHA512_Update(md->ctx, data, len); break; + default: break; + } +} + +static int +lib_hmac_block_length(const struct mrb_hmac *hmac) +{ + return md_block_length(hmac->type); +} + +static mrb_value +lib_hmac_digest(mrb_state *mrb, const struct mrb_hmac *hmac) +{ + CCHmacContext ctx; + unsigned char str[MAX_DIGEST_LENGTH]; + + memcpy(&ctx, &hmac->ctx, sizeof(ctx)); + CCHmacFinal(&ctx, str); + return mrb_str_new(mrb, (const char *)str, md_digest_length(hmac->type)); +} + +static int +lib_hmac_digest_length(const struct mrb_hmac *hmac) +{ + return md_digest_length(hmac->type); +} + +static void +lib_hmac_init(mrb_state *mrb, struct mrb_hmac *hmac, int type, const unsigned char *key, mrb_int keylen) +{ + CCHmacAlgorithm algorithm; + +#if MRB_INT_MAX > SIZE_MAX + if (len > SIZE_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "too long key"); + } +#endif + switch (type) { + case MD_TYPE_MD5: algorithm = kCCHmacAlgMD5; break; + case MD_TYPE_SHA1: algorithm = kCCHmacAlgSHA1; break; + case MD_TYPE_SHA256: algorithm = kCCHmacAlgSHA256; break; + case MD_TYPE_SHA384: algorithm = kCCHmacAlgSHA384; break; + case MD_TYPE_SHA512: algorithm = kCCHmacAlgSHA512; break; + default: + mrb_raisef(mrb, E_RUNTIME_ERROR, "mruby-digest: internal error: unexpected HMAC type: %S", mrb_fixnum_value(type)); + algorithm = 0; + break; + } + hmac->type = type; + CCHmacInit(&hmac->ctx, algorithm, key, keylen); +} + +static void +lib_hmac_update(mrb_state *mrb, struct mrb_hmac *hmac, unsigned char *data, mrb_int len) +{ +#if MRB_INT_MAX > SIZE_MAX + if (len > SIZE_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "too long string"); + } +#endif + CCHmacUpdate(&hmac->ctx, data, len); +} + +#endif + +static void +basecheck(mrb_state *mrb, mrb_value self, struct mrb_md **mdp) +{ + struct RClass *c; + struct mrb_md *md; + mrb_value t; + + c = mrb_obj_class(mrb, self); + t = mrb_const_get(mrb, mrb_obj_value(c), mrb_intern_lit(mrb, TYPESYM)); + if (mrb_nil_p(t)) { + mrb_raise(mrb, E_NOTIMP_ERROR, "Digest::Base is an abstract class"); + } + md = (struct mrb_md *)DATA_PTR(self); + if (!md) { + mrb_raise(mrb, E_RUNTIME_ERROR, "no md found (BUG?)"); + } + if (mdp) *mdp = md; +} + +static mrb_value +mrb_digest_block_length(mrb_state *mrb, mrb_value self) +{ + struct mrb_md *md; + + basecheck(mrb, self, &md); + return mrb_fixnum_value(lib_md_block_length(md)); +} + +static mrb_value +mrb_digest_digest(mrb_state *mrb, mrb_value self) +{ + struct mrb_md *md; + + md = (struct mrb_md *)DATA_PTR(self); + if (!md) return mrb_nil_value(); + return lib_md_digest(mrb, md); +} + +static mrb_value +mrb_digest_digest_bang(mrb_state *mrb, mrb_value self) +{ + struct mrb_md *md; + + md = (struct mrb_md *)DATA_PTR(self); + if (!md) return mrb_nil_value(); + return lib_md_digest_bang(mrb, md); +} + +static mrb_value +mrb_digest_digest_length(mrb_state *mrb, mrb_value self) +{ + struct mrb_md *md; + + basecheck(mrb, self, &md); + return mrb_fixnum_value(lib_md_digest_length(md)); +} + +static mrb_value +digest2hexdigest(mrb_state *mrb, mrb_value b) +{ + mrb_value h; + int i, len; + char *bp, buf[3]; + + bp = RSTRING_PTR(b); + len = RSTRING_LEN(b); + h = mrb_str_buf_new(mrb, len * 2); + for (i = 0; i < len; i++) { + snprintf(buf, sizeof(buf), "%02x", (unsigned char )bp[i]); + mrb_str_buf_cat(mrb, h, buf, 2); + } + return h; +} + +static mrb_value +mrb_digest_hexdigest(mrb_state *mrb, mrb_value self) +{ + return digest2hexdigest(mrb, mrb_digest_digest(mrb, self)); +} + +static mrb_value +mrb_digest_init(mrb_state *mrb, mrb_value self) +{ + struct RClass *c; + struct mrb_md *md; + mrb_value t; + + md = (struct mrb_md *)DATA_PTR(self); + if (md) { + lib_md_free(mrb, md); + } + DATA_TYPE(self) = &mrb_md_type; + DATA_PTR(self) = NULL; + + c = mrb_obj_class(mrb, self); + if (!mrb_const_defined(mrb, mrb_obj_value(c), mrb_intern_lit(mrb, TYPESYM))) { + mrb_raise(mrb, E_NOTIMP_ERROR, "Digest::Base is an abstract class"); + } + t = mrb_const_get(mrb, mrb_obj_value(c), mrb_intern_lit(mrb, TYPESYM)); +#if 0 + if (lib_md_supported(t)) { + mrb_raise(mrb, E_NOTIMP_ERROR, "unknown algorithm"); + } +#endif + + md = (struct mrb_md *)mrb_malloc(mrb, sizeof(*md)); + DATA_PTR(self) = md; + lib_md_init(mrb, md, mrb_fixnum(t)); + return self; +} + +static mrb_value +mrb_digest_init_copy(mrb_state *mrb, mrb_value copy) +{ + struct mrb_md *m1, *m2; + mrb_value src; + + mrb_get_args(mrb, "o", &src); + if (mrb_obj_equal(mrb, copy, src)) return copy; + if (!mrb_obj_is_instance_of(mrb, src, mrb_obj_class(mrb, copy))) { + mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); + } + if (!DATA_PTR(copy)) { + DATA_PTR(copy) = mrb_malloc(mrb, sizeof(struct mrb_md)); + DATA_TYPE(copy) = &mrb_md_type; + } + m1 = DATA_PTR(src); + m2 = DATA_PTR(copy); + lib_md_init_copy(mrb, m2, m1); + return copy; +} + +static mrb_value +mrb_digest_reset(mrb_state *mrb, mrb_value self) +{ + struct mrb_md *md; + + md = (struct mrb_md *)DATA_PTR(self); + if (!md) return mrb_nil_value(); + lib_md_reset(mrb, md); + return self; +} + +static mrb_value +mrb_digest_update(mrb_state *mrb, mrb_value self) +{ + struct mrb_md *md; + mrb_int len; + char *str; + + md = (struct mrb_md *)DATA_PTR(self); + if (!md) return mrb_nil_value(); + mrb_get_args(mrb, "s", &str, &len); + lib_md_update(mrb, md, (unsigned char *)str, len); + return self; +} + +static mrb_value +mrb_hmac_block_length(mrb_state *mrb, mrb_value self) +{ + struct mrb_hmac *hmac; + + hmac = (struct mrb_hmac *)DATA_PTR(self); + if (!hmac) return mrb_nil_value(); + return mrb_fixnum_value(lib_hmac_block_length(hmac)); +} + +static mrb_value +mrb_hmac_digest(mrb_state *mrb, mrb_value self) +{ + struct mrb_hmac *hmac; + + hmac = (struct mrb_hmac *)DATA_PTR(self); + if (!hmac) return mrb_nil_value(); + return lib_hmac_digest(mrb, hmac); +} + +static mrb_value +mrb_hmac_digest_length(mrb_state *mrb, mrb_value self) +{ + struct mrb_hmac *hmac; + + hmac = (struct mrb_hmac *)DATA_PTR(self); + if (!hmac) return mrb_nil_value(); + return mrb_fixnum_value(lib_hmac_digest_length(hmac)); +} + +static mrb_value +mrb_hmac_hexdigest(mrb_state *mrb, mrb_value self) +{ + return digest2hexdigest(mrb, mrb_hmac_digest(mrb, self)); +} + +static mrb_value +mrb_hmac_init(mrb_state *mrb, mrb_value self) +{ + struct mrb_hmac *hmac; + mrb_value digest, t; + mrb_int keylen; + char *key; + + hmac = (struct mrb_hmac *)DATA_PTR(self); + if (hmac) { + lib_hmac_free(mrb, hmac); + } + DATA_TYPE(self) = &mrb_hmac_type; + DATA_PTR(self) = NULL; + + mrb_get_args(mrb, "so", &key, &keylen, &digest); + t = mrb_const_get(mrb, digest, mrb_intern_lit(mrb, TYPESYM)); + if (mrb_nil_p(t)) { + mrb_raise(mrb, E_RUNTIME_ERROR, "not a digester"); + } + + hmac = (struct mrb_hmac *)mrb_malloc(mrb, sizeof(*hmac)); + DATA_PTR(self) = hmac; + lib_hmac_init(mrb, hmac, mrb_fixnum(t), (unsigned char *)key, keylen); + return self; +} + +static mrb_value +mrb_hmac_init_copy(mrb_state *mrb, mrb_value copy) +{ + mrb_raise(mrb, E_RUNTIME_ERROR, "cannot duplicate HMAC"); + return copy; +} + +static mrb_value +mrb_hmac_update(mrb_state *mrb, mrb_value self) +{ + struct mrb_hmac *hmac; + mrb_int len; + char *str; + + hmac = (struct mrb_hmac *)DATA_PTR(self); + if (!hmac) return mrb_nil_value(); + mrb_get_args(mrb, "s", &str, &len); + lib_hmac_update(mrb, hmac, (unsigned char *)str, len); + return self; +} + + +void +mrb_mruby_digest_gem_init(mrb_state *mrb) +{ + struct RClass *b, *d, *h; + + lib_init(); + + d = mrb_define_module(mrb, "Digest"); + + b = mrb_define_class_under(mrb, d, "Base", mrb->object_class); + mrb_define_method(mrb, b, "block_length", mrb_digest_block_length, MRB_ARGS_NONE()); + mrb_define_method(mrb, b, "digest", mrb_digest_digest, MRB_ARGS_NONE()); + mrb_define_method(mrb, b, "digest!", mrb_digest_digest_bang, MRB_ARGS_NONE()); /* XXX: can be defined in mrblib... */ + mrb_define_method(mrb, b, "digest_length", mrb_digest_digest_length, MRB_ARGS_NONE()); + //mrb_define_method(mrb, b, "file", mrb_digest_file, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, b, "hexdigest", mrb_digest_hexdigest, MRB_ARGS_NONE()); + //mrb_define_method(mrb, b, "hexdigest!", mrb_digest_hexdigest_bang, MRB_ARGS_NONE()); /* XXX: can be defined in mrblib... */ + mrb_define_method(mrb, b, "initialize", mrb_digest_init, MRB_ARGS_NONE()); + mrb_define_method(mrb, b, "initialize_copy", mrb_digest_init_copy, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, b, "reset", mrb_digest_reset, MRB_ARGS_NONE()); + mrb_define_method(mrb, b, "update", mrb_digest_update, MRB_ARGS_REQ(1)); + +#define DEFCLASS(n) \ +do { \ + struct RClass *a = mrb_define_class_under(mrb, d, #n, b); \ + MRB_SET_INSTANCE_TT(a, MRB_TT_DATA); \ + mrb_define_const(mrb, a, TYPESYM, mrb_fixnum_value(MD_TYPE_##n)); \ +} while (0) + +#ifdef HAVE_MD5 + DEFCLASS(MD5); +#endif +#ifdef HAVE_RMD160 + DEFCLASS(RMD160); +#endif +#ifdef HAVE_SHA1 + DEFCLASS(SHA1); +#endif +#ifdef HAVE_SHA256 + DEFCLASS(SHA256); +#endif +#ifdef HAVE_SHA384 + DEFCLASS(SHA384); +#endif +#ifdef HAVE_SHA512 + DEFCLASS(SHA512); +#endif + + h = mrb_define_class_under(mrb, d, "HMAC", mrb->object_class); + MRB_SET_INSTANCE_TT(h, MRB_TT_DATA); + mrb_define_method(mrb, h, "block_length", mrb_hmac_block_length, MRB_ARGS_NONE()); + mrb_define_method(mrb, h, "digest", mrb_hmac_digest, MRB_ARGS_NONE()); + mrb_define_method(mrb, h, "digest_length", mrb_hmac_digest_length, MRB_ARGS_NONE()); + mrb_define_method(mrb, h, "hexdigest", mrb_hmac_hexdigest, MRB_ARGS_NONE()); + mrb_define_method(mrb, h, "initialize", mrb_hmac_init, MRB_ARGS_REQ(2)); + mrb_define_method(mrb, h, "initialize_copy", mrb_hmac_init_copy, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, h, "update", mrb_hmac_update, MRB_ARGS_REQ(1)); +} + +void +mrb_mruby_digest_gem_final(mrb_state *mrb) +{ +} diff --git a/web/server/h2o/libh2o/deps/mruby-digest/src/picohash.h b/web/server/h2o/libh2o/deps/mruby-digest/src/picohash.h new file mode 100644 index 000000000..4c0206d95 --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/src/picohash.h @@ -0,0 +1,751 @@ +/* + * The code is placed under public domain by Kazuho Oku <kazuhooku@gmail.com>. + * + * The MD5 implementation is based on a public domain implementation written by + * Solar Designer <solar@openwall.com> in 2001, which is used by Dovecot. + * + * The SHA1 implementation is based on a public domain implementation written + * by Wei Dai and other contributors for libcrypt, used also in liboauth. + * + * The SHA224/SHA256 implementation is based on a public domain implementation + * by Sam Hocevar <sam@hocevar.net> for LibTomCrypt. + */ +#ifndef _picohash_h_ +#define _picohash_h_ + +#include <assert.h> +#include <inttypes.h> +#include <string.h> + +#ifdef __BIG_ENDIAN__ +#define _PICOHASH_BIG_ENDIAN +#elif defined __LITTLE_ENDIAN__ +/* override */ +#elif defined __BYTE_ORDER +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define _PICOHASH_BIG_ENDIAN +#endif +#else // ! defined __LITTLE_ENDIAN__ +#include <endian.h> // machine/endian.h +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define _PICOHASH_BIG_ENDIAN +#endif +#endif + +#define PICOHASH_MD5_BLOCK_LENGTH 64 +#define PICOHASH_MD5_DIGEST_LENGTH 16 + +typedef struct { + uint_fast32_t lo, hi; + uint_fast32_t a, b, c, d; + unsigned char buffer[64]; + uint_fast32_t block[PICOHASH_MD5_DIGEST_LENGTH]; +} _picohash_md5_ctx_t; + +static void _picohash_md5_init(_picohash_md5_ctx_t *ctx); +static void _picohash_md5_update(_picohash_md5_ctx_t *ctx, const void *data, size_t size); +static void _picohash_md5_final(_picohash_md5_ctx_t *ctx, void *digest); + +#define PICOHASH_SHA1_BLOCK_LENGTH 64 +#define PICOHASH_SHA1_DIGEST_LENGTH 20 + +typedef struct { + uint32_t buffer[PICOHASH_SHA1_BLOCK_LENGTH / 4]; + uint32_t state[PICOHASH_SHA1_DIGEST_LENGTH / 4]; + uint64_t byteCount; + uint8_t bufferOffset; +} _picohash_sha1_ctx_t; + +static void _picohash_sha1_init(_picohash_sha1_ctx_t *ctx); +static void _picohash_sha1_update(_picohash_sha1_ctx_t *ctx, const void *input, size_t len); +static void _picohash_sha1_final(_picohash_sha1_ctx_t *ctx, void *digest); + +#define PICOHASH_SHA256_BLOCK_LENGTH 64 +#define PICOHASH_SHA256_DIGEST_LENGTH 32 +#define PICOHASH_SHA224_BLOCK_LENGTH PICOHASH_SHA256_BLOCK_LENGTH +#define PICOHASH_SHA224_DIGEST_LENGTH 28 + +typedef struct { + uint64_t length; + uint32_t state[PICOHASH_SHA256_DIGEST_LENGTH / 4]; + uint32_t curlen; + unsigned char buf[PICOHASH_SHA256_BLOCK_LENGTH]; +} _picohash_sha256_ctx_t; + +static void _picohash_sha256_init(_picohash_sha256_ctx_t *ctx); +static void _picohash_sha256_update(_picohash_sha256_ctx_t *ctx, const void *data, size_t len); +static void _picohash_sha256_final(_picohash_sha256_ctx_t *ctx, void *digest); +static void _picohash_sha224_init(_picohash_sha256_ctx_t *ctx); +static void _picohash_sha224_final(_picohash_sha256_ctx_t *ctx, void *digest); + +#define PICOHASH_MAX_BLOCK_LENGTH 64 +#define PICOHASH_MAX_DIGEST_LENGTH 32 + +typedef struct { + union { + _picohash_md5_ctx_t _md5; + _picohash_sha1_ctx_t _sha1; + _picohash_sha256_ctx_t _sha256; + }; + size_t block_length; + size_t digest_length; + void (*_reset)(void *ctx); + void (*_update)(void *ctx, const void *input, size_t len); + void (*_final)(void *ctx, void *digest); + struct { + unsigned char key[PICOHASH_MAX_BLOCK_LENGTH]; + void (*hash_reset)(void *ctx); + void (*hash_final)(void *ctx, void *digest); + } _hmac; +} picohash_ctx_t; + +static void picohash_init_md5(picohash_ctx_t *ctx); +static void picohash_init_sha1(picohash_ctx_t *ctx); +static void picohash_init_sha224(picohash_ctx_t *ctx); +static void picohash_init_sha256(picohash_ctx_t *ctx); +static void picohash_update(picohash_ctx_t *ctx, const void *input, size_t len); +static void picohash_final(picohash_ctx_t *ctx, void *digest); +static void picohash_reset(picohash_ctx_t *ctx); + +static void picohash_init_hmac(picohash_ctx_t *ctx, void (*initf)(picohash_ctx_t *), const void *key, size_t key_len); + +/* following are private definitions */ + +/* + * The basic MD5 functions. + * + * F is optimized compared to its RFC 1321 definition just like in Colin + * Plumb's implementation. + */ +#define _PICOHASH_MD5_F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define _PICOHASH_MD5_G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) +#define _PICOHASH_MD5_H(x, y, z) ((x) ^ (y) ^ (z)) +#define _PICOHASH_MD5_I(x, y, z) ((y) ^ ((x) | ~(z))) + +/* + * The MD5 transformation for all four rounds. + */ +#define _PICOHASH_MD5_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. + * + * The check for little-endian architectures which tolerate unaligned + * memory accesses is just an optimization. Nothing will break if it + * doesn't work. + */ +#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) +#define _PICOHASH_MD5_SET(n) (*(const uint32_t *)&ptr[(n)*4]) +#define _PICOHASH_MD5_GET(n) _PICOHASH_MD5_SET(n) +#else +#define _PICOHASH_MD5_SET(n) \ + (ctx->block[(n)] = (uint_fast32_t)ptr[(n)*4] | ((uint_fast32_t)ptr[(n)*4 + 1] << 8) | ((uint_fast32_t)ptr[(n)*4 + 2] << 16) | \ + ((uint_fast32_t)ptr[(n)*4 + 3] << 24)) +#define _PICOHASH_MD5_GET(n) (ctx->block[(n)]) +#endif + +/* + * This processes one or more 64-byte data blocks, but does NOT update + * the bit counters. There're no alignment requirements. + */ +static const void *_picohash_md5_body(_picohash_md5_ctx_t *ctx, const void *data, size_t size) +{ + const unsigned char *ptr; + uint_fast32_t a, b, c, d; + uint_fast32_t saved_a, saved_b, saved_c, saved_d; + + ptr = 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 */ + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, a, b, c, d, _PICOHASH_MD5_SET(0), 0xd76aa478, 7) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, d, a, b, c, _PICOHASH_MD5_SET(1), 0xe8c7b756, 12) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, c, d, a, b, _PICOHASH_MD5_SET(2), 0x242070db, 17) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, b, c, d, a, _PICOHASH_MD5_SET(3), 0xc1bdceee, 22) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, a, b, c, d, _PICOHASH_MD5_SET(4), 0xf57c0faf, 7) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, d, a, b, c, _PICOHASH_MD5_SET(5), 0x4787c62a, 12) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, c, d, a, b, _PICOHASH_MD5_SET(6), 0xa8304613, 17) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, b, c, d, a, _PICOHASH_MD5_SET(7), 0xfd469501, 22) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, a, b, c, d, _PICOHASH_MD5_SET(8), 0x698098d8, 7) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, d, a, b, c, _PICOHASH_MD5_SET(9), 0x8b44f7af, 12) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, c, d, a, b, _PICOHASH_MD5_SET(10), 0xffff5bb1, 17) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, b, c, d, a, _PICOHASH_MD5_SET(11), 0x895cd7be, 22) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, a, b, c, d, _PICOHASH_MD5_SET(12), 0x6b901122, 7) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, d, a, b, c, _PICOHASH_MD5_SET(13), 0xfd987193, 12) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, c, d, a, b, _PICOHASH_MD5_SET(14), 0xa679438e, 17) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, b, c, d, a, _PICOHASH_MD5_SET(15), 0x49b40821, 22) + + /* Round 2 */ + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, a, b, c, d, _PICOHASH_MD5_GET(1), 0xf61e2562, 5) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, d, a, b, c, _PICOHASH_MD5_GET(6), 0xc040b340, 9) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, c, d, a, b, _PICOHASH_MD5_GET(11), 0x265e5a51, 14) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, b, c, d, a, _PICOHASH_MD5_GET(0), 0xe9b6c7aa, 20) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, a, b, c, d, _PICOHASH_MD5_GET(5), 0xd62f105d, 5) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, d, a, b, c, _PICOHASH_MD5_GET(10), 0x02441453, 9) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, c, d, a, b, _PICOHASH_MD5_GET(15), 0xd8a1e681, 14) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, b, c, d, a, _PICOHASH_MD5_GET(4), 0xe7d3fbc8, 20) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, a, b, c, d, _PICOHASH_MD5_GET(9), 0x21e1cde6, 5) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, d, a, b, c, _PICOHASH_MD5_GET(14), 0xc33707d6, 9) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, c, d, a, b, _PICOHASH_MD5_GET(3), 0xf4d50d87, 14) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, b, c, d, a, _PICOHASH_MD5_GET(8), 0x455a14ed, 20) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, a, b, c, d, _PICOHASH_MD5_GET(13), 0xa9e3e905, 5) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, d, a, b, c, _PICOHASH_MD5_GET(2), 0xfcefa3f8, 9) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, c, d, a, b, _PICOHASH_MD5_GET(7), 0x676f02d9, 14) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, b, c, d, a, _PICOHASH_MD5_GET(12), 0x8d2a4c8a, 20) + + /* Round 3 */ + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, a, b, c, d, _PICOHASH_MD5_GET(5), 0xfffa3942, 4) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, d, a, b, c, _PICOHASH_MD5_GET(8), 0x8771f681, 11) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, c, d, a, b, _PICOHASH_MD5_GET(11), 0x6d9d6122, 16) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, b, c, d, a, _PICOHASH_MD5_GET(14), 0xfde5380c, 23) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, a, b, c, d, _PICOHASH_MD5_GET(1), 0xa4beea44, 4) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, d, a, b, c, _PICOHASH_MD5_GET(4), 0x4bdecfa9, 11) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, c, d, a, b, _PICOHASH_MD5_GET(7), 0xf6bb4b60, 16) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, b, c, d, a, _PICOHASH_MD5_GET(10), 0xbebfbc70, 23) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, a, b, c, d, _PICOHASH_MD5_GET(13), 0x289b7ec6, 4) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, d, a, b, c, _PICOHASH_MD5_GET(0), 0xeaa127fa, 11) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, c, d, a, b, _PICOHASH_MD5_GET(3), 0xd4ef3085, 16) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, b, c, d, a, _PICOHASH_MD5_GET(6), 0x04881d05, 23) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, a, b, c, d, _PICOHASH_MD5_GET(9), 0xd9d4d039, 4) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, d, a, b, c, _PICOHASH_MD5_GET(12), 0xe6db99e5, 11) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, c, d, a, b, _PICOHASH_MD5_GET(15), 0x1fa27cf8, 16) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, b, c, d, a, _PICOHASH_MD5_GET(2), 0xc4ac5665, 23) + + /* Round 4 */ + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, a, b, c, d, _PICOHASH_MD5_GET(0), 0xf4292244, 6) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, d, a, b, c, _PICOHASH_MD5_GET(7), 0x432aff97, 10) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, c, d, a, b, _PICOHASH_MD5_GET(14), 0xab9423a7, 15) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, b, c, d, a, _PICOHASH_MD5_GET(5), 0xfc93a039, 21) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, a, b, c, d, _PICOHASH_MD5_GET(12), 0x655b59c3, 6) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, d, a, b, c, _PICOHASH_MD5_GET(3), 0x8f0ccc92, 10) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, c, d, a, b, _PICOHASH_MD5_GET(10), 0xffeff47d, 15) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, b, c, d, a, _PICOHASH_MD5_GET(1), 0x85845dd1, 21) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, a, b, c, d, _PICOHASH_MD5_GET(8), 0x6fa87e4f, 6) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, d, a, b, c, _PICOHASH_MD5_GET(15), 0xfe2ce6e0, 10) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, c, d, a, b, _PICOHASH_MD5_GET(6), 0xa3014314, 15) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, b, c, d, a, _PICOHASH_MD5_GET(13), 0x4e0811a1, 21) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, a, b, c, d, _PICOHASH_MD5_GET(4), 0xf7537e82, 6) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, d, a, b, c, _PICOHASH_MD5_GET(11), 0xbd3af235, 10) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, c, d, a, b, _PICOHASH_MD5_GET(2), 0x2ad7d2bb, 15) + _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, b, c, d, a, _PICOHASH_MD5_GET(9), 0xeb86d391, 21) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while (size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + + return ptr; +} + +inline void _picohash_md5_init(_picohash_md5_ctx_t *ctx) +{ + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; + + ctx->lo = 0; + ctx->hi = 0; +} + +inline void _picohash_md5_update(_picohash_md5_ctx_t *ctx, const void *data, size_t size) +{ + uint_fast32_t saved_lo; + unsigned long used, free; + + saved_lo = ctx->lo; + if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) + ctx->hi++; + ctx->hi += size >> 29; + + used = saved_lo & 0x3f; + + if (used) { + free = 64 - used; + + if (size < free) { + memcpy(&ctx->buffer[used], data, size); + return; + } + + memcpy(&ctx->buffer[used], data, free); + data = (const unsigned char *)data + free; + size -= free; + _picohash_md5_body(ctx, ctx->buffer, 64); + } + + if (size >= 64) { + data = _picohash_md5_body(ctx, data, size & ~(unsigned long)0x3f); + size &= 0x3f; + } + + memcpy(ctx->buffer, data, size); +} + +inline void _picohash_md5_final(_picohash_md5_ctx_t *ctx, void *_digest) +{ + unsigned char *digest = _digest; + unsigned long used, free; + + used = ctx->lo & 0x3f; + + ctx->buffer[used++] = 0x80; + + free = 64 - used; + + if (free < 8) { + memset(&ctx->buffer[used], 0, free); + _picohash_md5_body(ctx, ctx->buffer, 64); + used = 0; + free = 64; + } + + memset(&ctx->buffer[used], 0, free - 8); + + ctx->lo <<= 3; + ctx->buffer[56] = ctx->lo; + ctx->buffer[57] = ctx->lo >> 8; + ctx->buffer[58] = ctx->lo >> 16; + ctx->buffer[59] = ctx->lo >> 24; + ctx->buffer[60] = ctx->hi; + ctx->buffer[61] = ctx->hi >> 8; + ctx->buffer[62] = ctx->hi >> 16; + ctx->buffer[63] = ctx->hi >> 24; + + _picohash_md5_body(ctx, ctx->buffer, 64); + + digest[0] = ctx->a; + digest[1] = ctx->a >> 8; + digest[2] = ctx->a >> 16; + digest[3] = ctx->a >> 24; + digest[4] = ctx->b; + digest[5] = ctx->b >> 8; + digest[6] = ctx->b >> 16; + digest[7] = ctx->b >> 24; + digest[8] = ctx->c; + digest[9] = ctx->c >> 8; + digest[10] = ctx->c >> 16; + digest[11] = ctx->c >> 24; + digest[12] = ctx->d; + digest[13] = ctx->d >> 8; + digest[14] = ctx->d >> 16; + digest[15] = ctx->d >> 24; + + memset(ctx, 0, sizeof(*ctx)); +} + +#define _PICOHASH_SHA1_K0 0x5a827999 +#define _PICOHASH_SHA1_K20 0x6ed9eba1 +#define _PICOHASH_SHA1_K40 0x8f1bbcdc +#define _PICOHASH_SHA1_K60 0xca62c1d6 + +static inline uint32_t _picohash_sha1_rol32(uint32_t number, uint8_t bits) +{ + return ((number << bits) | (number >> (32 - bits))); +} + +static inline void _picohash_sha1_hash_block(_picohash_sha1_ctx_t *s) +{ + uint8_t i; + uint32_t a, b, c, d, e, t; + + a = s->state[0]; + b = s->state[1]; + c = s->state[2]; + d = s->state[3]; + e = s->state[4]; + for (i = 0; i < 80; i++) { + if (i >= 16) { + t = s->buffer[(i + 13) & 15] ^ s->buffer[(i + 8) & 15] ^ s->buffer[(i + 2) & 15] ^ s->buffer[i & 15]; + s->buffer[i & 15] = _picohash_sha1_rol32(t, 1); + } + if (i < 20) { + t = (d ^ (b & (c ^ d))) + _PICOHASH_SHA1_K0; + } else if (i < 40) { + t = (b ^ c ^ d) + _PICOHASH_SHA1_K20; + } else if (i < 60) { + t = ((b & c) | (d & (b | c))) + _PICOHASH_SHA1_K40; + } else { + t = (b ^ c ^ d) + _PICOHASH_SHA1_K60; + } + t += _picohash_sha1_rol32(a, 5) + e + s->buffer[i & 15]; + e = d; + d = c; + c = _picohash_sha1_rol32(b, 30); + b = a; + a = t; + } + s->state[0] += a; + s->state[1] += b; + s->state[2] += c; + s->state[3] += d; + s->state[4] += e; +} + +static inline void _picohash_sha1_add_uncounted(_picohash_sha1_ctx_t *s, uint8_t data) +{ + uint8_t *const b = (uint8_t *)s->buffer; +#ifdef _PICOHASH_BIG_ENDIAN + b[s->bufferOffset] = data; +#else + b[s->bufferOffset ^ 3] = data; +#endif + s->bufferOffset++; + if (s->bufferOffset == PICOHASH_SHA1_BLOCK_LENGTH) { + _picohash_sha1_hash_block(s); + s->bufferOffset = 0; + } +} + +inline void _picohash_sha1_init(_picohash_sha1_ctx_t *s) +{ + s->state[0] = 0x67452301; + s->state[1] = 0xefcdab89; + s->state[2] = 0x98badcfe; + s->state[3] = 0x10325476; + s->state[4] = 0xc3d2e1f0; + s->byteCount = 0; + s->bufferOffset = 0; +} + +inline void _picohash_sha1_update(_picohash_sha1_ctx_t *s, const void *_data, size_t len) +{ + const uint8_t *data = _data; + for (; len != 0; --len) { + ++s->byteCount; + _picohash_sha1_add_uncounted(s, *data++); + } +} + +inline void _picohash_sha1_final(_picohash_sha1_ctx_t *s, void *digest) +{ + // Pad with 0x80 followed by 0x00 until the end of the block + _picohash_sha1_add_uncounted(s, 0x80); + while (s->bufferOffset != 56) + _picohash_sha1_add_uncounted(s, 0x00); + + // Append length in the last 8 bytes + _picohash_sha1_add_uncounted(s, s->byteCount >> 53); // Shifting to multiply by 8 + _picohash_sha1_add_uncounted(s, s->byteCount >> 45); // as SHA-1 supports bitstreams as well as + _picohash_sha1_add_uncounted(s, s->byteCount >> 37); // byte. + _picohash_sha1_add_uncounted(s, s->byteCount >> 29); + _picohash_sha1_add_uncounted(s, s->byteCount >> 21); + _picohash_sha1_add_uncounted(s, s->byteCount >> 13); + _picohash_sha1_add_uncounted(s, s->byteCount >> 5); + _picohash_sha1_add_uncounted(s, s->byteCount << 3); + +#ifndef SHA_BIG_ENDIAN + { // Swap byte order back + int i; + for (i = 0; i < 5; i++) { + s->state[i] = (((s->state[i]) << 24) & 0xff000000) | (((s->state[i]) << 8) & 0x00ff0000) | + (((s->state[i]) >> 8) & 0x0000ff00) | (((s->state[i]) >> 24) & 0x000000ff); + } + } +#endif + + memcpy(digest, s->state, sizeof(s->state)); +} + +#define _picohash_sha256_ch(x, y, z) (z ^ (x & (y ^ z))) +#define _picohash_sha256_maj(x, y, z) (((x | y) & z) | (x & y)) +#define _picohash_sha256_s(x, y) \ + (((((uint32_t)(x)&0xFFFFFFFFUL) >> (uint32_t)((y)&31)) | ((uint32_t)(x) << (uint32_t)(32 - ((y)&31)))) & 0xFFFFFFFFUL) +#define _picohash_sha256_r(x, n) (((x)&0xFFFFFFFFUL) >> (n)) +#define _picohash_sha256_sigma0(x) (_picohash_sha256_s(x, 2) ^ _picohash_sha256_s(x, 13) ^ _picohash_sha256_s(x, 22)) +#define _picohash_sha256_sigma1(x) (_picohash_sha256_s(x, 6) ^ _picohash_sha256_s(x, 11) ^ _picohash_sha256_s(x, 25)) +#define _picohash_sha256_gamma0(x) (_picohash_sha256_s(x, 7) ^ _picohash_sha256_s(x, 18) ^ _picohash_sha256_r(x, 3)) +#define _picohash_sha256_gamma1(x) (_picohash_sha256_s(x, 17) ^ _picohash_sha256_s(x, 19) ^ _picohash_sha256_r(x, 10)) +#define _picohash_sha256_rnd(a, b, c, d, e, f, g, h, i) \ + t0 = h + _picohash_sha256_sigma1(e) + _picohash_sha256_ch(e, f, g) + K[i] + W[i]; \ + t1 = _picohash_sha256_sigma0(a) + _picohash_sha256_maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + +static inline void _picohash_sha256_compress(_picohash_sha256_ctx_t *ctx, unsigned char *buf) +{ + static const uint32_t K[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL}; + uint32_t S[8], W[64], t, t0, t1; + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) + S[i] = ctx->state[i]; + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) + W[i] = + (uint32_t)buf[4 * i] << 24 | (uint32_t)buf[4 * i + 1] << 16 | (uint32_t)buf[4 * i + 2] << 8 | (uint32_t)buf[4 * i + 3]; + + /* fill W[16..63] */ + for (i = 16; i < 64; i++) + W[i] = _picohash_sha256_gamma1(W[i - 2]) + W[i - 7] + _picohash_sha256_gamma0(W[i - 15]) + W[i - 16]; + + /* Compress */ + for (i = 0; i < 64; ++i) { + _picohash_sha256_rnd(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i); + t = S[7]; + S[7] = S[6]; + S[6] = S[5]; + S[5] = S[4]; + S[4] = S[3]; + S[3] = S[2]; + S[2] = S[1]; + S[1] = S[0]; + S[0] = t; + } + + /* feedback */ + for (i = 0; i < 8; i++) + ctx->state[i] = ctx->state[i] + S[i]; +} + +static inline void _picohash_sha256_do_final(_picohash_sha256_ctx_t *ctx, void *digest, size_t len) +{ + unsigned char *out = digest; + size_t i; + + /* increase the length of the message */ + ctx->length += ctx->curlen * 8; + + /* append the '1' bit */ + ctx->buf[ctx->curlen++] = (unsigned char)0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (ctx->curlen > 56) { + while (ctx->curlen < 64) { + ctx->buf[ctx->curlen++] = (unsigned char)0; + } + _picohash_sha256_compress(ctx, ctx->buf); + ctx->curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (ctx->curlen < 56) { + ctx->buf[ctx->curlen++] = (unsigned char)0; + } + + /* store length */ + for (i = 0; i != 8; ++i) + ctx->buf[56 + i] = ctx->length >> (56 - 8 * i); + _picohash_sha256_compress(ctx, ctx->buf); + + /* copy output */ + for (i = 0; i != len / 4; ++i) { + out[i * 4] = ctx->state[i] >> 24; + out[i * 4 + 1] = ctx->state[i] >> 16; + out[i * 4 + 2] = ctx->state[i] >> 8; + out[i * 4 + 3] = ctx->state[i]; + } +} + +inline void _picohash_sha256_init(_picohash_sha256_ctx_t *ctx) +{ + ctx->curlen = 0; + ctx->length = 0; + ctx->state[0] = 0x6A09E667UL; + ctx->state[1] = 0xBB67AE85UL; + ctx->state[2] = 0x3C6EF372UL; + ctx->state[3] = 0xA54FF53AUL; + ctx->state[4] = 0x510E527FUL; + ctx->state[5] = 0x9B05688CUL; + ctx->state[6] = 0x1F83D9ABUL; + ctx->state[7] = 0x5BE0CD19UL; +} + +inline void _picohash_sha256_update(_picohash_sha256_ctx_t *ctx, const void *data, size_t len) +{ + const unsigned char *in = data; + size_t n; + + while (len > 0) { + if (ctx->curlen == 0 && len >= PICOHASH_SHA256_BLOCK_LENGTH) { + _picohash_sha256_compress(ctx, (unsigned char *)in); + ctx->length += PICOHASH_SHA256_BLOCK_LENGTH * 8; + in += PICOHASH_SHA256_BLOCK_LENGTH; + len -= PICOHASH_SHA256_BLOCK_LENGTH; + } else { + n = PICOHASH_SHA256_BLOCK_LENGTH - ctx->curlen; + if (n > len) + n = len; + memcpy(ctx->buf + ctx->curlen, in, (size_t)n); + ctx->curlen += n; + in += n; + len -= n; + if (ctx->curlen == 64) { + _picohash_sha256_compress(ctx, ctx->buf); + ctx->length += 8 * PICOHASH_SHA256_BLOCK_LENGTH; + ctx->curlen = 0; + } + } + } +} + +inline void _picohash_sha256_final(_picohash_sha256_ctx_t *ctx, void *digest) +{ + _picohash_sha256_do_final(ctx, digest, PICOHASH_SHA256_DIGEST_LENGTH); +} + +inline void _picohash_sha224_init(_picohash_sha256_ctx_t *ctx) +{ + ctx->curlen = 0; + ctx->length = 0; + ctx->state[0] = 0xc1059ed8UL; + ctx->state[1] = 0x367cd507UL; + ctx->state[2] = 0x3070dd17UL; + ctx->state[3] = 0xf70e5939UL; + ctx->state[4] = 0xffc00b31UL; + ctx->state[5] = 0x68581511UL; + ctx->state[6] = 0x64f98fa7UL; + ctx->state[7] = 0xbefa4fa4UL; +} + +inline void _picohash_sha224_final(_picohash_sha256_ctx_t *ctx, void *digest) +{ + _picohash_sha256_do_final(ctx, digest, PICOHASH_SHA224_DIGEST_LENGTH); +} + +inline void picohash_init_md5(picohash_ctx_t *ctx) +{ + ctx->block_length = PICOHASH_MD5_BLOCK_LENGTH; + ctx->digest_length = PICOHASH_MD5_DIGEST_LENGTH; + ctx->_reset = (void *)_picohash_md5_init; + ctx->_update = (void *)_picohash_md5_update; + ctx->_final = (void *)_picohash_md5_final; + + _picohash_md5_init(&ctx->_md5); +} + +inline void picohash_init_sha1(picohash_ctx_t *ctx) +{ + ctx->block_length = PICOHASH_SHA1_BLOCK_LENGTH; + ctx->digest_length = PICOHASH_SHA1_DIGEST_LENGTH; + ctx->_reset = (void *)_picohash_sha1_init; + ctx->_update = (void *)_picohash_sha1_update; + ctx->_final = (void *)_picohash_sha1_final; + _picohash_sha1_init(&ctx->_sha1); +} + +inline void picohash_init_sha224(picohash_ctx_t *ctx) +{ + ctx->block_length = PICOHASH_SHA224_BLOCK_LENGTH; + ctx->digest_length = PICOHASH_SHA224_DIGEST_LENGTH; + ctx->_reset = (void *)_picohash_sha224_init; + ctx->_update = (void *)_picohash_sha256_update; + ctx->_final = (void *)_picohash_sha224_final; + _picohash_sha224_init(&ctx->_sha256); +} + +inline void picohash_init_sha256(picohash_ctx_t *ctx) +{ + ctx->block_length = PICOHASH_SHA256_BLOCK_LENGTH; + ctx->digest_length = PICOHASH_SHA256_DIGEST_LENGTH; + ctx->_reset = (void *)_picohash_sha256_init; + ctx->_update = (void *)_picohash_sha256_update; + ctx->_final = (void *)_picohash_sha256_final; + _picohash_sha256_init(&ctx->_sha256); +} + +inline void picohash_update(picohash_ctx_t *ctx, const void *input, size_t len) +{ + ctx->_update(ctx, input, len); +} + +inline void picohash_final(picohash_ctx_t *ctx, void *digest) +{ + ctx->_final(ctx, digest); +} + +inline void picohash_reset(picohash_ctx_t *ctx) +{ + ctx->_reset(ctx); +} + +static inline void _picohash_hmac_apply_key(picohash_ctx_t *ctx, unsigned char delta) +{ + size_t i; + for (i = 0; i != ctx->block_length; ++i) + ctx->_hmac.key[i] ^= delta; + picohash_update(ctx, ctx->_hmac.key, ctx->block_length); + for (i = 0; i != ctx->block_length; ++i) + ctx->_hmac.key[i] ^= delta; +} + +static void _picohash_hmac_final(picohash_ctx_t *ctx, void *digest) +{ + unsigned char inner_digest[PICOHASH_MAX_DIGEST_LENGTH]; + + ctx->_hmac.hash_final(ctx, inner_digest); + + ctx->_hmac.hash_reset(ctx); + _picohash_hmac_apply_key(ctx, 0x5c); + picohash_update(ctx, inner_digest, ctx->digest_length); + memset(inner_digest, 0, ctx->digest_length); + + ctx->_hmac.hash_final(ctx, digest); +} + +static inline void _picohash_hmac_reset(picohash_ctx_t *ctx) +{ + ctx->_hmac.hash_reset(ctx); + _picohash_hmac_apply_key(ctx, 0x36); +} + +inline void picohash_init_hmac(picohash_ctx_t *ctx, void (*initf)(picohash_ctx_t *), const void *key, size_t key_len) +{ + initf(ctx); + + memset(ctx->_hmac.key, 0, ctx->block_length); + if (key_len > ctx->block_length) { + /* hash the key if it is too long */ + picohash_update(ctx, key, key_len); + picohash_final(ctx, ctx->_hmac.key); + ctx->_hmac.hash_reset(ctx); + } else { + memcpy(ctx->_hmac.key, key, key_len); + } + + /* replace reset and final function */ + ctx->_hmac.hash_reset = ctx->_reset; + ctx->_hmac.hash_final = ctx->_final; + ctx->_reset = (void *)_picohash_hmac_reset; + ctx->_final = (void *)_picohash_hmac_final; + + /* start calculating the inner hash */ + _picohash_hmac_apply_key(ctx, 0x36); +} + +#endif diff --git a/web/server/h2o/libh2o/deps/mruby-digest/test/digest.rb b/web/server/h2o/libh2o/deps/mruby-digest/test/digest.rb new file mode 100644 index 000000000..fd13fa43a --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby-digest/test/digest.rb @@ -0,0 +1,203 @@ +## +# Digest Test + +if Object.const_defined?(:Digest) + assert('Digest') do + Digest.class == Module + end + + assert('Digest::Base') do + Digest::Base.class == Class + end + + assert('Digest::Base#new') do + e1 = nil + begin + Digest::Base.new + rescue NotImplementedError => e + e1 = e + end + e1.class == NotImplementedError + end + + assert('Digest::MD5') do + Digest::MD5.class == Class + end + + assert('Digest::MD5 superclass') do + Digest::MD5.superclass == Digest::Base + end + + assert('Digest::MD5.digest') do + Digest::MD5.digest('ruby') == "X\xE5=\x13$\xEE\xF6&_\xDB\x97\xB0\x8E\xD9\xAA\xDF" + end + + #assert('Digest::MD5.file') + + assert('Digest::MD5.hexdigest') do + Digest::MD5.hexdigest('ruby') == "58e53d1324eef6265fdb97b08ed9aadf" + end + + assert('Digest::MD5#update') do + d = Digest::MD5.new + d.update('ruby') + d.hexdigest == "58e53d1324eef6265fdb97b08ed9aadf" + end + + assert('Digest::MD5#update 2') do + d = Digest::MD5.new + d.update('ruby') + d.update('digest') + d.hexdigest == "2ac1b3e3db06239e3244817f281450f1" + end + + assert('Digest::MD5#<<') do + a = Digest::MD5.new + b = Digest::MD5.new + a.update('ruby') + b << "r" << "u" << "b" << "y" + a.hexdigest == b.hexdigest + end + + assert('Digest::MD5#== with Digest::XXX') do + x1 = Digest::MD5.new.update("ruby") + x2 = Digest::MD5.new.update("ruby") + x3 = Digest::MD5.new.update("RUBY") + (x1 == x2) == true and + (x1 == x3) == false + end + + assert('Digest::MD5#== with String') do + Digest::MD5.new.update("ruby") == "58e53d1324eef6265fdb97b08ed9aadf" + end + + assert('Digest::MD5#block_length') do + Digest::MD5.new.block_length == 64 + end + + assert('Digest::MD5#digest') do + Digest::MD5.new.update("ruby").digest == "X\xE5=\x13$\xEE\xF6&_\xDB\x97\xB0\x8E\xD9\xAA\xDF" + end + + assert('Digest::MD5#digest!') do + d = Digest::MD5.new.update("ruby") + d.digest! + #d.digest! == "\xD4\x1D\x8C\xD9\x8F\x00\xB2\x04\xE9\x80\t\x98\xEC\xF8B~" + # XXX: mrbtest dumps core! + d.digest! == Digest::MD5.new.digest + end + + assert('Digest::MD5#digest_length') do + d = Digest::MD5.new + n = 16 + d.digest_length == n and + d.length == n and + d.size == n + end + + #assert('Digest::MD5#file') + + assert('Digest::MD5#hexdigest') do + d = Digest::MD5.new.update("ruby") + s = "58e53d1324eef6265fdb97b08ed9aadf" + d.hexdigest == s and + d.to_s == s + end + + assert('Digest::MD5#hexdigest!') do + d = Digest::MD5.new.update("ruby") + d.hexdigest! + d.hexdigest! == "d41d8cd98f00b204e9800998ecf8427e" + end + + assert('Digest::MD5#reset') do + d = Digest::MD5.new.update("ruby") + d.reset + d.hexdigest! == "d41d8cd98f00b204e9800998ecf8427e" + end + + if Digest.const_defined? :RMD160 + assert('Digest::RMD160#hexdigest') do + d = Digest::RMD160.new.update("ruby") + s = "29d9b710bc50866fa2399c3061cd02c0c8ffa197" + d.hexdigest == s + end + end + + if Digest.const_defined? :SHA1 + assert('Digest::SHA1#hexdigest') do + d = Digest::SHA1.new.update("ruby") + s = "18e40e1401eef67e1ae69efab09afb71f87ffb81" + d.hexdigest == s + end + end + + if Digest.const_defined? :SHA256 + assert('Digest::SHA256#hexdigest') do + d = Digest::SHA256.new.update("ruby") + s = "b9138194ffe9e7c8bb6d79d1ed56259553d18d9cb60b66e3ba5aa2e5b078055a" + d.hexdigest == s + end + end + + if Digest.const_defined? :SHA384 + assert('Digest::SHA384#hexdigest') do + d = Digest::SHA384.new.update("ruby") + s = "635365ef93ebf2c7a4e40b0b497da727ab8c2914eb9f052e6be40476f95d3daf44786790f5f0e843fab419b43022e069" + d.hexdigest == s + end + end + + if Digest.const_defined? :SHA512 + assert('Digest::SHA512#hexdigest') do + d = Digest::SHA512.new.update("ruby") + s = "423408d7723a3d80baefa804bd50b61a89667efec1713386a7b8efe28e5d13968307a908778cad210d7aa2dfe7db9a2aa86895f9fc1eeefcc99814310b207a6b" + d.hexdigest == s + end + end + + assert('Digest::HMAC') do + Digest::HMAC.class == Class + end + + assert('Digest::HMAC.digest') do + Digest::HMAC.digest("data", "hash key", Digest::SHA1) == "\xFD \xECC=\xFD\x97\x0E\xEC!FW\xCF\xB5Gl]\x913f" + end + + assert('Digest::HMAC.hexdigest') do + Digest::HMAC.hexdigest("data", "hash key", Digest::SHA1) == "fd20ec433dfd970eec214657cfb5476c5d913366" + end + + assert('Digest::HMAC#<<') do + a = Digest::HMAC.new('hash key', Digest::SHA1) + b = Digest::HMAC.new('hash key', Digest::SHA1) + a.update('ruby') + b << "r" << "u" << "b" << "y" + a.hexdigest == b.hexdigest + end + + assert('Digest::HMAC#block_length') do + d = Digest::HMAC.new("hash key", Digest::SHA1) + d.block_length == 64 + end + + assert('Digest::HMAC#digest_length') do + d = Digest::HMAC.new("hash key", Digest::SHA1) + d.digest_length == 20 + end + + # assert('Digest::HMAC#reset') + + assert('Digest::HMAC#update') do + d = Digest::HMAC.new("hash key", Digest::SHA1) + d.update('data') + d.hexdigest == "fd20ec433dfd970eec214657cfb5476c5d913366" + end + + assert('Digest::HMAC#update 2') do + d = Digest::HMAC.new("hash key", Digest::SHA1) + d.update('ruby') + d.update('digest') + d.hexdigest == "e4be3728777e43deba3aa522a4247ea83b19a1c7" + end +end |