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