Ruby  2.0.0p247(2013-06-27revision41674)
ext/openssl/ossl_hmac.c
Go to the documentation of this file.
00001 /*
00002  * $Id: ossl_hmac.c 32609 2011-07-22 04:11:38Z emboss $
00003  * 'OpenSSL for Ruby' project
00004  * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
00005  * All rights reserved.
00006  */
00007 /*
00008  * This program is licenced under the same licence as Ruby.
00009  * (See the file 'LICENCE'.)
00010  */
00011 #if !defined(OPENSSL_NO_HMAC)
00012 
00013 #include "ossl.h"
00014 
00015 #define MakeHMAC(obj, klass, ctx) \
00016     (obj) = Data_Make_Struct((klass), HMAC_CTX, 0, ossl_hmac_free, (ctx))
00017 #define GetHMAC(obj, ctx) do { \
00018     Data_Get_Struct((obj), HMAC_CTX, (ctx)); \
00019     if (!(ctx)) { \
00020         ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \
00021     } \
00022 } while (0)
00023 #define SafeGetHMAC(obj, ctx) do { \
00024     OSSL_Check_Kind((obj), cHMAC); \
00025     GetHMAC((obj), (ctx)); \
00026 } while (0)
00027 
00028 /*
00029  * Classes
00030  */
00031 VALUE cHMAC;
00032 VALUE eHMACError;
00033 
00034 /*
00035  * Public
00036  */
00037 
00038 /*
00039  * Private
00040  */
00041 static void
00042 ossl_hmac_free(HMAC_CTX *ctx)
00043 {
00044     HMAC_CTX_cleanup(ctx);
00045     ruby_xfree(ctx);
00046 }
00047 
00048 static VALUE
00049 ossl_hmac_alloc(VALUE klass)
00050 {
00051     HMAC_CTX *ctx;
00052     VALUE obj;
00053 
00054     MakeHMAC(obj, klass, ctx);
00055     HMAC_CTX_init(ctx);
00056 
00057     return obj;
00058 }
00059 
00060 
00061 /*
00062  *  call-seq:
00063  *     HMAC.new(key, digest) -> hmac
00064  *
00065  */
00066 static VALUE
00067 ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest)
00068 {
00069     HMAC_CTX *ctx;
00070 
00071     StringValue(key);
00072     GetHMAC(self, ctx);
00073     HMAC_Init(ctx, RSTRING_PTR(key), RSTRING_LENINT(key),
00074                  GetDigestPtr(digest));
00075 
00076     return self;
00077 }
00078 
00079 static VALUE
00080 ossl_hmac_copy(VALUE self, VALUE other)
00081 {
00082     HMAC_CTX *ctx1, *ctx2;
00083 
00084     rb_check_frozen(self);
00085     if (self == other) return self;
00086 
00087     GetHMAC(self, ctx1);
00088     SafeGetHMAC(other, ctx2);
00089 
00090     HMAC_CTX_copy(ctx1, ctx2);
00091     return self;
00092 }
00093 
00094 /*
00095  *  call-seq:
00096  *     hmac.update(string) -> self
00097  *
00098  */
00099 static VALUE
00100 ossl_hmac_update(VALUE self, VALUE data)
00101 {
00102     HMAC_CTX *ctx;
00103 
00104     StringValue(data);
00105     GetHMAC(self, ctx);
00106     HMAC_Update(ctx, (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data));
00107 
00108     return self;
00109 }
00110 
00111 static void
00112 hmac_final(HMAC_CTX *ctx, unsigned char **buf, unsigned int *buf_len)
00113 {
00114     HMAC_CTX final;
00115 
00116     HMAC_CTX_copy(&final, ctx);
00117     if (!(*buf = OPENSSL_malloc(HMAC_size(&final)))) {
00118         HMAC_CTX_cleanup(&final);
00119         OSSL_Debug("Allocating %d mem", HMAC_size(&final));
00120         ossl_raise(eHMACError, "Cannot allocate memory for hmac");
00121     }
00122     HMAC_Final(&final, *buf, buf_len);
00123     HMAC_CTX_cleanup(&final);
00124 }
00125 
00126 /*
00127  *  call-seq:
00128  *     hmac.digest -> aString
00129  *
00130  */
00131 static VALUE
00132 ossl_hmac_digest(VALUE self)
00133 {
00134     HMAC_CTX *ctx;
00135     unsigned char *buf;
00136     unsigned int buf_len;
00137     VALUE digest;
00138 
00139     GetHMAC(self, ctx);
00140     hmac_final(ctx, &buf, &buf_len);
00141     digest = ossl_buf2str((char *)buf, buf_len);
00142 
00143     return digest;
00144 }
00145 
00146 /*
00147  *  call-seq:
00148  *     hmac.hexdigest -> aString
00149  *
00150  */
00151 static VALUE
00152 ossl_hmac_hexdigest(VALUE self)
00153 {
00154     HMAC_CTX *ctx;
00155     unsigned char *buf;
00156     char *hexbuf;
00157     unsigned int buf_len;
00158     VALUE hexdigest;
00159 
00160     GetHMAC(self, ctx);
00161     hmac_final(ctx, &buf, &buf_len);
00162     if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * (int)buf_len) {
00163         OPENSSL_free(buf);
00164         ossl_raise(eHMACError, "Memory alloc error");
00165     }
00166     OPENSSL_free(buf);
00167     hexdigest = ossl_buf2str(hexbuf, 2 * buf_len);
00168 
00169     return hexdigest;
00170 }
00171 
00172 /*
00173  *  call-seq:
00174  *     hmac.reset -> self
00175  *
00176  */
00177 static VALUE
00178 ossl_hmac_reset(VALUE self)
00179 {
00180     HMAC_CTX *ctx;
00181 
00182     GetHMAC(self, ctx);
00183     HMAC_Init(ctx, NULL, 0, NULL);
00184 
00185     return self;
00186 }
00187 
00188 /*
00189  *  call-seq:
00190  *     HMAC.digest(digest, key, data) -> aString
00191  *
00192  */
00193 static VALUE
00194 ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data)
00195 {
00196     unsigned char *buf;
00197     unsigned int buf_len;
00198 
00199     StringValue(key);
00200     StringValue(data);
00201     buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LENINT(key),
00202                (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len);
00203 
00204     return rb_str_new((const char *)buf, buf_len);
00205 }
00206 
00207 /*
00208  *  call-seq:
00209  *     HMAC.digest(digest, key, data) -> aString
00210  *
00211  */
00212 static VALUE
00213 ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data)
00214 {
00215     unsigned char *buf;
00216     char *hexbuf;
00217     unsigned int buf_len;
00218     VALUE hexdigest;
00219 
00220     StringValue(key);
00221     StringValue(data);
00222 
00223     buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LENINT(key),
00224                (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len);
00225     if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * (int)buf_len) {
00226         ossl_raise(eHMACError, "Cannot convert buf to hexbuf");
00227     }
00228     hexdigest = ossl_buf2str(hexbuf, 2 * buf_len);
00229 
00230     return hexdigest;
00231 }
00232 
00233 /*
00234  * INIT
00235  */
00236 void
00237 Init_ossl_hmac()
00238 {
00239 #if 0
00240     mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
00241 #endif
00242 
00243     eHMACError = rb_define_class_under(mOSSL, "HMACError", eOSSLError);
00244 
00245     cHMAC = rb_define_class_under(mOSSL, "HMAC", rb_cObject);
00246 
00247     rb_define_alloc_func(cHMAC, ossl_hmac_alloc);
00248     rb_define_singleton_method(cHMAC, "digest", ossl_hmac_s_digest, 3);
00249     rb_define_singleton_method(cHMAC, "hexdigest", ossl_hmac_s_hexdigest, 3);
00250 
00251     rb_define_method(cHMAC, "initialize", ossl_hmac_initialize, 2);
00252     rb_define_copy_func(cHMAC, ossl_hmac_copy);
00253 
00254     rb_define_method(cHMAC, "reset", ossl_hmac_reset, 0);
00255     rb_define_method(cHMAC, "update", ossl_hmac_update, 1);
00256     rb_define_alias(cHMAC, "<<", "update");
00257     rb_define_method(cHMAC, "digest", ossl_hmac_digest, 0);
00258     rb_define_method(cHMAC, "hexdigest", ossl_hmac_hexdigest, 0);
00259     rb_define_alias(cHMAC, "inspect", "hexdigest");
00260     rb_define_alias(cHMAC, "to_s", "hexdigest");
00261 }
00262 
00263 #else /* NO_HMAC */
00264 #  warning >>> OpenSSL is compiled without HMAC support <<<
00265 void
00266 Init_ossl_hmac()
00267 {
00268     rb_warning("HMAC will NOT be avaible: OpenSSL is compiled without HMAC.");
00269 }
00270 #endif /* NO_HMAC */
00271