|
Ruby 1.9.2p290(2011-07-09revision32553)
|
00001 /* 00002 * $Id: ossl_digest.c 27440 2010-04-22 08:21:01Z 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 00040 if (TYPE(obj) == T_STRING) { 00041 const char *name = StringValueCStr(obj); 00042 00043 md = EVP_get_digestbyname(name); 00044 if (!md) 00045 ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%s).", name); 00046 } else { 00047 EVP_MD_CTX *ctx; 00048 00049 SafeGetDigest(obj, ctx); 00050 00051 md = EVP_MD_CTX_md(ctx); 00052 } 00053 00054 return md; 00055 } 00056 00057 VALUE 00058 ossl_digest_new(const EVP_MD *md) 00059 { 00060 VALUE ret; 00061 EVP_MD_CTX *ctx; 00062 00063 ret = ossl_digest_alloc(cDigest); 00064 GetDigest(ret, ctx); 00065 EVP_DigestInit_ex(ctx, md, NULL); 00066 00067 return ret; 00068 } 00069 00070 /* 00071 * Private 00072 */ 00073 static VALUE 00074 ossl_digest_alloc(VALUE klass) 00075 { 00076 EVP_MD_CTX *ctx; 00077 VALUE obj; 00078 00079 ctx = EVP_MD_CTX_create(); 00080 if (ctx == NULL) 00081 ossl_raise(rb_eRuntimeError, "EVP_MD_CTX_create() failed"); 00082 obj = Data_Wrap_Struct(klass, 0, EVP_MD_CTX_destroy, ctx); 00083 00084 return obj; 00085 } 00086 00087 VALUE ossl_digest_update(VALUE, VALUE); 00088 00089 /* 00090 * call-seq: 00091 * Digest.new(string) -> digest 00092 * 00093 */ 00094 static VALUE 00095 ossl_digest_initialize(int argc, VALUE *argv, VALUE self) 00096 { 00097 EVP_MD_CTX *ctx; 00098 const EVP_MD *md; 00099 VALUE type, data; 00100 00101 rb_scan_args(argc, argv, "11", &type, &data); 00102 md = GetDigestPtr(type); 00103 if (!NIL_P(data)) StringValue(data); 00104 00105 GetDigest(self, ctx); 00106 EVP_DigestInit_ex(ctx, md, NULL); 00107 00108 if (!NIL_P(data)) return ossl_digest_update(self, data); 00109 return self; 00110 } 00111 00112 static VALUE 00113 ossl_digest_copy(VALUE self, VALUE other) 00114 { 00115 EVP_MD_CTX *ctx1, *ctx2; 00116 00117 rb_check_frozen(self); 00118 if (self == other) return self; 00119 00120 GetDigest(self, ctx1); 00121 SafeGetDigest(other, ctx2); 00122 00123 if (!EVP_MD_CTX_copy(ctx1, ctx2)) { 00124 ossl_raise(eDigestError, NULL); 00125 } 00126 return self; 00127 } 00128 00129 /* 00130 * call-seq: 00131 * digest.reset -> self 00132 * 00133 */ 00134 static VALUE 00135 ossl_digest_reset(VALUE self) 00136 { 00137 EVP_MD_CTX *ctx; 00138 00139 GetDigest(self, ctx); 00140 EVP_DigestInit_ex(ctx, EVP_MD_CTX_md(ctx), NULL); 00141 00142 return self; 00143 } 00144 00145 /* 00146 * call-seq: 00147 * digest.update(string) -> aString 00148 * 00149 */ 00150 VALUE 00151 ossl_digest_update(VALUE self, VALUE data) 00152 { 00153 EVP_MD_CTX *ctx; 00154 00155 StringValue(data); 00156 GetDigest(self, ctx); 00157 EVP_DigestUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)); 00158 00159 return self; 00160 } 00161 00162 /* 00163 * call-seq: 00164 * digest.finish -> aString 00165 * 00166 */ 00167 static VALUE 00168 ossl_digest_finish(int argc, VALUE *argv, VALUE self) 00169 { 00170 EVP_MD_CTX *ctx; 00171 VALUE str; 00172 00173 rb_scan_args(argc, argv, "01", &str); 00174 00175 GetDigest(self, ctx); 00176 00177 if (NIL_P(str)) { 00178 str = rb_str_new(NULL, EVP_MD_CTX_size(ctx)); 00179 } else { 00180 StringValue(str); 00181 rb_str_resize(str, EVP_MD_CTX_size(ctx)); 00182 } 00183 00184 EVP_DigestFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), NULL); 00185 00186 return str; 00187 } 00188 00189 /* 00190 * call-seq: 00191 * digest.name -> string 00192 * 00193 */ 00194 static VALUE 00195 ossl_digest_name(VALUE self) 00196 { 00197 EVP_MD_CTX *ctx; 00198 00199 GetDigest(self, ctx); 00200 00201 return rb_str_new2(EVP_MD_name(EVP_MD_CTX_md(ctx))); 00202 } 00203 00204 /* 00205 * call-seq: 00206 * digest.digest_size -> integer 00207 * 00208 * Returns the output size of the digest. 00209 */ 00210 static VALUE 00211 ossl_digest_size(VALUE self) 00212 { 00213 EVP_MD_CTX *ctx; 00214 00215 GetDigest(self, ctx); 00216 00217 return INT2NUM(EVP_MD_CTX_size(ctx)); 00218 } 00219 00220 static VALUE 00221 ossl_digest_block_length(VALUE self) 00222 { 00223 EVP_MD_CTX *ctx; 00224 00225 GetDigest(self, ctx); 00226 00227 return INT2NUM(EVP_MD_CTX_block_size(ctx)); 00228 } 00229 00230 /* 00231 * INIT 00232 */ 00233 void 00234 Init_ossl_digest() 00235 { 00236 rb_require("digest"); 00237 00238 #if 0 /* let rdoc know about mOSSL */ 00239 mOSSL = rb_define_module("OpenSSL"); 00240 #endif 00241 00242 cDigest = rb_define_class_under(mOSSL, "Digest", rb_path2class("Digest::Class")); 00243 eDigestError = rb_define_class_under(cDigest, "DigestError", eOSSLError); 00244 00245 rb_define_alloc_func(cDigest, ossl_digest_alloc); 00246 00247 rb_define_method(cDigest, "initialize", ossl_digest_initialize, -1); 00248 rb_define_copy_func(cDigest, ossl_digest_copy); 00249 rb_define_method(cDigest, "reset", ossl_digest_reset, 0); 00250 rb_define_method(cDigest, "update", ossl_digest_update, 1); 00251 rb_define_alias(cDigest, "<<", "update"); 00252 rb_define_private_method(cDigest, "finish", ossl_digest_finish, -1); 00253 rb_define_method(cDigest, "digest_length", ossl_digest_size, 0); 00254 rb_define_method(cDigest, "block_length", ossl_digest_block_length, 0); 00255 00256 rb_define_method(cDigest, "name", ossl_digest_name, 0); 00257 } 00258
1.7.3