00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "ossl.h"
00012
00013 #define MakeCipher(obj, klass, ctx) \
00014 obj = Data_Make_Struct(klass, EVP_CIPHER_CTX, 0, ossl_cipher_free, ctx)
00015 #define GetCipher(obj, ctx) do { \
00016 Data_Get_Struct(obj, EVP_CIPHER_CTX, ctx); \
00017 if (!ctx) { \
00018 ossl_raise(rb_eRuntimeError, "Cipher not inititalized!"); \
00019 } \
00020 } while (0)
00021 #define SafeGetCipher(obj, ctx) do { \
00022 OSSL_Check_Kind(obj, cCipher); \
00023 GetCipher(obj, ctx); \
00024 } while (0)
00025
00026
00027
00028
00029 VALUE cCipher;
00030 VALUE eCipherError;
00031
00032 static VALUE ossl_cipher_alloc(VALUE klass);
00033
00034
00035
00036
00037 const EVP_CIPHER *
00038 GetCipherPtr(VALUE obj)
00039 {
00040 EVP_CIPHER_CTX *ctx;
00041
00042 SafeGetCipher(obj, ctx);
00043
00044 return EVP_CIPHER_CTX_cipher(ctx);
00045 }
00046
00047 VALUE
00048 ossl_cipher_new(const EVP_CIPHER *cipher)
00049 {
00050 VALUE ret;
00051 EVP_CIPHER_CTX *ctx;
00052
00053 ret = ossl_cipher_alloc(cCipher);
00054 GetCipher(ret, ctx);
00055 EVP_CIPHER_CTX_init(ctx);
00056 if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)
00057 ossl_raise(eCipherError, NULL);
00058
00059 return ret;
00060 }
00061
00062
00063
00064
00065 static void
00066 ossl_cipher_free(EVP_CIPHER_CTX *ctx)
00067 {
00068 if (ctx) {
00069 EVP_CIPHER_CTX_cleanup(ctx);
00070 ruby_xfree(ctx);
00071 }
00072 }
00073
00074 static VALUE
00075 ossl_cipher_alloc(VALUE klass)
00076 {
00077 EVP_CIPHER_CTX *ctx;
00078 VALUE obj;
00079
00080 MakeCipher(obj, klass, ctx);
00081 EVP_CIPHER_CTX_init(ctx);
00082
00083 return obj;
00084 }
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 static VALUE
00095 ossl_cipher_initialize(VALUE self, VALUE str)
00096 {
00097 EVP_CIPHER_CTX *ctx;
00098 const EVP_CIPHER *cipher;
00099 char *name;
00100
00101 name = StringValuePtr(str);
00102 GetCipher(self, ctx);
00103 if (!(cipher = EVP_get_cipherbyname(name))) {
00104 ossl_raise(rb_eRuntimeError, "unsupported cipher algorithm (%s)", name);
00105 }
00106 if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)
00107 ossl_raise(eCipherError, NULL);
00108
00109 return self;
00110 }
00111 static VALUE
00112 ossl_cipher_copy(VALUE self, VALUE other)
00113 {
00114 EVP_CIPHER_CTX *ctx1, *ctx2;
00115
00116 rb_check_frozen(self);
00117 if (self == other) return self;
00118
00119 GetCipher(self, ctx1);
00120 SafeGetCipher(other, ctx2);
00121 if (EVP_CIPHER_CTX_copy(ctx1, ctx2) != 1)
00122 ossl_raise(eCipherError, NULL);
00123
00124 return self;
00125 }
00126
00127 #ifdef HAVE_OBJ_NAME_DO_ALL_SORTED
00128 static void*
00129 add_cipher_name_to_ary(const OBJ_NAME *name, VALUE ary)
00130 {
00131 rb_ary_push(ary, rb_str_new2(name->name));
00132 return NULL;
00133 }
00134 #endif
00135
00136 #ifdef HAVE_OBJ_NAME_DO_ALL_SORTED
00137
00138
00139
00140
00141
00142
00143 static VALUE
00144 ossl_s_ciphers(VALUE self)
00145 {
00146 VALUE ary;
00147
00148 ary = rb_ary_new();
00149 OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH,
00150 (void(*)(const OBJ_NAME*,void*))add_cipher_name_to_ary,
00151 (void*)ary);
00152
00153 return ary;
00154 }
00155 #else
00156 #define ossl_s_ciphers rb_f_notimplement
00157 #endif
00158
00159
00160
00161
00162
00163
00164
00165 static VALUE
00166 ossl_cipher_reset(VALUE self)
00167 {
00168 EVP_CIPHER_CTX *ctx;
00169
00170 GetCipher(self, ctx);
00171 if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1) != 1)
00172 ossl_raise(eCipherError, NULL);
00173
00174 return self;
00175 }
00176
00177 static VALUE
00178 ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode)
00179 {
00180 EVP_CIPHER_CTX *ctx;
00181 unsigned char key[EVP_MAX_KEY_LENGTH], *p_key = NULL;
00182 unsigned char iv[EVP_MAX_IV_LENGTH], *p_iv = NULL;
00183 VALUE pass, init_v;
00184
00185 if(rb_scan_args(argc, argv, "02", &pass, &init_v) > 0){
00186
00187
00188
00189
00190
00191 const char *cname = rb_class2name(rb_obj_class(self));
00192 rb_warn("argumtents for %s#encrypt and %s#decrypt were deprecated; "
00193 "use %s#pkcs5_keyivgen to derive key and IV",
00194 cname, cname, cname);
00195 StringValue(pass);
00196 GetCipher(self, ctx);
00197 if (NIL_P(init_v)) memcpy(iv, "OpenSSL for Ruby rulez!", sizeof(iv));
00198 else{
00199 StringValue(init_v);
00200 if (EVP_MAX_IV_LENGTH > RSTRING_LEN(init_v)) {
00201 memset(iv, 0, EVP_MAX_IV_LENGTH);
00202 memcpy(iv, RSTRING_PTR(init_v), RSTRING_LEN(init_v));
00203 }
00204 else memcpy(iv, RSTRING_PTR(init_v), sizeof(iv));
00205 }
00206 EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), EVP_md5(), iv,
00207 (unsigned char *)RSTRING_PTR(pass), RSTRING_LEN(pass), 1, key, NULL);
00208 p_key = key;
00209 p_iv = iv;
00210 }
00211 else {
00212 GetCipher(self, ctx);
00213 }
00214 if (EVP_CipherInit_ex(ctx, NULL, NULL, p_key, p_iv, mode) != 1) {
00215 ossl_raise(eCipherError, NULL);
00216 }
00217
00218 return self;
00219 }
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 static VALUE
00231 ossl_cipher_encrypt(int argc, VALUE *argv, VALUE self)
00232 {
00233 return ossl_cipher_init(argc, argv, self, 1);
00234 }
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 static VALUE
00246 ossl_cipher_decrypt(int argc, VALUE *argv, VALUE self)
00247 {
00248 return ossl_cipher_init(argc, argv, self, 0);
00249 }
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269 static VALUE
00270 ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
00271 {
00272 EVP_CIPHER_CTX *ctx;
00273 const EVP_MD *digest;
00274 VALUE vpass, vsalt, viter, vdigest;
00275 unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH], *salt = NULL;
00276 int iter;
00277
00278 rb_scan_args(argc, argv, "13", &vpass, &vsalt, &viter, &vdigest);
00279 StringValue(vpass);
00280 if(!NIL_P(vsalt)){
00281 StringValue(vsalt);
00282 if(RSTRING_LEN(vsalt) != PKCS5_SALT_LEN)
00283 rb_raise(eCipherError, "salt must be an 8-octet string");
00284 salt = (unsigned char *)RSTRING_PTR(vsalt);
00285 }
00286 iter = NIL_P(viter) ? 2048 : NUM2INT(viter);
00287 digest = NIL_P(vdigest) ? EVP_md5() : GetDigestPtr(vdigest);
00288 GetCipher(self, ctx);
00289 EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), digest, salt,
00290 (unsigned char *)RSTRING_PTR(vpass), RSTRING_LEN(vpass), iter, key, iv);
00291 if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, -1) != 1)
00292 ossl_raise(eCipherError, NULL);
00293 OPENSSL_cleanse(key, sizeof key);
00294 OPENSSL_cleanse(iv, sizeof iv);
00295
00296 return Qnil;
00297 }
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308 static VALUE
00309 ossl_cipher_update(int argc, VALUE *argv, VALUE self)
00310 {
00311 EVP_CIPHER_CTX *ctx;
00312 unsigned char *in;
00313 int in_len, out_len;
00314 VALUE data, str;
00315
00316 rb_scan_args(argc, argv, "11", &data, &str);
00317
00318 StringValue(data);
00319 in = (unsigned char *)RSTRING_PTR(data);
00320 if ((in_len = RSTRING_LEN(data)) == 0)
00321 rb_raise(rb_eArgError, "data must not be empty");
00322 GetCipher(self, ctx);
00323 out_len = in_len+EVP_CIPHER_CTX_block_size(ctx);
00324
00325 if (NIL_P(str)) {
00326 str = rb_str_new(0, out_len);
00327 } else {
00328 StringValue(str);
00329 rb_str_resize(str, out_len);
00330 }
00331
00332 if (!EVP_CipherUpdate(ctx, (unsigned char *)RSTRING_PTR(str), &out_len, in, in_len))
00333 ossl_raise(eCipherError, NULL);
00334 assert(out_len < RSTRING_LEN(str));
00335 rb_str_set_len(str, out_len);
00336
00337 return str;
00338 }
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348 static VALUE
00349 ossl_cipher_final(VALUE self)
00350 {
00351 EVP_CIPHER_CTX *ctx;
00352 int out_len;
00353 VALUE str;
00354
00355 GetCipher(self, ctx);
00356 str = rb_str_new(0, EVP_CIPHER_CTX_block_size(ctx));
00357 if (!EVP_CipherFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), &out_len))
00358 ossl_raise(eCipherError, NULL);
00359 assert(out_len <= RSTRING_LEN(str));
00360 rb_str_set_len(str, out_len);
00361
00362 return str;
00363 }
00364
00365
00366
00367
00368
00369
00370
00371 static VALUE
00372 ossl_cipher_name(VALUE self)
00373 {
00374 EVP_CIPHER_CTX *ctx;
00375
00376 GetCipher(self, ctx);
00377
00378 return rb_str_new2(EVP_CIPHER_name(EVP_CIPHER_CTX_cipher(ctx)));
00379 }
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389 static VALUE
00390 ossl_cipher_set_key(VALUE self, VALUE key)
00391 {
00392 EVP_CIPHER_CTX *ctx;
00393
00394 StringValue(key);
00395 GetCipher(self, ctx);
00396
00397 if (RSTRING_LEN(key) < EVP_CIPHER_CTX_key_length(ctx))
00398 ossl_raise(eCipherError, "key length too short");
00399
00400 if (EVP_CipherInit_ex(ctx, NULL, NULL, (unsigned char *)RSTRING_PTR(key), NULL, -1) != 1)
00401 ossl_raise(eCipherError, NULL);
00402
00403 return key;
00404 }
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414 static VALUE
00415 ossl_cipher_set_iv(VALUE self, VALUE iv)
00416 {
00417 EVP_CIPHER_CTX *ctx;
00418
00419 StringValue(iv);
00420 GetCipher(self, ctx);
00421
00422 if (RSTRING_LEN(iv) < EVP_CIPHER_CTX_iv_length(ctx))
00423 ossl_raise(eCipherError, "iv length too short");
00424
00425 if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, (unsigned char *)RSTRING_PTR(iv), -1) != 1)
00426 ossl_raise(eCipherError, NULL);
00427
00428 return iv;
00429 }
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443 static VALUE
00444 ossl_cipher_set_key_length(VALUE self, VALUE key_length)
00445 {
00446 int len = NUM2INT(key_length);
00447 EVP_CIPHER_CTX *ctx;
00448
00449 GetCipher(self, ctx);
00450 if (EVP_CIPHER_CTX_set_key_length(ctx, len) != 1)
00451 ossl_raise(eCipherError, NULL);
00452
00453 return key_length;
00454 }
00455
00456 #if defined(HAVE_EVP_CIPHER_CTX_SET_PADDING)
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467 static VALUE
00468 ossl_cipher_set_padding(VALUE self, VALUE padding)
00469 {
00470 EVP_CIPHER_CTX *ctx;
00471 int pad = NUM2INT(padding);
00472
00473 GetCipher(self, ctx);
00474 if (EVP_CIPHER_CTX_set_padding(ctx, pad) != 1)
00475 ossl_raise(eCipherError, NULL);
00476 return padding;
00477 }
00478 #else
00479 #define ossl_cipher_set_padding rb_f_notimplement
00480 #endif
00481
00482 #define CIPHER_0ARG_INT(func) \
00483 static VALUE \
00484 ossl_cipher_##func(VALUE self) \
00485 { \
00486 EVP_CIPHER_CTX *ctx; \
00487 GetCipher(self, ctx); \
00488 return INT2NUM(EVP_CIPHER_##func(EVP_CIPHER_CTX_cipher(ctx))); \
00489 }
00490 CIPHER_0ARG_INT(key_length)
00491 CIPHER_0ARG_INT(iv_length)
00492 CIPHER_0ARG_INT(block_size)
00493
00494 #if 0
00495
00496
00497
00498
00499
00500 static VALUE ossl_cipher_key_length() { }
00501
00502
00503
00504
00505
00506 static VALUE ossl_cipher_iv_length() { }
00507
00508
00509
00510
00511
00512 static VALUE ossl_cipher_block_size() { }
00513 #endif
00514
00515
00516
00517
00518 void
00519 Init_ossl_cipher(void)
00520 {
00521 #if 0
00522 mOSSL = rb_define_module("OpenSSL");
00523 #endif
00524 cCipher = rb_define_class_under(mOSSL, "Cipher", rb_cObject);
00525 eCipherError = rb_define_class_under(cCipher, "CipherError", eOSSLError);
00526
00527 rb_define_alloc_func(cCipher, ossl_cipher_alloc);
00528 rb_define_copy_func(cCipher, ossl_cipher_copy);
00529 rb_define_module_function(cCipher, "ciphers", ossl_s_ciphers, 0);
00530 rb_define_method(cCipher, "initialize", ossl_cipher_initialize, 1);
00531 rb_define_method(cCipher, "reset", ossl_cipher_reset, 0);
00532 rb_define_method(cCipher, "encrypt", ossl_cipher_encrypt, -1);
00533 rb_define_method(cCipher, "decrypt", ossl_cipher_decrypt, -1);
00534 rb_define_method(cCipher, "pkcs5_keyivgen", ossl_cipher_pkcs5_keyivgen, -1);
00535 rb_define_method(cCipher, "update", ossl_cipher_update, -1);
00536 rb_define_method(cCipher, "final", ossl_cipher_final, 0);
00537 rb_define_method(cCipher, "name", ossl_cipher_name, 0);
00538 rb_define_method(cCipher, "key=", ossl_cipher_set_key, 1);
00539 rb_define_method(cCipher, "key_len=", ossl_cipher_set_key_length, 1);
00540 rb_define_method(cCipher, "key_len", ossl_cipher_key_length, 0);
00541 rb_define_method(cCipher, "iv=", ossl_cipher_set_iv, 1);
00542 rb_define_method(cCipher, "iv_len", ossl_cipher_iv_length, 0);
00543 rb_define_method(cCipher, "block_size", ossl_cipher_block_size, 0);
00544 rb_define_method(cCipher, "padding=", ossl_cipher_set_padding, 1);
00545 }
00546
00547