ext/rubysl/openssl/ossl_hmac.c in rubysl-openssl-2.10 vs ext/rubysl/openssl/ossl_hmac.c in rubysl-openssl-2.11

- old
+ new

@@ -9,12 +9,12 @@ */ #if !defined(OPENSSL_NO_HMAC) #include "ossl.h" -#define MakeHMAC(obj, klass, ctx) \ - (obj) = TypedData_Make_Struct((klass), HMAC_CTX, &ossl_hmac_type, (ctx)) +#define NewHMAC(klass) \ + TypedData_Wrap_Struct((klass), &ossl_hmac_type, 0) #define GetHMAC(obj, ctx) do { \ TypedData_Get_Struct((obj), HMAC_CTX, &ossl_hmac_type, (ctx)); \ if (!(ctx)) { \ ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \ } \ @@ -38,12 +38,11 @@ * Private */ static void ossl_hmac_free(void *ctx) { - HMAC_CTX_cleanup(ctx); - ruby_xfree(ctx); + HMAC_CTX_free(ctx); } static const rb_data_type_t ossl_hmac_type = { "OpenSSL/HMAC", { @@ -53,15 +52,18 @@ }; static VALUE ossl_hmac_alloc(VALUE klass) { - HMAC_CTX *ctx; VALUE obj; + HMAC_CTX *ctx; - MakeHMAC(obj, klass, ctx); - HMAC_CTX_init(ctx); + obj = NewHMAC(klass); + ctx = HMAC_CTX_new(); + if (!ctx) + ossl_raise(eHMACError, NULL); + RTYPEDDATA_DATA(obj) = ctx; return obj; } @@ -105,12 +107,12 @@ { HMAC_CTX *ctx; StringValue(key); GetHMAC(self, ctx); - HMAC_Init(ctx, RSTRING_PTR(key), RSTRING_LENINT(key), - GetDigestPtr(digest)); + HMAC_Init_ex(ctx, RSTRING_PTR(key), RSTRING_LENINT(key), + GetDigestPtr(digest), NULL); return self; } static VALUE @@ -122,11 +124,12 @@ if (self == other) return self; GetHMAC(self, ctx1); SafeGetHMAC(other, ctx2); - HMAC_CTX_copy(ctx1, ctx2); + if (!HMAC_CTX_copy(ctx1, ctx2)) + ossl_raise(eHMACError, "HMAC_CTX_copy"); return self; } /* * call-seq: @@ -157,80 +160,76 @@ return self; } static void -hmac_final(HMAC_CTX *ctx, unsigned char **buf, unsigned int *buf_len) +hmac_final(HMAC_CTX *ctx, unsigned char *buf, unsigned int *buf_len) { - HMAC_CTX final; + HMAC_CTX *final; - HMAC_CTX_copy(&final, ctx); - if (!(*buf = OPENSSL_malloc(HMAC_size(&final)))) { - HMAC_CTX_cleanup(&final); - OSSL_Debug("Allocating %d mem", HMAC_size(&final)); - ossl_raise(eHMACError, "Cannot allocate memory for hmac"); + final = HMAC_CTX_new(); + if (!final) + ossl_raise(eHMACError, "HMAC_CTX_new"); + + if (!HMAC_CTX_copy(final, ctx)) { + HMAC_CTX_free(final); + ossl_raise(eHMACError, "HMAC_CTX_copy"); } - HMAC_Final(&final, *buf, buf_len); - HMAC_CTX_cleanup(&final); + + HMAC_Final(final, buf, buf_len); + HMAC_CTX_free(final); } /* * call-seq: * hmac.digest -> string * * Returns the authentication code an instance represents as a binary string. * * === Example - * - * instance = OpenSSL::HMAC.new('key', OpenSSL::Digest.new('sha1')) - * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f - * instance.digest - * #=> "\xF4+\xB0\xEE\xB0\x18\xEB\xBDE\x97\xAEr\x13q\x1E\xC6\a`\x84?" - * + * instance = OpenSSL::HMAC.new('key', OpenSSL::Digest.new('sha1')) + * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f + * instance.digest + * #=> "\xF4+\xB0\xEE\xB0\x18\xEB\xBDE\x97\xAEr\x13q\x1E\xC6\a`\x84?" */ static VALUE ossl_hmac_digest(VALUE self) { HMAC_CTX *ctx; - unsigned char *buf; unsigned int buf_len; - VALUE digest; + VALUE ret; GetHMAC(self, ctx); - hmac_final(ctx, &buf, &buf_len); - digest = ossl_buf2str((char *)buf, buf_len); + ret = rb_str_new(NULL, EVP_MAX_MD_SIZE); + hmac_final(ctx, (unsigned char *)RSTRING_PTR(ret), &buf_len); + assert(buf_len <= EVP_MAX_MD_SIZE); + rb_str_set_len(ret, buf_len); - return digest; + return ret; } /* * call-seq: * hmac.hexdigest -> string * * Returns the authentication code an instance represents as a hex-encoded * string. - * */ static VALUE ossl_hmac_hexdigest(VALUE self) { HMAC_CTX *ctx; - unsigned char *buf; - char *hexbuf; + unsigned char buf[EVP_MAX_MD_SIZE]; unsigned int buf_len; - VALUE hexdigest; + VALUE ret; GetHMAC(self, ctx); - hmac_final(ctx, &buf, &buf_len); - if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * (int)buf_len) { - OPENSSL_free(buf); - ossl_raise(eHMACError, "Memory alloc error"); - } - OPENSSL_free(buf); - hexdigest = ossl_buf2str(hexbuf, 2 * buf_len); + hmac_final(ctx, buf, &buf_len); + ret = rb_str_new(NULL, buf_len * 2); + ossl_bin2hex(buf, RSTRING_PTR(ret), buf_len); - return hexdigest; + return ret; } /* * call-seq: * hmac.reset -> self @@ -254,11 +253,11 @@ ossl_hmac_reset(VALUE self) { HMAC_CTX *ctx; GetHMAC(self, ctx); - HMAC_Init(ctx, NULL, 0, NULL); + HMAC_Init_ex(ctx, NULL, 0, NULL, NULL); return self; } /* @@ -310,38 +309,66 @@ * */ static VALUE ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data) { - unsigned char *buf; - char *hexbuf; + unsigned char buf[EVP_MAX_MD_SIZE]; unsigned int buf_len; - VALUE hexdigest; + VALUE ret; StringValue(key); StringValue(data); - buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LENINT(key), - (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len); - if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * (int)buf_len) { - ossl_raise(eHMACError, "Cannot convert buf to hexbuf"); - } - hexdigest = ossl_buf2str(hexbuf, 2 * buf_len); + if (!HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LENINT(key), + (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data), + buf, &buf_len)) + ossl_raise(eHMACError, "HMAC"); - return hexdigest; + ret = rb_str_new(NULL, buf_len * 2); + ossl_bin2hex(buf, RSTRING_PTR(ret), buf_len); + + return ret; } /* * INIT */ void Init_ossl_hmac(void) { #if 0 - /* :nodoc: */ - mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */ + mOSSL = rb_define_module("OpenSSL"); + eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); #endif + /* + * Document-class: OpenSSL::HMAC + * + * OpenSSL::HMAC allows computing Hash-based Message Authentication Code + * (HMAC). It is a type of message authentication code (MAC) involving a + * hash function in combination with a key. HMAC can be used to verify the + * integrity of a message as well as the authenticity. + * + * OpenSSL::HMAC has a similar interface to OpenSSL::Digest. + * + * === HMAC-SHA256 using one-shot interface + * + * key = "key" + * data = "message-to-be-authenticated" + * mac = OpenSSL::HMAC.hexdigest("SHA256", key, data) + * #=> "cddb0db23f469c8bf072b21fd837149bd6ace9ab771cceef14c9e517cc93282e" + * + * === HMAC-SHA256 using incremental interface + * + * data1 = File.read("file1") + * data2 = File.read("file2") + * key = "key" + * digest = OpenSSL::Digest::SHA256.new + * hmac = OpenSSL::HMAC.new(key, digest) + * hmac << data1 + * hmac << data2 + * mac = hmac.digest + */ eHMACError = rb_define_class_under(mOSSL, "HMACError", eOSSLError); cHMAC = rb_define_class_under(mOSSL, "HMAC", rb_cObject); rb_define_alloc_func(cHMAC, ossl_hmac_alloc);