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 #include "ossl.h"
11 
12 #define GetDigest(obj, ctx) do { \
13     TypedData_Get_Struct((obj), EVP_MD_CTX, &ossl_digest_type, (ctx)); \
14     if (!(ctx)) { \
15 	ossl_raise(rb_eRuntimeError, "Digest CTX wasn't initialized!"); \
16     } \
17 } while (0)
18 
19 /*
20  * Classes
21  */
22 VALUE cDigest;
23 VALUE eDigestError;
24 
25 static VALUE ossl_digest_alloc(VALUE klass);
26 
27 static void
ossl_digest_free(void * ctx)28 ossl_digest_free(void *ctx)
29 {
30     EVP_MD_CTX_destroy(ctx);
31 }
32 
33 static const rb_data_type_t ossl_digest_type = {
34     "OpenSSL/Digest",
35     {
36 	0, ossl_digest_free,
37     },
38     0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
39 };
40 
41 /*
42  * Public
43  */
44 const EVP_MD *
ossl_evp_get_digestbyname(VALUE obj)45 ossl_evp_get_digestbyname(VALUE obj)
46 {
47     const EVP_MD *md;
48     ASN1_OBJECT *oid = NULL;
49 
50     if (RB_TYPE_P(obj, T_STRING)) {
51     	const char *name = StringValueCStr(obj);
52 
53 	md = EVP_get_digestbyname(name);
54 	if (!md) {
55 	    oid = OBJ_txt2obj(name, 0);
56 	    md = EVP_get_digestbyobj(oid);
57 	    ASN1_OBJECT_free(oid);
58 	}
59 	if(!md)
60             ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%"PRIsVALUE").", obj);
61     } else {
62         EVP_MD_CTX *ctx;
63 
64         GetDigest(obj, ctx);
65 
66         md = EVP_MD_CTX_md(ctx);
67     }
68 
69     return md;
70 }
71 
72 VALUE
ossl_digest_new(const EVP_MD * md)73 ossl_digest_new(const EVP_MD *md)
74 {
75     VALUE ret;
76     EVP_MD_CTX *ctx;
77 
78     ret = ossl_digest_alloc(cDigest);
79     ctx = EVP_MD_CTX_new();
80     if (!ctx)
81 	ossl_raise(eDigestError, "EVP_MD_CTX_new");
82     RTYPEDDATA_DATA(ret) = ctx;
83 
84     if (!EVP_DigestInit_ex(ctx, md, NULL))
85 	ossl_raise(eDigestError, "Digest initialization failed");
86 
87     return ret;
88 }
89 
90 /*
91  * Private
92  */
93 static VALUE
ossl_digest_alloc(VALUE klass)94 ossl_digest_alloc(VALUE klass)
95 {
96     return TypedData_Wrap_Struct(klass, &ossl_digest_type, 0);
97 }
98 
99 VALUE ossl_digest_update(VALUE, VALUE);
100 
101 /*
102  *  call-seq:
103  *     Digest.new(string [, data]) -> Digest
104  *
105  * Creates a Digest instance based on _string_, which is either the ln
106  * (long name) or sn (short name) of a supported digest algorithm.
107  *
108  * If _data_ (a String) is given, it is used as the initial input to the
109  * Digest instance, i.e.
110  *
111  *   digest = OpenSSL::Digest.new('sha256', 'digestdata')
112  *
113  * is equivalent to
114  *
115  *   digest = OpenSSL::Digest.new('sha256')
116  *   digest.update('digestdata')
117  */
118 static VALUE
ossl_digest_initialize(int argc,VALUE * argv,VALUE self)119 ossl_digest_initialize(int argc, VALUE *argv, VALUE self)
120 {
121     EVP_MD_CTX *ctx;
122     const EVP_MD *md;
123     VALUE type, data;
124 
125     rb_scan_args(argc, argv, "11", &type, &data);
126     md = ossl_evp_get_digestbyname(type);
127     if (!NIL_P(data)) StringValue(data);
128 
129     TypedData_Get_Struct(self, EVP_MD_CTX, &ossl_digest_type, ctx);
130     if (!ctx) {
131 	RTYPEDDATA_DATA(self) = ctx = EVP_MD_CTX_new();
132 	if (!ctx)
133 	    ossl_raise(eDigestError, "EVP_MD_CTX_new");
134     }
135 
136     if (!EVP_DigestInit_ex(ctx, md, NULL))
137 	ossl_raise(eDigestError, "Digest initialization failed");
138 
139     if (!NIL_P(data)) return ossl_digest_update(self, data);
140     return self;
141 }
142 
143 static VALUE
ossl_digest_copy(VALUE self,VALUE other)144 ossl_digest_copy(VALUE self, VALUE other)
145 {
146     EVP_MD_CTX *ctx1, *ctx2;
147 
148     rb_check_frozen(self);
149     if (self == other) return self;
150 
151     TypedData_Get_Struct(self, EVP_MD_CTX, &ossl_digest_type, ctx1);
152     if (!ctx1) {
153 	RTYPEDDATA_DATA(self) = ctx1 = EVP_MD_CTX_new();
154 	if (!ctx1)
155 	    ossl_raise(eDigestError, "EVP_MD_CTX_new");
156     }
157     GetDigest(other, ctx2);
158 
159     if (!EVP_MD_CTX_copy(ctx1, ctx2)) {
160 	ossl_raise(eDigestError, NULL);
161     }
162     return self;
163 }
164 
165 /*
166  *  call-seq:
167  *     digest.reset -> self
168  *
169  * Resets the Digest in the sense that any Digest#update that has been
170  * performed is abandoned and the Digest is set to its initial state again.
171  *
172  */
173 static VALUE
ossl_digest_reset(VALUE self)174 ossl_digest_reset(VALUE self)
175 {
176     EVP_MD_CTX *ctx;
177 
178     GetDigest(self, ctx);
179     if (EVP_DigestInit_ex(ctx, EVP_MD_CTX_md(ctx), NULL) != 1) {
180 	ossl_raise(eDigestError, "Digest initialization failed.");
181     }
182 
183     return self;
184 }
185 
186 /*
187  *  call-seq:
188  *     digest.update(string) -> aString
189  *
190  * Not every message digest can be computed in one single pass. If a message
191  * digest is to be computed from several subsequent sources, then each may
192  * be passed individually to the Digest instance.
193  *
194  * === Example
195  *   digest = OpenSSL::Digest::SHA256.new
196  *   digest.update('First input')
197  *   digest << 'Second input' # equivalent to digest.update('Second input')
198  *   result = digest.digest
199  *
200  */
201 VALUE
ossl_digest_update(VALUE self,VALUE data)202 ossl_digest_update(VALUE self, VALUE data)
203 {
204     EVP_MD_CTX *ctx;
205 
206     StringValue(data);
207     GetDigest(self, ctx);
208 
209     if (!EVP_DigestUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)))
210 	ossl_raise(eDigestError, "EVP_DigestUpdate");
211 
212     return self;
213 }
214 
215 /*
216  *  call-seq:
217  *      digest.finish -> aString
218  *
219  */
220 static VALUE
ossl_digest_finish(int argc,VALUE * argv,VALUE self)221 ossl_digest_finish(int argc, VALUE *argv, VALUE self)
222 {
223     EVP_MD_CTX *ctx;
224     VALUE str;
225     int out_len;
226 
227     GetDigest(self, ctx);
228     rb_scan_args(argc, argv, "01", &str);
229     out_len = EVP_MD_CTX_size(ctx);
230 
231     if (NIL_P(str)) {
232         str = rb_str_new(NULL, out_len);
233     } else {
234         StringValue(str);
235         rb_str_resize(str, out_len);
236     }
237 
238     if (!EVP_DigestFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), NULL))
239 	ossl_raise(eDigestError, "EVP_DigestFinal_ex");
240 
241     return str;
242 }
243 
244 /*
245  *  call-seq:
246  *      digest.name -> string
247  *
248  * Returns the sn of this Digest algorithm.
249  *
250  * === Example
251  *   digest = OpenSSL::Digest::SHA512.new
252  *   puts digest.name # => SHA512
253  *
254  */
255 static VALUE
ossl_digest_name(VALUE self)256 ossl_digest_name(VALUE self)
257 {
258     EVP_MD_CTX *ctx;
259 
260     GetDigest(self, ctx);
261 
262     return rb_str_new2(EVP_MD_name(EVP_MD_CTX_md(ctx)));
263 }
264 
265 /*
266  *  call-seq:
267  *      digest.digest_length -> integer
268  *
269  * Returns the output size of the digest, i.e. the length in bytes of the
270  * final message digest result.
271  *
272  * === Example
273  *   digest = OpenSSL::Digest::SHA1.new
274  *   puts digest.digest_length # => 20
275  *
276  */
277 static VALUE
ossl_digest_size(VALUE self)278 ossl_digest_size(VALUE self)
279 {
280     EVP_MD_CTX *ctx;
281 
282     GetDigest(self, ctx);
283 
284     return INT2NUM(EVP_MD_CTX_size(ctx));
285 }
286 
287 /*
288  *  call-seq:
289  *      digest.block_length -> integer
290  *
291  * Returns the block length of the digest algorithm, i.e. the length in bytes
292  * of an individual block. Most modern algorithms partition a message to be
293  * digested into a sequence of fix-sized blocks that are processed
294  * consecutively.
295  *
296  * === Example
297  *   digest = OpenSSL::Digest::SHA1.new
298  *   puts digest.block_length # => 64
299  */
300 static VALUE
ossl_digest_block_length(VALUE self)301 ossl_digest_block_length(VALUE self)
302 {
303     EVP_MD_CTX *ctx;
304 
305     GetDigest(self, ctx);
306 
307     return INT2NUM(EVP_MD_CTX_block_size(ctx));
308 }
309 
310 /*
311  * INIT
312  */
313 void
Init_ossl_digest(void)314 Init_ossl_digest(void)
315 {
316     rb_require("digest");
317 
318 #if 0
319     mOSSL = rb_define_module("OpenSSL");
320     eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
321 #endif
322 
323     /* Document-class: OpenSSL::Digest
324      *
325      * OpenSSL::Digest allows you to compute message digests (sometimes
326      * interchangeably called "hashes") of arbitrary data that are
327      * cryptographically secure, i.e. a Digest implements a secure one-way
328      * function.
329      *
330      * One-way functions offer some useful properties. E.g. given two
331      * distinct inputs the probability that both yield the same output
332      * is highly unlikely. Combined with the fact that every message digest
333      * algorithm has a fixed-length output of just a few bytes, digests are
334      * often used to create unique identifiers for arbitrary data. A common
335      * example is the creation of a unique id for binary documents that are
336      * stored in a database.
337      *
338      * Another useful characteristic of one-way functions (and thus the name)
339      * is that given a digest there is no indication about the original
340      * data that produced it, i.e. the only way to identify the original input
341      * is to "brute-force" through every possible combination of inputs.
342      *
343      * These characteristics make one-way functions also ideal companions
344      * for public key signature algorithms: instead of signing an entire
345      * document, first a hash of the document is produced with a considerably
346      * faster message digest algorithm and only the few bytes of its output
347      * need to be signed using the slower public key algorithm. To validate
348      * the integrity of a signed document, it suffices to re-compute the hash
349      * and verify that it is equal to that in the signature.
350      *
351      * Among the supported message digest algorithms are:
352      * * SHA, SHA1, SHA224, SHA256, SHA384 and SHA512
353      * * MD2, MD4, MDC2 and MD5
354      * * RIPEMD160
355      * * DSS, DSS1 (Pseudo algorithms to be used for DSA signatures. DSS is
356      *   equal to SHA and DSS1 is equal to SHA1)
357      *
358      * For each of these algorithms, there is a sub-class of Digest that
359      * can be instantiated as simply as e.g.
360      *
361      *   digest = OpenSSL::Digest::SHA1.new
362      *
363      * === Mapping between Digest class and sn/ln
364      *
365      * The sn (short names) and ln (long names) are defined in
366      * <openssl/object.h> and <openssl/obj_mac.h>. They are textual
367      * representations of ASN.1 OBJECT IDENTIFIERs. Each supported digest
368      * algorithm has an OBJECT IDENTIFIER associated to it and those again
369      * have short/long names assigned to them.
370      * E.g. the OBJECT IDENTIFIER for SHA-1 is 1.3.14.3.2.26 and its
371      * sn is "SHA1" and its ln is "sha1".
372      * ==== MD2
373      * * sn: MD2
374      * * ln: md2
375      * ==== MD4
376      * * sn: MD4
377      * * ln: md4
378      * ==== MD5
379      * * sn: MD5
380      * * ln: md5
381      * ==== SHA
382      * * sn: SHA
383      * * ln: SHA
384      * ==== SHA-1
385      * * sn: SHA1
386      * * ln: sha1
387      * ==== SHA-224
388      * * sn: SHA224
389      * * ln: sha224
390      * ==== SHA-256
391      * * sn: SHA256
392      * * ln: sha256
393      * ==== SHA-384
394      * * sn: SHA384
395      * * ln: sha384
396      * ==== SHA-512
397      * * sn: SHA512
398      * * ln: sha512
399      *
400      * "Breaking" a message digest algorithm means defying its one-way
401      * function characteristics, i.e. producing a collision or finding a way
402      * to get to the original data by means that are more efficient than
403      * brute-forcing etc. Most of the supported digest algorithms can be
404      * considered broken in this sense, even the very popular MD5 and SHA1
405      * algorithms. Should security be your highest concern, then you should
406      * probably rely on SHA224, SHA256, SHA384 or SHA512.
407      *
408      * === Hashing a file
409      *
410      *   data = File.read('document')
411      *   sha256 = OpenSSL::Digest::SHA256.new
412      *   digest = sha256.digest(data)
413      *
414      * === Hashing several pieces of data at once
415      *
416      *   data1 = File.read('file1')
417      *   data2 = File.read('file2')
418      *   data3 = File.read('file3')
419      *   sha256 = OpenSSL::Digest::SHA256.new
420      *   sha256 << data1
421      *   sha256 << data2
422      *   sha256 << data3
423      *   digest = sha256.digest
424      *
425      * === Reuse a Digest instance
426      *
427      *   data1 = File.read('file1')
428      *   sha256 = OpenSSL::Digest::SHA256.new
429      *   digest1 = sha256.digest(data1)
430      *
431      *   data2 = File.read('file2')
432      *   sha256.reset
433      *   digest2 = sha256.digest(data2)
434      *
435      */
436     cDigest = rb_define_class_under(mOSSL, "Digest", rb_path2class("Digest::Class"));
437     /* Document-class: OpenSSL::Digest::DigestError
438      *
439      * Generic Exception class that is raised if an error occurs during a
440      * Digest operation.
441      */
442     eDigestError = rb_define_class_under(cDigest, "DigestError", eOSSLError);
443 
444     rb_define_alloc_func(cDigest, ossl_digest_alloc);
445 
446     rb_define_method(cDigest, "initialize", ossl_digest_initialize, -1);
447     rb_define_method(cDigest, "initialize_copy", ossl_digest_copy, 1);
448     rb_define_method(cDigest, "reset", ossl_digest_reset, 0);
449     rb_define_method(cDigest, "update", ossl_digest_update, 1);
450     rb_define_alias(cDigest, "<<", "update");
451     rb_define_private_method(cDigest, "finish", ossl_digest_finish, -1);
452     rb_define_method(cDigest, "digest_length", ossl_digest_size, 0);
453     rb_define_method(cDigest, "block_length", ossl_digest_block_length, 0);
454 
455     rb_define_method(cDigest, "name", ossl_digest_name, 0);
456 }
457