00001
00002
00003
00004
00005
00006
00007
00008
00009
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
00026
00027 VALUE cDigest;
00028 VALUE eDigestError;
00029
00030 static VALUE ossl_digest_alloc(VALUE klass);
00031
00032
00033
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
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
00091
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
00131
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
00147
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
00164
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
00191
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
00206
00207
00208
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
00232
00233 void
00234 Init_ossl_digest()
00235 {
00236 rb_require("digest");
00237
00238 #if 0
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