Ruby  2.4.2p198(2017-09-14revision59899)
ossl_hmac.c
Go to the documentation of this file.
1 /*
2  * 'OpenSSL for Ruby' project
3  * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
4  * All rights reserved.
5  */
6 /*
7  * This program is licensed under the same licence as Ruby.
8  * (See the file 'LICENCE'.)
9  */
10 #if !defined(OPENSSL_NO_HMAC)
11 
12 #include "ossl.h"
13 
14 #define NewHMAC(klass) \
15  TypedData_Wrap_Struct((klass), &ossl_hmac_type, 0)
16 #define GetHMAC(obj, ctx) do { \
17  TypedData_Get_Struct((obj), HMAC_CTX, &ossl_hmac_type, (ctx)); \
18  if (!(ctx)) { \
19  ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \
20  } \
21 } while (0)
22 #define SafeGetHMAC(obj, ctx) do { \
23  OSSL_Check_Kind((obj), cHMAC); \
24  GetHMAC((obj), (ctx)); \
25 } while (0)
26 
27 /*
28  * Classes
29  */
32 
33 /*
34  * Public
35  */
36 
37 /*
38  * Private
39  */
40 static void
41 ossl_hmac_free(void *ctx)
42 {
43  HMAC_CTX_free(ctx);
44 }
45 
47  "OpenSSL/HMAC",
48  {
49  0, ossl_hmac_free,
50  },
52 };
53 
54 static VALUE
56 {
57  VALUE obj;
58  HMAC_CTX *ctx;
59 
60  obj = NewHMAC(klass);
61  ctx = HMAC_CTX_new();
62  if (!ctx)
64  RTYPEDDATA_DATA(obj) = ctx;
65 
66  return obj;
67 }
68 
69 
70 /*
71  * call-seq:
72  * HMAC.new(key, digest) -> hmac
73  *
74  * Returns an instance of OpenSSL::HMAC set with the key and digest
75  * algorithm to be used. The instance represents the initial state of
76  * the message authentication code before any data has been processed.
77  * To process data with it, use the instance method #update with your
78  * data as an argument.
79  *
80  * === Example
81  *
82  * key = 'key'
83  * digest = OpenSSL::Digest.new('sha1')
84  * instance = OpenSSL::HMAC.new(key, digest)
85  * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
86  * instance.class
87  * #=> OpenSSL::HMAC
88  *
89  * === A note about comparisons
90  *
91  * Two instances won't be equal when they're compared, even if they have the
92  * same value. Use #to_s or #hexdigest to return the authentication code that
93  * the instance represents. For example:
94  *
95  * other_instance = OpenSSL::HMAC.new('key', OpenSSL::Digest.new('sha1'))
96  * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
97  * instance
98  * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
99  * instance == other_instance
100  * #=> false
101  * instance.to_s == other_instance.to_s
102  * #=> true
103  *
104  */
105 static VALUE
107 {
108  HMAC_CTX *ctx;
109 
110  StringValue(key);
111  GetHMAC(self, ctx);
112  HMAC_Init_ex(ctx, RSTRING_PTR(key), RSTRING_LENINT(key),
113  GetDigestPtr(digest), NULL);
114 
115  return self;
116 }
117 
118 static VALUE
120 {
121  HMAC_CTX *ctx1, *ctx2;
122 
123  rb_check_frozen(self);
124  if (self == other) return self;
125 
126  GetHMAC(self, ctx1);
127  SafeGetHMAC(other, ctx2);
128 
129  if (!HMAC_CTX_copy(ctx1, ctx2))
130  ossl_raise(eHMACError, "HMAC_CTX_copy");
131  return self;
132 }
133 
134 /*
135  * call-seq:
136  * hmac.update(string) -> self
137  *
138  * Returns +self+ updated with the message to be authenticated.
139  * Can be called repeatedly with chunks of the message.
140  *
141  * === Example
142  *
143  * first_chunk = 'The quick brown fox jumps '
144  * second_chunk = 'over the lazy dog'
145  *
146  * instance.update(first_chunk)
147  * #=> 5b9a8038a65d571076d97fe783989e52278a492a
148  * instance.update(second_chunk)
149  * #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
150  *
151  */
152 static VALUE
154 {
155  HMAC_CTX *ctx;
156 
157  StringValue(data);
158  GetHMAC(self, ctx);
159  HMAC_Update(ctx, (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data));
160 
161  return self;
162 }
163 
164 static void
165 hmac_final(HMAC_CTX *ctx, unsigned char *buf, unsigned int *buf_len)
166 {
167  HMAC_CTX *final;
168 
169  final = HMAC_CTX_new();
170  if (!final)
171  ossl_raise(eHMACError, "HMAC_CTX_new");
172 
173  if (!HMAC_CTX_copy(final, ctx)) {
174  HMAC_CTX_free(final);
175  ossl_raise(eHMACError, "HMAC_CTX_copy");
176  }
177 
178  HMAC_Final(final, buf, buf_len);
179  HMAC_CTX_free(final);
180 }
181 
182 /*
183  * call-seq:
184  * hmac.digest -> string
185  *
186  * Returns the authentication code an instance represents as a binary string.
187  *
188  * === Example
189  * instance = OpenSSL::HMAC.new('key', OpenSSL::Digest.new('sha1'))
190  * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
191  * instance.digest
192  * #=> "\xF4+\xB0\xEE\xB0\x18\xEB\xBDE\x97\xAEr\x13q\x1E\xC6\a`\x84?"
193  */
194 static VALUE
196 {
197  HMAC_CTX *ctx;
198  unsigned int buf_len;
199  VALUE ret;
200 
201  GetHMAC(self, ctx);
202  ret = rb_str_new(NULL, EVP_MAX_MD_SIZE);
203  hmac_final(ctx, (unsigned char *)RSTRING_PTR(ret), &buf_len);
204  assert(buf_len <= EVP_MAX_MD_SIZE);
205  rb_str_set_len(ret, buf_len);
206 
207  return ret;
208 }
209 
210 /*
211  * call-seq:
212  * hmac.hexdigest -> string
213  *
214  * Returns the authentication code an instance represents as a hex-encoded
215  * string.
216  */
217 static VALUE
219 {
220  HMAC_CTX *ctx;
221  unsigned char buf[EVP_MAX_MD_SIZE];
222  unsigned int buf_len;
223  VALUE ret;
224 
225  GetHMAC(self, ctx);
226  hmac_final(ctx, buf, &buf_len);
227  ret = rb_str_new(NULL, buf_len * 2);
228  ossl_bin2hex(buf, RSTRING_PTR(ret), buf_len);
229 
230  return ret;
231 }
232 
233 /*
234  * call-seq:
235  * hmac.reset -> self
236  *
237  * Returns +self+ as it was when it was first initialized, with all processed
238  * data cleared from it.
239  *
240  * === Example
241  *
242  * data = "The quick brown fox jumps over the lazy dog"
243  * instance = OpenSSL::HMAC.new('key', OpenSSL::Digest.new('sha1'))
244  * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
245  *
246  * instance.update(data)
247  * #=> de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
248  * instance.reset
249  * #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
250  *
251  */
252 static VALUE
254 {
255  HMAC_CTX *ctx;
256 
257  GetHMAC(self, ctx);
258  HMAC_Init_ex(ctx, NULL, 0, NULL, NULL);
259 
260  return self;
261 }
262 
263 /*
264  * call-seq:
265  * HMAC.digest(digest, key, data) -> aString
266  *
267  * Returns the authentication code as a binary string. The +digest+ parameter
268  * must be an instance of OpenSSL::Digest.
269  *
270  * === Example
271  *
272  * key = 'key'
273  * data = 'The quick brown fox jumps over the lazy dog'
274  * digest = OpenSSL::Digest.new('sha1')
275  *
276  * hmac = OpenSSL::HMAC.digest(digest, key, data)
277  * #=> "\xDE|\x9B\x85\xB8\xB7\x8A\xA6\xBC\x8Az6\xF7\n\x90p\x1C\x9D\xB4\xD9"
278  *
279  */
280 static VALUE
282 {
283  unsigned char *buf;
284  unsigned int buf_len;
285 
286  StringValue(key);
287  StringValue(data);
288  buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LENINT(key),
289  (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len);
290 
291  return rb_str_new((const char *)buf, buf_len);
292 }
293 
294 /*
295  * call-seq:
296  * HMAC.hexdigest(digest, key, data) -> aString
297  *
298  * Returns the authentication code as a hex-encoded string. The +digest+
299  * parameter must be an instance of OpenSSL::Digest.
300  *
301  * === Example
302  *
303  * key = 'key'
304  * data = 'The quick brown fox jumps over the lazy dog'
305  * digest = OpenSSL::Digest.new('sha1')
306  *
307  * hmac = OpenSSL::HMAC.hexdigest(digest, key, data)
308  * #=> "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"
309  *
310  */
311 static VALUE
313 {
314  unsigned char buf[EVP_MAX_MD_SIZE];
315  unsigned int buf_len;
316  VALUE ret;
317 
318  StringValue(key);
319  StringValue(data);
320 
321  if (!HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LENINT(key),
322  (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data),
323  buf, &buf_len))
324  ossl_raise(eHMACError, "HMAC");
325 
326  ret = rb_str_new(NULL, buf_len * 2);
327  ossl_bin2hex(buf, RSTRING_PTR(ret), buf_len);
328 
329  return ret;
330 }
331 
332 /*
333  * INIT
334  */
335 void
337 {
338 #if 0
339  mOSSL = rb_define_module("OpenSSL");
341 #endif
342 
343  /*
344  * Document-class: OpenSSL::HMAC
345  *
346  * OpenSSL::HMAC allows computing Hash-based Message Authentication Code
347  * (HMAC). It is a type of message authentication code (MAC) involving a
348  * hash function in combination with a key. HMAC can be used to verify the
349  * integrity of a message as well as the authenticity.
350  *
351  * OpenSSL::HMAC has a similar interface to OpenSSL::Digest.
352  *
353  * === HMAC-SHA256 using one-shot interface
354  *
355  * key = "key"
356  * data = "message-to-be-authenticated"
357  * mac = OpenSSL::HMAC.hexdigest("SHA256", key, data)
358  * #=> "cddb0db23f469c8bf072b21fd837149bd6ace9ab771cceef14c9e517cc93282e"
359  *
360  * === HMAC-SHA256 using incremental interface
361  *
362  * data1 = File.read("file1")
363  * data2 = File.read("file2")
364  * key = "key"
365  * digest = OpenSSL::Digest::SHA256.new
366  * hmac = OpenSSL::HMAC.new(key, digest)
367  * hmac << data1
368  * hmac << data2
369  * mac = hmac.digest
370  */
372 
374 
378 
379  rb_define_method(cHMAC, "initialize", ossl_hmac_initialize, 2);
381 
382  rb_define_method(cHMAC, "reset", ossl_hmac_reset, 0);
383  rb_define_method(cHMAC, "update", ossl_hmac_update, 1);
384  rb_define_alias(cHMAC, "<<", "update");
385  rb_define_method(cHMAC, "digest", ossl_hmac_digest, 0);
386  rb_define_method(cHMAC, "hexdigest", ossl_hmac_hexdigest, 0);
387  rb_define_alias(cHMAC, "inspect", "hexdigest");
388  rb_define_alias(cHMAC, "to_s", "hexdigest");
389 }
390 
391 #else /* NO_HMAC */
392 # warning >>> OpenSSL is compiled without HMAC support <<<
393 void
394 Init_ossl_hmac(void)
395 {
396  rb_warning("HMAC is not available: OpenSSL is compiled without HMAC.");
397 }
398 #endif /* NO_HMAC */
VALUE rb_eStandardError
Definition: error.c:760
#define GetHMAC(obj, ctx)
Definition: ossl_hmac.c:16
VALUE mOSSL
Definition: ossl.c:213
#define RUBY_TYPED_FREE_IMMEDIATELY
Definition: ruby.h:1145
VALUE cHMAC
Definition: ossl_hmac.c:30
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1716
#define HMAC_CTX_new
static VALUE ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest)
Definition: ossl_hmac.c:106
void rb_str_set_len(VALUE, long)
Definition: string.c:2545
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:693
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
#define assert(x)
Definition: dlmalloc.c:1176
VALUE eHMACError
Definition: ossl_hmac.c:31
static void ossl_hmac_free(void *ctx)
Definition: ossl_hmac.c:41
#define NewHMAC(klass)
Definition: ossl_hmac.c:14
#define rb_define_copy_func(klass, func)
Definition: ruby_missing.h:13
static VALUE ossl_hmac_digest(VALUE self)
Definition: ossl_hmac.c:195
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1872
const EVP_MD * GetDigestPtr(VALUE obj)
Definition: ossl_digest.c:49
VALUE eOSSLError
Definition: ossl.c:218
void Init_ossl_hmac(void)
Definition: ossl_hmac.c:336
static VALUE ossl_hmac_alloc(VALUE klass)
Definition: ossl_hmac.c:55
#define HMAC_CTX_free
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition: class.c:1758
#define RSTRING_LEN(str)
Definition: ruby.h:978
#define HMAC_CTX_copy
#define SafeGetHMAC(obj, ctx)
Definition: ossl_hmac.c:22
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4309
static VALUE ossl_hmac_hexdigest(VALUE self)
Definition: ossl_hmac.c:218
unsigned long VALUE
Definition: ruby.h:85
void ossl_bin2hex(unsigned char *in, char *out, size_t inlen)
Definition: ossl.c:115
static VALUE ossl_hmac_update(VALUE self, VALUE data)
Definition: ossl_hmac.c:153
#define RSTRING_PTR(str)
Definition: ruby.h:982
static VALUE ossl_hmac_copy(VALUE self, VALUE other)
Definition: ossl_hmac.c:119
static VALUE ossl_hmac_reset(VALUE self)
Definition: ossl_hmac.c:253
static void hmac_final(HMAC_CTX *ctx, unsigned char *buf, unsigned int *buf_len)
Definition: ossl_hmac.c:165
void ossl_raise(VALUE exc, const char *fmt,...)
Definition: ossl.c:278
static VALUE ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data)
Definition: ossl_hmac.c:281
#define RTYPEDDATA_DATA(v)
Definition: ruby.h:1117
void rb_warning(const char *fmt,...)
Definition: error.c:250
#define RSTRING_LENINT(str)
Definition: ruby.h:990
#define rb_check_frozen(obj)
Definition: intern.h:276
VALUE rb_define_module(const char *name)
Definition: class.c:768
#define NULL
Definition: _sdbm.c:102
static VALUE ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data)
Definition: ossl_hmac.c:312
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1515
static const rb_data_type_t ossl_hmac_type
Definition: ossl_hmac.c:46
#define StringValue(v)
Definition: ruby.h:569
VALUE rb_str_new(const char *, long)
Definition: string.c:736