Ruby
2.0.0p247(2013-06-27revision41674)
|
00001 /* 00002 * $Id: ossl_digest.c 33634 2011-11-04 07:19:23Z nobu $ 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 #include "ossl.h" 00012 00013 #define GetDigest(obj, ctx) do { \ 00014 Data_Get_Struct((obj), EVP_MD_CTX, (ctx)); \ 00015 if (!(ctx)) { \ 00016 ossl_raise(rb_eRuntimeError, "Digest CTX wasn't initialized!"); \ 00017 } \ 00018 } while (0) 00019 #define SafeGetDigest(obj, ctx) do { \ 00020 OSSL_Check_Kind((obj), cDigest); \ 00021 GetDigest((obj), (ctx)); \ 00022 } while (0) 00023 00024 /* 00025 * Classes 00026 */ 00027 VALUE cDigest; 00028 VALUE eDigestError; 00029 00030 static VALUE ossl_digest_alloc(VALUE klass); 00031 00032 /* 00033 * Public 00034 */ 00035 const EVP_MD * 00036 GetDigestPtr(VALUE obj) 00037 { 00038 const EVP_MD *md; 00039 ASN1_OBJECT *oid = NULL; 00040 00041 if (TYPE(obj) == T_STRING) { 00042 const char *name = StringValueCStr(obj); 00043 00044 md = EVP_get_digestbyname(name); 00045 if (!md) { 00046 oid = OBJ_txt2obj(name, 0); 00047 md = EVP_get_digestbyobj(oid); 00048 ASN1_OBJECT_free(oid); 00049 } 00050 if(!md) 00051 ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%s).", name); 00052 } else { 00053 EVP_MD_CTX *ctx; 00054 00055 SafeGetDigest(obj, ctx); 00056 00057 md = EVP_MD_CTX_md(ctx); 00058 } 00059 00060 return md; 00061 } 00062 00063 VALUE 00064 ossl_digest_new(const EVP_MD *md) 00065 { 00066 VALUE ret; 00067 EVP_MD_CTX *ctx; 00068 00069 ret = ossl_digest_alloc(cDigest); 00070 GetDigest(ret, ctx); 00071 if (EVP_DigestInit_ex(ctx, md, NULL) != 1) { 00072 ossl_raise(eDigestError, "Digest initialization failed."); 00073 } 00074 00075 return ret; 00076 } 00077 00078 /* 00079 * Private 00080 */ 00081 static VALUE 00082 ossl_digest_alloc(VALUE klass) 00083 { 00084 EVP_MD_CTX *ctx; 00085 VALUE obj; 00086 00087 ctx = EVP_MD_CTX_create(); 00088 if (ctx == NULL) 00089 ossl_raise(rb_eRuntimeError, "EVP_MD_CTX_create() failed"); 00090 obj = Data_Wrap_Struct(klass, 0, EVP_MD_CTX_destroy, ctx); 00091 00092 return obj; 00093 } 00094 00095 VALUE ossl_digest_update(VALUE, VALUE); 00096 00097 /* 00098 * call-seq: 00099 * Digest.new(string [, data]) -> Digest 00100 * 00101 * Creates a Digest instance based on +string+, which is either the ln 00102 * (long name) or sn (short name) of a supported digest algorithm. 00103 * If +data+ (a +String+) is given, it is used as the initial input to the 00104 * Digest instance, i.e. 00105 * digest = OpenSSL::Digest.new('sha256', 'digestdata') 00106 * is equal to 00107 * digest = OpenSSL::Digest.new('sha256') 00108 * digest.update('digestdata') 00109 * 00110 * === Example 00111 * digest = OpenSSL::Digest.new('sha1') 00112 * 00113 * 00114 */ 00115 static VALUE 00116 ossl_digest_initialize(int argc, VALUE *argv, VALUE self) 00117 { 00118 EVP_MD_CTX *ctx; 00119 const EVP_MD *md; 00120 VALUE type, data; 00121 00122 rb_scan_args(argc, argv, "11", &type, &data); 00123 md = GetDigestPtr(type); 00124 if (!NIL_P(data)) StringValue(data); 00125 00126 GetDigest(self, ctx); 00127 if (EVP_DigestInit_ex(ctx, md, NULL) != 1) { 00128 ossl_raise(eDigestError, "Digest initialization failed."); 00129 } 00130 00131 if (!NIL_P(data)) return ossl_digest_update(self, data); 00132 return self; 00133 } 00134 00135 static VALUE 00136 ossl_digest_copy(VALUE self, VALUE other) 00137 { 00138 EVP_MD_CTX *ctx1, *ctx2; 00139 00140 rb_check_frozen(self); 00141 if (self == other) return self; 00142 00143 GetDigest(self, ctx1); 00144 SafeGetDigest(other, ctx2); 00145 00146 if (!EVP_MD_CTX_copy(ctx1, ctx2)) { 00147 ossl_raise(eDigestError, NULL); 00148 } 00149 return self; 00150 } 00151 00152 /* 00153 * call-seq: 00154 * digest.reset -> self 00155 * 00156 * Resets the Digest in the sense that any Digest#update that has been 00157 * performed is abandoned and the Digest is set to its initial state again. 00158 * 00159 */ 00160 static VALUE 00161 ossl_digest_reset(VALUE self) 00162 { 00163 EVP_MD_CTX *ctx; 00164 00165 GetDigest(self, ctx); 00166 if (EVP_DigestInit_ex(ctx, EVP_MD_CTX_md(ctx), NULL) != 1) { 00167 ossl_raise(eDigestError, "Digest initialization failed."); 00168 } 00169 00170 return self; 00171 } 00172 00173 /* 00174 * call-seq: 00175 * digest.update(string) -> aString 00176 * 00177 * Not every message digest can be computed in one single pass. If a message 00178 * digest is to be computed from several subsequent sources, then each may 00179 * be passed individually to the Digest instance. 00180 * 00181 * === Example 00182 * digest = OpenSSL::Digest::SHA256.new 00183 * digest.update('First input') 00184 * digest << 'Second input' # equivalent to digest.update('Second input') 00185 * result = digest.digest 00186 * 00187 */ 00188 VALUE 00189 ossl_digest_update(VALUE self, VALUE data) 00190 { 00191 EVP_MD_CTX *ctx; 00192 00193 StringValue(data); 00194 GetDigest(self, ctx); 00195 EVP_DigestUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)); 00196 00197 return self; 00198 } 00199 00200 /* 00201 * call-seq: 00202 * digest.finish -> aString 00203 * 00204 */ 00205 static VALUE 00206 ossl_digest_finish(int argc, VALUE *argv, VALUE self) 00207 { 00208 EVP_MD_CTX *ctx; 00209 VALUE str; 00210 00211 rb_scan_args(argc, argv, "01", &str); 00212 00213 GetDigest(self, ctx); 00214 00215 if (NIL_P(str)) { 00216 str = rb_str_new(NULL, EVP_MD_CTX_size(ctx)); 00217 } else { 00218 StringValue(str); 00219 rb_str_resize(str, EVP_MD_CTX_size(ctx)); 00220 } 00221 00222 EVP_DigestFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), NULL); 00223 00224 return str; 00225 } 00226 00227 /* 00228 * call-seq: 00229 * digest.name -> string 00230 * 00231 * Returns the sn of this Digest instance. 00232 * 00233 * === Example 00234 * digest = OpenSSL::Digest::SHA512.new 00235 * puts digest.name # => SHA512 00236 * 00237 */ 00238 static VALUE 00239 ossl_digest_name(VALUE self) 00240 { 00241 EVP_MD_CTX *ctx; 00242 00243 GetDigest(self, ctx); 00244 00245 return rb_str_new2(EVP_MD_name(EVP_MD_CTX_md(ctx))); 00246 } 00247 00248 /* 00249 * call-seq: 00250 * digest.digest_length -> integer 00251 * 00252 * Returns the output size of the digest, i.e. the length in bytes of the 00253 * final message digest result. 00254 * 00255 * === Example 00256 * digest = OpenSSL::Digest::SHA1.new 00257 * puts digest.digest_length # => 20 00258 * 00259 */ 00260 static VALUE 00261 ossl_digest_size(VALUE self) 00262 { 00263 EVP_MD_CTX *ctx; 00264 00265 GetDigest(self, ctx); 00266 00267 return INT2NUM(EVP_MD_CTX_size(ctx)); 00268 } 00269 00270 /* 00271 * call-seq: 00272 * digest.block_length -> integer 00273 * 00274 * Returns the block length of the digest algorithm, i.e. the length in bytes 00275 * of an individual block. Most modern algorithms partition a message to be 00276 * digested into a sequence of fix-sized blocks that are processed 00277 * consecutively. 00278 * 00279 * === Example 00280 * digest = OpenSSL::Digest::SHA1.new 00281 * puts digest.block_length # => 64 00282 */ 00283 static VALUE 00284 ossl_digest_block_length(VALUE self) 00285 { 00286 EVP_MD_CTX *ctx; 00287 00288 GetDigest(self, ctx); 00289 00290 return INT2NUM(EVP_MD_CTX_block_size(ctx)); 00291 } 00292 00293 /* 00294 * INIT 00295 */ 00296 void 00297 Init_ossl_digest() 00298 { 00299 rb_require("digest"); 00300 00301 #if 0 00302 mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */ 00303 #endif 00304 00305 /* Document-class: OpenSSL::Digest 00306 * 00307 * OpenSSL::Digest allows you to compute message digests (sometimes 00308 * interchangeably called "hashes") of arbitrary data that are 00309 * cryptographically secure, i.e. a Digest implements a secure one-way 00310 * function. 00311 * 00312 * One-way functions offer some useful properties. E.g. given two 00313 * distinct inputs the probability that both yield the same output 00314 * is highly unlikely. Combined with the fact that every message digest 00315 * algorithm has a fixed-length output of just a few bytes, digests are 00316 * often used to create unique identifiers for arbitrary data. A common 00317 * example is the creation of a unique id for binary documents that are 00318 * stored in a database. 00319 * 00320 * Another useful characteristic of one-way functions (and thus the name) 00321 * is that given a digest there is no indication about the original 00322 * data that produced it, i.e. the only way to identify the original input 00323 * is to "brute-force" through every possible combination of inputs. 00324 * 00325 * These characteristics make one-way functions also ideal companions 00326 * for public key signature algorithms: instead of signing an entire 00327 * document, first a hash of the document is produced with a considerably 00328 * faster message digest algorithm and only the few bytes of its output 00329 * need to be signed using the slower public key algorithm. To validate 00330 * the integrity of a signed document, it suffices to re-compute the hash 00331 * and verify that it is equal to that in the signature. 00332 * 00333 * Among the supported message digest algorithms are: 00334 * * SHA, SHA1, SHA224, SHA256, SHA384 and SHA512 00335 * * MD2, MD4, MDC2 and MD5 00336 * * RIPEMD160 00337 * * DSS, DSS1 (Pseudo algorithms to be used for DSA signatures. DSS is 00338 * equal to SHA and DSS1 is equal to SHA1) 00339 * 00340 * For each of these algorithms, there is a sub-class of Digest that 00341 * can be instantiated as simply as e.g. 00342 * 00343 * digest = OpenSSL::Digest::SHA1.new 00344 * 00345 * === Mapping between Digest class and sn/ln 00346 * 00347 * The sn (short names) and ln (long names) are defined in 00348 * <openssl/object.h> and <openssl/obj_mac.h>. They are textual 00349 * representations of ASN.1 OBJECT IDENTIFIERs. Each supported digest 00350 * algorithm has an OBJECT IDENTIFIER associated to it and those again 00351 * have short/long names assigned to them. 00352 * E.g. the OBJECT IDENTIFIER for SHA-1 is 1.3.14.3.2.26 and its 00353 * sn is "SHA1" and its ln is "sha1". 00354 * ==== MD2 00355 * * sn: MD2 00356 * * ln: md2 00357 * ==== MD4 00358 * * sn: MD4 00359 * * ln: md4 00360 * ==== MD5 00361 * * sn: MD5 00362 * * ln: md5 00363 * ==== SHA 00364 * * sn: SHA 00365 * * ln: SHA 00366 * ==== SHA-1 00367 * * sn: SHA1 00368 * * ln: sha1 00369 * ==== SHA-224 00370 * * sn: SHA224 00371 * * ln: sha224 00372 * ==== SHA-256 00373 * * sn: SHA256 00374 * * ln: sha256 00375 * ==== SHA-384 00376 * * sn: SHA384 00377 * * ln: sha384 00378 * ==== SHA-512 00379 * * sn: SHA512 00380 * * ln: sha512 00381 * 00382 * "Breaking" a message digest algorithm means defying its one-way 00383 * function characteristics, i.e. producing a collision or finding a way 00384 * to get to the original data by means that are more efficient than 00385 * brute-forcing etc. Most of the supported digest algorithms can be 00386 * considered broken in this sense, even the very popular MD5 and SHA1 00387 * algorithms. Should security be your highest concern, then you should 00388 * probably rely on SHA224, SHA256, SHA384 or SHA512. 00389 * 00390 * === Hashing a file 00391 * 00392 * data = File.read('document') 00393 * sha256 = OpenSSL::Digest::SHA256.new 00394 * digest = sha256.digest(data) 00395 * 00396 * === Hashing several pieces of data at once 00397 * 00398 * data1 = File.read('file1') 00399 * data2 = File.read('file2') 00400 * data3 = File.read('file3') 00401 * sha256 = OpenSSL::Digest::SHA256.new 00402 * sha256 << data1 00403 * sha256 << data2 00404 * sha256 << data3 00405 * digest = sha256.digest 00406 * 00407 * === Reuse a Digest instance 00408 * 00409 * data1 = File.read('file1') 00410 * sha256 = OpenSSL::Digest::SHA256.new 00411 * digest1 = sha256.digest(data1) 00412 * 00413 * data2 = File.read('file2') 00414 * sha256.reset 00415 * digest2 = sha256.digest(data2) 00416 * 00417 */ 00418 cDigest = rb_define_class_under(mOSSL, "Digest", rb_path2class("Digest::Class")); 00419 /* Document-class: OpenSSL::Digest::DigestError 00420 * 00421 * Generic Exception class that is raised if an error occurs during a 00422 * Digest operation. 00423 */ 00424 eDigestError = rb_define_class_under(cDigest, "DigestError", eOSSLError); 00425 00426 rb_define_alloc_func(cDigest, ossl_digest_alloc); 00427 00428 rb_define_method(cDigest, "initialize", ossl_digest_initialize, -1); 00429 rb_define_copy_func(cDigest, ossl_digest_copy); 00430 rb_define_method(cDigest, "reset", ossl_digest_reset, 0); 00431 rb_define_method(cDigest, "update", ossl_digest_update, 1); 00432 rb_define_alias(cDigest, "<<", "update"); 00433 rb_define_private_method(cDigest, "finish", ossl_digest_finish, -1); 00434 rb_define_method(cDigest, "digest_length", ossl_digest_size, 0); 00435 rb_define_method(cDigest, "block_length", ossl_digest_block_length, 0); 00436 00437 rb_define_method(cDigest, "name", ossl_digest_name, 0); 00438 } 00439