1/* 2 * $Id: ossl_hmac.c 32609 2011-07-22 04:11:38Z emboss $ 3 * 'OpenSSL for Ruby' project 4 * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> 5 * All rights reserved. 6 */ 7/* 8 * This program is licenced under the same licence as Ruby. 9 * (See the file 'LICENCE'.) 10 */ 11#if !defined(OPENSSL_NO_HMAC) 12 13#include "ossl.h" 14 15#define MakeHMAC(obj, klass, ctx) \ 16 (obj) = Data_Make_Struct((klass), HMAC_CTX, 0, ossl_hmac_free, (ctx)) 17#define GetHMAC(obj, ctx) do { \ 18 Data_Get_Struct((obj), HMAC_CTX, (ctx)); \ 19 if (!(ctx)) { \ 20 ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \ 21 } \ 22} while (0) 23#define SafeGetHMAC(obj, ctx) do { \ 24 OSSL_Check_Kind((obj), cHMAC); \ 25 GetHMAC((obj), (ctx)); \ 26} while (0) 27 28/* 29 * Classes 30 */ 31VALUE cHMAC; 32VALUE eHMACError; 33 34/* 35 * Public 36 */ 37 38/* 39 * Private 40 */ 41static void 42ossl_hmac_free(HMAC_CTX *ctx) 43{ 44 HMAC_CTX_cleanup(ctx); 45 ruby_xfree(ctx); 46} 47 48static VALUE 49ossl_hmac_alloc(VALUE klass) 50{ 51 HMAC_CTX *ctx; 52 VALUE obj; 53 54 MakeHMAC(obj, klass, ctx); 55 HMAC_CTX_init(ctx); 56 57 return obj; 58} 59 60 61/* 62 * call-seq: 63 * HMAC.new(key, digest) -> hmac 64 * 65 */ 66static VALUE 67ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest) 68{ 69 HMAC_CTX *ctx; 70 71 StringValue(key); 72 GetHMAC(self, ctx); 73 HMAC_Init(ctx, RSTRING_PTR(key), RSTRING_LENINT(key), 74 GetDigestPtr(digest)); 75 76 return self; 77} 78 79static VALUE 80ossl_hmac_copy(VALUE self, VALUE other) 81{ 82 HMAC_CTX *ctx1, *ctx2; 83 84 rb_check_frozen(self); 85 if (self == other) return self; 86 87 GetHMAC(self, ctx1); 88 SafeGetHMAC(other, ctx2); 89 90 HMAC_CTX_copy(ctx1, ctx2); 91 return self; 92} 93 94/* 95 * call-seq: 96 * hmac.update(string) -> self 97 * 98 */ 99static VALUE 100ossl_hmac_update(VALUE self, VALUE data) 101{ 102 HMAC_CTX *ctx; 103 104 StringValue(data); 105 GetHMAC(self, ctx); 106 HMAC_Update(ctx, (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data)); 107 108 return self; 109} 110 111static void 112hmac_final(HMAC_CTX *ctx, unsigned char **buf, unsigned int *buf_len) 113{ 114 HMAC_CTX final; 115 116 HMAC_CTX_copy(&final, ctx); 117 if (!(*buf = OPENSSL_malloc(HMAC_size(&final)))) { 118 HMAC_CTX_cleanup(&final); 119 OSSL_Debug("Allocating %d mem", HMAC_size(&final)); 120 ossl_raise(eHMACError, "Cannot allocate memory for hmac"); 121 } 122 HMAC_Final(&final, *buf, buf_len); 123 HMAC_CTX_cleanup(&final); 124} 125 126/* 127 * call-seq: 128 * hmac.digest -> aString 129 * 130 */ 131static VALUE 132ossl_hmac_digest(VALUE self) 133{ 134 HMAC_CTX *ctx; 135 unsigned char *buf; 136 unsigned int buf_len; 137 VALUE digest; 138 139 GetHMAC(self, ctx); 140 hmac_final(ctx, &buf, &buf_len); 141 digest = ossl_buf2str((char *)buf, buf_len); 142 143 return digest; 144} 145 146/* 147 * call-seq: 148 * hmac.hexdigest -> aString 149 * 150 */ 151static VALUE 152ossl_hmac_hexdigest(VALUE self) 153{ 154 HMAC_CTX *ctx; 155 unsigned char *buf; 156 char *hexbuf; 157 unsigned int buf_len; 158 VALUE hexdigest; 159 160 GetHMAC(self, ctx); 161 hmac_final(ctx, &buf, &buf_len); 162 if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * (int)buf_len) { 163 OPENSSL_free(buf); 164 ossl_raise(eHMACError, "Memory alloc error"); 165 } 166 OPENSSL_free(buf); 167 hexdigest = ossl_buf2str(hexbuf, 2 * buf_len); 168 169 return hexdigest; 170} 171 172/* 173 * call-seq: 174 * hmac.reset -> self 175 * 176 */ 177static VALUE 178ossl_hmac_reset(VALUE self) 179{ 180 HMAC_CTX *ctx; 181 182 GetHMAC(self, ctx); 183 HMAC_Init(ctx, NULL, 0, NULL); 184 185 return self; 186} 187 188/* 189 * call-seq: 190 * HMAC.digest(digest, key, data) -> aString 191 * 192 */ 193static VALUE 194ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data) 195{ 196 unsigned char *buf; 197 unsigned int buf_len; 198 199 StringValue(key); 200 StringValue(data); 201 buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LENINT(key), 202 (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len); 203 204 return rb_str_new((const char *)buf, buf_len); 205} 206 207/* 208 * call-seq: 209 * HMAC.digest(digest, key, data) -> aString 210 * 211 */ 212static VALUE 213ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data) 214{ 215 unsigned char *buf; 216 char *hexbuf; 217 unsigned int buf_len; 218 VALUE hexdigest; 219 220 StringValue(key); 221 StringValue(data); 222 223 buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LENINT(key), 224 (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len); 225 if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * (int)buf_len) { 226 ossl_raise(eHMACError, "Cannot convert buf to hexbuf"); 227 } 228 hexdigest = ossl_buf2str(hexbuf, 2 * buf_len); 229 230 return hexdigest; 231} 232 233/* 234 * INIT 235 */ 236void 237Init_ossl_hmac() 238{ 239#if 0 240 mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */ 241#endif 242 243 eHMACError = rb_define_class_under(mOSSL, "HMACError", eOSSLError); 244 245 cHMAC = rb_define_class_under(mOSSL, "HMAC", rb_cObject); 246 247 rb_define_alloc_func(cHMAC, ossl_hmac_alloc); 248 rb_define_singleton_method(cHMAC, "digest", ossl_hmac_s_digest, 3); 249 rb_define_singleton_method(cHMAC, "hexdigest", ossl_hmac_s_hexdigest, 3); 250 251 rb_define_method(cHMAC, "initialize", ossl_hmac_initialize, 2); 252 rb_define_copy_func(cHMAC, ossl_hmac_copy); 253 254 rb_define_method(cHMAC, "reset", ossl_hmac_reset, 0); 255 rb_define_method(cHMAC, "update", ossl_hmac_update, 1); 256 rb_define_alias(cHMAC, "<<", "update"); 257 rb_define_method(cHMAC, "digest", ossl_hmac_digest, 0); 258 rb_define_method(cHMAC, "hexdigest", ossl_hmac_hexdigest, 0); 259 rb_define_alias(cHMAC, "inspect", "hexdigest"); 260 rb_define_alias(cHMAC, "to_s", "hexdigest"); 261} 262 263#else /* NO_HMAC */ 264# warning >>> OpenSSL is compiled without HMAC support <<< 265void 266Init_ossl_hmac() 267{ 268 rb_warning("HMAC will NOT be avaible: OpenSSL is compiled without HMAC."); 269} 270#endif /* NO_HMAC */ 271