* io.c (rb_open_file): encoding in mode string was ignored if perm is
[ruby-svn.git] / ext / openssl / ossl_digest.c
blobecd52fec9c639383a2ac54b3b78067a6c8d49e9e
1 /*
2 * $Id$
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'.)
11 #include "ossl.h"
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)
25 * Classes
27 VALUE cDigest;
28 VALUE eDigestError;
30 static VALUE ossl_digest_alloc(VALUE klass);
33 * Public
35 const EVP_MD *
36 GetDigestPtr(VALUE obj)
38 const EVP_MD *md;
40 if (TYPE(obj) == T_STRING) {
41 const char *name = STR2CSTR(obj);
43 md = EVP_get_digestbyname(name);
44 if (!md)
45 ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%s).", name);
46 } else {
47 EVP_MD_CTX *ctx;
49 SafeGetDigest(obj, ctx);
51 md = EVP_MD_CTX_md(ctx);
54 return md;
57 VALUE
58 ossl_digest_new(const EVP_MD *md)
60 VALUE ret;
61 EVP_MD_CTX *ctx;
63 ret = ossl_digest_alloc(cDigest);
64 GetDigest(ret, ctx);
65 EVP_DigestInit_ex(ctx, md, NULL);
67 return ret;
71 * Private
73 static VALUE
74 ossl_digest_alloc(VALUE klass)
76 EVP_MD_CTX *ctx;
77 VALUE obj;
79 ctx = EVP_MD_CTX_create();
80 if (ctx == NULL)
81 ossl_raise(rb_eRuntimeError, "EVP_MD_CTX_create() failed");
82 obj = Data_Wrap_Struct(klass, 0, EVP_MD_CTX_destroy, ctx);
84 return obj;
87 VALUE ossl_digest_update(VALUE, VALUE);
90 * call-seq:
91 * Digest.new(string) -> digest
94 static VALUE
95 ossl_digest_initialize(int argc, VALUE *argv, VALUE self)
97 EVP_MD_CTX *ctx;
98 const EVP_MD *md;
99 VALUE type, data;
101 rb_scan_args(argc, argv, "11", &type, &data);
102 md = GetDigestPtr(type);
103 if (!NIL_P(data)) StringValue(data);
105 GetDigest(self, ctx);
106 EVP_DigestInit_ex(ctx, md, NULL);
108 if (!NIL_P(data)) return ossl_digest_update(self, data);
109 return self;
112 static VALUE
113 ossl_digest_copy(VALUE self, VALUE other)
115 EVP_MD_CTX *ctx1, *ctx2;
117 rb_check_frozen(self);
118 if (self == other) return self;
120 GetDigest(self, ctx1);
121 SafeGetDigest(other, ctx2);
123 if (!EVP_MD_CTX_copy(ctx1, ctx2)) {
124 ossl_raise(eDigestError, NULL);
126 return self;
130 * call-seq:
131 * digest.reset -> self
134 static VALUE
135 ossl_digest_reset(VALUE self)
137 EVP_MD_CTX *ctx;
139 GetDigest(self, ctx);
140 EVP_DigestInit_ex(ctx, EVP_MD_CTX_md(ctx), NULL);
142 return self;
146 * call-seq:
147 * digest.update(string) -> aString
150 VALUE
151 ossl_digest_update(VALUE self, VALUE data)
153 EVP_MD_CTX *ctx;
155 StringValue(data);
156 GetDigest(self, ctx);
157 EVP_DigestUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data));
159 return self;
163 * call-seq:
164 * digest.finish -> aString
167 static VALUE
168 ossl_digest_finish(int argc, VALUE *argv, VALUE self)
170 EVP_MD_CTX *ctx;
171 VALUE str;
173 rb_scan_args(argc, argv, "01", &str);
175 GetDigest(self, ctx);
177 if (NIL_P(str)) {
178 str = rb_str_new(NULL, EVP_MD_CTX_size(ctx));
179 } else {
180 StringValue(str);
181 rb_str_resize(str, EVP_MD_CTX_size(ctx));
184 EVP_DigestFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), NULL);
186 return str;
190 * call-seq:
191 * digest.name -> string
194 static VALUE
195 ossl_digest_name(VALUE self)
197 EVP_MD_CTX *ctx;
199 GetDigest(self, ctx);
201 return rb_str_new2(EVP_MD_name(EVP_MD_CTX_md(ctx)));
205 * call-seq:
206 * digest.digest_size -> integer
208 * Returns the output size of the digest.
210 static VALUE
211 ossl_digest_size(VALUE self)
213 EVP_MD_CTX *ctx;
215 GetDigest(self, ctx);
217 return INT2NUM(EVP_MD_CTX_size(ctx));
220 static VALUE
221 ossl_digest_block_length(VALUE self)
223 EVP_MD_CTX *ctx;
225 GetDigest(self, ctx);
227 return INT2NUM(EVP_MD_CTX_block_size(ctx));
231 * INIT
233 void
234 Init_ossl_digest()
236 rb_require("openssl");
237 rb_require("digest");
239 #if 0 /* let rdoc know about mOSSL */
240 mOSSL = rb_define_module("OpenSSL");
241 #endif
243 cDigest = rb_define_class_under(mOSSL, "Digest", rb_path2class("Digest::Class"));
244 eDigestError = rb_define_class_under(cDigest, "DigestError", eOSSLError);
246 rb_define_alloc_func(cDigest, ossl_digest_alloc);
248 rb_define_method(cDigest, "initialize", ossl_digest_initialize, -1);
249 rb_define_copy_func(cDigest, ossl_digest_copy);
250 rb_define_method(cDigest, "reset", ossl_digest_reset, 0);
251 rb_define_method(cDigest, "update", ossl_digest_update, 1);
252 rb_define_alias(cDigest, "<<", "update");
253 rb_define_private_method(cDigest, "finish", ossl_digest_finish, -1);
254 rb_define_method(cDigest, "digest_length", ossl_digest_size, 0);
255 rb_define_method(cDigest, "block_length", ossl_digest_block_length, 0);
257 rb_define_method(cDigest, "name", ossl_digest_name, 0);