diff options
Diffstat (limited to 'web/server/h2o/libh2o/deps/mruby-digest/src/digest.c')
-rw-r--r-- | web/server/h2o/libh2o/deps/mruby-digest/src/digest.c | 1007 |
1 files changed, 1007 insertions, 0 deletions
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) +{ +} |