00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "ossl.h"
00012
00013 #define WrapCipher(obj, klass, ctx) \
00014 (obj) = Data_Wrap_Struct((klass), 0, ossl_cipher_free, (ctx))
00015 #define MakeCipher(obj, klass, ctx) \
00016 (obj) = Data_Make_Struct((klass), EVP_CIPHER_CTX, 0, ossl_cipher_free, (ctx))
00017 #define AllocCipher(obj, ctx) \
00018 memset(DATA_PTR(obj) = (ctx) = ALLOC(EVP_CIPHER_CTX), 0, sizeof(EVP_CIPHER_CTX))
00019 #define GetCipherInit(obj, ctx) do { \
00020 Data_Get_Struct((obj), EVP_CIPHER_CTX, (ctx)); \
00021 } while (0)
00022 #define GetCipher(obj, ctx) do { \
00023 GetCipherInit((obj), (ctx)); \
00024 if (!(ctx)) { \
00025 ossl_raise(rb_eRuntimeError, "Cipher not inititalized!"); \
00026 } \
00027 } while (0)
00028 #define SafeGetCipher(obj, ctx) do { \
00029 OSSL_Check_Kind((obj), cCipher); \
00030 GetCipher((obj), (ctx)); \
00031 } while (0)
00032
00033
00034
00035
00036 VALUE cCipher;
00037 VALUE eCipherError;
00038
00039 static VALUE ossl_cipher_alloc(VALUE klass);
00040
00041
00042
00043
00044 const EVP_CIPHER *
00045 GetCipherPtr(VALUE obj)
00046 {
00047 EVP_CIPHER_CTX *ctx;
00048
00049 SafeGetCipher(obj, ctx);
00050
00051 return EVP_CIPHER_CTX_cipher(ctx);
00052 }
00053
00054 VALUE
00055 ossl_cipher_new(const EVP_CIPHER *cipher)
00056 {
00057 VALUE ret;
00058 EVP_CIPHER_CTX *ctx;
00059
00060 ret = ossl_cipher_alloc(cCipher);
00061 AllocCipher(ret, ctx);
00062 EVP_CIPHER_CTX_init(ctx);
00063 if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)
00064 ossl_raise(eCipherError, NULL);
00065
00066 return ret;
00067 }
00068
00069
00070
00071
00072 static void
00073 ossl_cipher_free(EVP_CIPHER_CTX *ctx)
00074 {
00075 if (ctx) {
00076 EVP_CIPHER_CTX_cleanup(ctx);
00077 ruby_xfree(ctx);
00078 }
00079 }
00080
00081 static VALUE
00082 ossl_cipher_alloc(VALUE klass)
00083 {
00084 VALUE obj;
00085
00086 WrapCipher(obj, klass, 0);
00087
00088 return obj;
00089 }
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099 static VALUE
00100 ossl_cipher_initialize(VALUE self, VALUE str)
00101 {
00102 EVP_CIPHER_CTX *ctx;
00103 const EVP_CIPHER *cipher;
00104 char *name;
00105 unsigned char key[EVP_MAX_KEY_LENGTH];
00106
00107 name = StringValuePtr(str);
00108 GetCipherInit(self, ctx);
00109 if (ctx) {
00110 ossl_raise(rb_eRuntimeError, "Cipher already inititalized!");
00111 }
00112 AllocCipher(self, ctx);
00113 EVP_CIPHER_CTX_init(ctx);
00114 if (!(cipher = EVP_get_cipherbyname(name))) {
00115 ossl_raise(rb_eRuntimeError, "unsupported cipher algorithm (%s)", name);
00116 }
00117
00118
00119
00120
00121
00122
00123 memset(key, 0, EVP_MAX_KEY_LENGTH);
00124 if (EVP_CipherInit_ex(ctx, cipher, NULL, key, NULL, -1) != 1)
00125 ossl_raise(eCipherError, NULL);
00126
00127 return self;
00128 }
00129
00130 static VALUE
00131 ossl_cipher_copy(VALUE self, VALUE other)
00132 {
00133 EVP_CIPHER_CTX *ctx1, *ctx2;
00134
00135 rb_check_frozen(self);
00136 if (self == other) return self;
00137
00138 GetCipherInit(self, ctx1);
00139 if (!ctx1) {
00140 AllocCipher(self, ctx1);
00141 }
00142 SafeGetCipher(other, ctx2);
00143 if (EVP_CIPHER_CTX_copy(ctx1, ctx2) != 1)
00144 ossl_raise(eCipherError, NULL);
00145
00146 return self;
00147 }
00148
00149 #ifdef HAVE_OBJ_NAME_DO_ALL_SORTED
00150 static void*
00151 add_cipher_name_to_ary(const OBJ_NAME *name, VALUE ary)
00152 {
00153 rb_ary_push(ary, rb_str_new2(name->name));
00154 return NULL;
00155 }
00156 #endif
00157
00158 #ifdef HAVE_OBJ_NAME_DO_ALL_SORTED
00159
00160
00161
00162
00163
00164
00165 static VALUE
00166 ossl_s_ciphers(VALUE self)
00167 {
00168 VALUE ary;
00169
00170 ary = rb_ary_new();
00171 OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH,
00172 (void(*)(const OBJ_NAME*,void*))add_cipher_name_to_ary,
00173 (void*)ary);
00174
00175 return ary;
00176 }
00177 #else
00178 #define ossl_s_ciphers rb_f_notimplement
00179 #endif
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190 static VALUE
00191 ossl_cipher_reset(VALUE self)
00192 {
00193 EVP_CIPHER_CTX *ctx;
00194
00195 GetCipher(self, ctx);
00196 if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1) != 1)
00197 ossl_raise(eCipherError, NULL);
00198
00199 return self;
00200 }
00201
00202 static VALUE
00203 ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode)
00204 {
00205 EVP_CIPHER_CTX *ctx;
00206 unsigned char key[EVP_MAX_KEY_LENGTH], *p_key = NULL;
00207 unsigned char iv[EVP_MAX_IV_LENGTH], *p_iv = NULL;
00208 VALUE pass, init_v;
00209
00210 if(rb_scan_args(argc, argv, "02", &pass, &init_v) > 0){
00211
00212
00213
00214
00215
00216 VALUE cname = rb_class_path(rb_obj_class(self));
00217 rb_warn("arguments for %"PRIsVALUE"#encrypt and %"PRIsVALUE"#decrypt were deprecated; "
00218 "use %"PRIsVALUE"#pkcs5_keyivgen to derive key and IV",
00219 RB_OBJ_STRING(cname), RB_OBJ_STRING(cname), RB_OBJ_STRING(cname));
00220 StringValue(pass);
00221 GetCipher(self, ctx);
00222 if (NIL_P(init_v)) memcpy(iv, "OpenSSL for Ruby rulez!", sizeof(iv));
00223 else{
00224 StringValue(init_v);
00225 if (EVP_MAX_IV_LENGTH > RSTRING_LEN(init_v)) {
00226 memset(iv, 0, EVP_MAX_IV_LENGTH);
00227 memcpy(iv, RSTRING_PTR(init_v), RSTRING_LEN(init_v));
00228 }
00229 else memcpy(iv, RSTRING_PTR(init_v), sizeof(iv));
00230 }
00231 EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), EVP_md5(), iv,
00232 (unsigned char *)RSTRING_PTR(pass), RSTRING_LENINT(pass), 1, key, NULL);
00233 p_key = key;
00234 p_iv = iv;
00235 }
00236 else {
00237 GetCipher(self, ctx);
00238 }
00239 if (EVP_CipherInit_ex(ctx, NULL, NULL, p_key, p_iv, mode) != 1) {
00240 ossl_raise(eCipherError, NULL);
00241 }
00242
00243 return self;
00244 }
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258 static VALUE
00259 ossl_cipher_encrypt(int argc, VALUE *argv, VALUE self)
00260 {
00261 return ossl_cipher_init(argc, argv, self, 1);
00262 }
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276 static VALUE
00277 ossl_cipher_decrypt(int argc, VALUE *argv, VALUE self)
00278 {
00279 return ossl_cipher_init(argc, argv, self, 0);
00280 }
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 static VALUE
00303 ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
00304 {
00305 EVP_CIPHER_CTX *ctx;
00306 const EVP_MD *digest;
00307 VALUE vpass, vsalt, viter, vdigest;
00308 unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH], *salt = NULL;
00309 int iter;
00310
00311 rb_scan_args(argc, argv, "13", &vpass, &vsalt, &viter, &vdigest);
00312 StringValue(vpass);
00313 if(!NIL_P(vsalt)){
00314 StringValue(vsalt);
00315 if(RSTRING_LEN(vsalt) != PKCS5_SALT_LEN)
00316 ossl_raise(eCipherError, "salt must be an 8-octet string");
00317 salt = (unsigned char *)RSTRING_PTR(vsalt);
00318 }
00319 iter = NIL_P(viter) ? 2048 : NUM2INT(viter);
00320 digest = NIL_P(vdigest) ? EVP_md5() : GetDigestPtr(vdigest);
00321 GetCipher(self, ctx);
00322 EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), digest, salt,
00323 (unsigned char *)RSTRING_PTR(vpass), RSTRING_LENINT(vpass), iter, key, iv);
00324 if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, -1) != 1)
00325 ossl_raise(eCipherError, NULL);
00326 OPENSSL_cleanse(key, sizeof key);
00327 OPENSSL_cleanse(iv, sizeof iv);
00328
00329 return Qnil;
00330 }
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346 static VALUE
00347 ossl_cipher_update(int argc, VALUE *argv, VALUE self)
00348 {
00349 EVP_CIPHER_CTX *ctx;
00350 unsigned char *in;
00351 int in_len, out_len;
00352 VALUE data, str;
00353
00354 rb_scan_args(argc, argv, "11", &data, &str);
00355
00356 StringValue(data);
00357 in = (unsigned char *)RSTRING_PTR(data);
00358 if ((in_len = RSTRING_LENINT(data)) == 0)
00359 ossl_raise(rb_eArgError, "data must not be empty");
00360 GetCipher(self, ctx);
00361 out_len = in_len+EVP_CIPHER_CTX_block_size(ctx);
00362
00363 if (NIL_P(str)) {
00364 str = rb_str_new(0, out_len);
00365 } else {
00366 StringValue(str);
00367 rb_str_resize(str, out_len);
00368 }
00369
00370 if (!EVP_CipherUpdate(ctx, (unsigned char *)RSTRING_PTR(str), &out_len, in, in_len))
00371 ossl_raise(eCipherError, NULL);
00372 assert(out_len < RSTRING_LEN(str));
00373 rb_str_set_len(str, out_len);
00374
00375 return str;
00376 }
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387 static VALUE
00388 ossl_cipher_final(VALUE self)
00389 {
00390 EVP_CIPHER_CTX *ctx;
00391 int out_len;
00392 VALUE str;
00393
00394 GetCipher(self, ctx);
00395 str = rb_str_new(0, EVP_CIPHER_CTX_block_size(ctx));
00396 if (!EVP_CipherFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), &out_len))
00397 ossl_raise(eCipherError, NULL);
00398 assert(out_len <= RSTRING_LEN(str));
00399 rb_str_set_len(str, out_len);
00400
00401 return str;
00402 }
00403
00404
00405
00406
00407
00408
00409
00410
00411 static VALUE
00412 ossl_cipher_name(VALUE self)
00413 {
00414 EVP_CIPHER_CTX *ctx;
00415
00416 GetCipher(self, ctx);
00417
00418 return rb_str_new2(EVP_CIPHER_name(EVP_CIPHER_CTX_cipher(ctx)));
00419 }
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432 static VALUE
00433 ossl_cipher_set_key(VALUE self, VALUE key)
00434 {
00435 EVP_CIPHER_CTX *ctx;
00436
00437 StringValue(key);
00438 GetCipher(self, ctx);
00439
00440 if (RSTRING_LEN(key) < EVP_CIPHER_CTX_key_length(ctx))
00441 ossl_raise(eCipherError, "key length too short");
00442
00443 if (EVP_CipherInit_ex(ctx, NULL, NULL, (unsigned char *)RSTRING_PTR(key), NULL, -1) != 1)
00444 ossl_raise(eCipherError, NULL);
00445
00446 return key;
00447 }
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464 static VALUE
00465 ossl_cipher_set_iv(VALUE self, VALUE iv)
00466 {
00467 EVP_CIPHER_CTX *ctx;
00468
00469 StringValue(iv);
00470 GetCipher(self, ctx);
00471
00472 if (RSTRING_LEN(iv) < EVP_CIPHER_CTX_iv_length(ctx))
00473 ossl_raise(eCipherError, "iv length too short");
00474
00475 if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, (unsigned char *)RSTRING_PTR(iv), -1) != 1)
00476 ossl_raise(eCipherError, NULL);
00477
00478 return iv;
00479 }
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494 static VALUE
00495 ossl_cipher_set_key_length(VALUE self, VALUE key_length)
00496 {
00497 int len = NUM2INT(key_length);
00498 EVP_CIPHER_CTX *ctx;
00499
00500 GetCipher(self, ctx);
00501 if (EVP_CIPHER_CTX_set_key_length(ctx, len) != 1)
00502 ossl_raise(eCipherError, NULL);
00503
00504 return key_length;
00505 }
00506
00507 #if defined(HAVE_EVP_CIPHER_CTX_SET_PADDING)
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518 static VALUE
00519 ossl_cipher_set_padding(VALUE self, VALUE padding)
00520 {
00521 EVP_CIPHER_CTX *ctx;
00522 int pad = NUM2INT(padding);
00523
00524 GetCipher(self, ctx);
00525 if (EVP_CIPHER_CTX_set_padding(ctx, pad) != 1)
00526 ossl_raise(eCipherError, NULL);
00527 return padding;
00528 }
00529 #else
00530 #define ossl_cipher_set_padding rb_f_notimplement
00531 #endif
00532
00533 #define CIPHER_0ARG_INT(func) \
00534 static VALUE \
00535 ossl_cipher_##func(VALUE self) \
00536 { \
00537 EVP_CIPHER_CTX *ctx; \
00538 GetCipher(self, ctx); \
00539 return INT2NUM(EVP_CIPHER_##func(EVP_CIPHER_CTX_cipher(ctx))); \
00540 }
00541
00542
00543
00544
00545
00546
00547
00548 CIPHER_0ARG_INT(key_length)
00549
00550
00551
00552
00553
00554
00555 CIPHER_0ARG_INT(iv_length)
00556
00557
00558
00559
00560
00561
00562 CIPHER_0ARG_INT(block_size)
00563
00564
00565
00566
00567 void
00568 Init_ossl_cipher(void)
00569 {
00570 #if 0
00571 mOSSL = rb_define_module("OpenSSL");
00572 #endif
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732 cCipher = rb_define_class_under(mOSSL, "Cipher", rb_cObject);
00733 eCipherError = rb_define_class_under(cCipher, "CipherError", eOSSLError);
00734
00735 rb_define_alloc_func(cCipher, ossl_cipher_alloc);
00736 rb_define_copy_func(cCipher, ossl_cipher_copy);
00737 rb_define_module_function(cCipher, "ciphers", ossl_s_ciphers, 0);
00738 rb_define_method(cCipher, "initialize", ossl_cipher_initialize, 1);
00739 rb_define_method(cCipher, "reset", ossl_cipher_reset, 0);
00740 rb_define_method(cCipher, "encrypt", ossl_cipher_encrypt, -1);
00741 rb_define_method(cCipher, "decrypt", ossl_cipher_decrypt, -1);
00742 rb_define_method(cCipher, "pkcs5_keyivgen", ossl_cipher_pkcs5_keyivgen, -1);
00743 rb_define_method(cCipher, "update", ossl_cipher_update, -1);
00744 rb_define_method(cCipher, "final", ossl_cipher_final, 0);
00745 rb_define_method(cCipher, "name", ossl_cipher_name, 0);
00746 rb_define_method(cCipher, "key=", ossl_cipher_set_key, 1);
00747 rb_define_method(cCipher, "key_len=", ossl_cipher_set_key_length, 1);
00748 rb_define_method(cCipher, "key_len", ossl_cipher_key_length, 0);
00749 rb_define_method(cCipher, "iv=", ossl_cipher_set_iv, 1);
00750 rb_define_method(cCipher, "iv_len", ossl_cipher_iv_length, 0);
00751 rb_define_method(cCipher, "block_size", ossl_cipher_block_size, 0);
00752 rb_define_method(cCipher, "padding=", ossl_cipher_set_padding, 1);
00753 }
00754
00755