• Main Page
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

ext/openssl/ossl_cipher.c

Go to the documentation of this file.
00001 /*
00002  * $Id: ossl_cipher.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 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  * Classes
00028  */
00029 VALUE cCipher;
00030 VALUE eCipherError;
00031 
00032 static VALUE ossl_cipher_alloc(VALUE klass);
00033 
00034 /*
00035  * PUBLIC
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  * PRIVATE
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  *  call-seq:
00088  *     Cipher.new(string) -> cipher
00089  *
00090  *  The string must contain a valid cipher name like "AES-128-CBC" or "3DES".
00091  *
00092  *  A list of cipher names is available by calling OpenSSL::Cipher.ciphers.
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  *  call-seq:
00139  *     Cipher.ciphers -> array[string...]
00140  *
00141  *  Returns the names of all available ciphers in an array.
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  *  call-seq:
00161  *     cipher.reset -> self
00162  *
00163  *  Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1).
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          * oops. this code mistakes salt for IV.
00188          * We deprecated the arguments for this method, but we decided
00189          * keeping this behaviour for backward compatibility.
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  *  call-seq:
00223  *     cipher.encrypt -> self
00224  *
00225  *  Make sure to call .encrypt or .decrypt before using any of the following methods:
00226  *  * [key=, iv=, random_key, random_iv, pkcs5_keyivgen]
00227  *
00228  *  Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 1).
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  *  call-seq:
00238  *     cipher.decrypt -> self
00239  *
00240  *  Make sure to call .encrypt or .decrypt before using any of the following methods:
00241  *  * [key=, iv=, random_key, random_iv, pkcs5_keyivgen]
00242  *
00243  *  Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 0).
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  *  call-seq:
00253  *     cipher.pkcs5_keyivgen(pass [, salt [, iterations [, digest]]] ) -> nil
00254  *
00255  *  Generates and sets the key/iv based on a password.
00256  *
00257  *  WARNING: This method is only PKCS5 v1.5 compliant when using RC2, RC4-40, or DES
00258  *  with MD5 or SHA1.  Using anything else (like AES) will generate the key/iv using an
00259  *  OpenSSL specific method.  Use a PKCS5 v2 key generation method instead.
00260  *
00261  *  === Parameters
00262  *  +salt+ must be an 8 byte string if provided.
00263  *  +iterations+ is a integer with a default of 2048.
00264  *  +digest+ is a Digest object that defaults to 'MD5'
00265  *
00266  *  A minimum of 1000 iterations is recommended.
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  *  call-seq:
00302  *     cipher.update(data [, buffer]) -> string or buffer
00303  *
00304  *  === Parameters
00305  *  +data+ is a nonempty string.
00306  *  +buffer+ is an optional string to store the result.
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  *  call-seq:
00342  *     cipher.final -> aString
00343  *
00344  *  Returns the remaining data held in the cipher object.  Further calls to update() or final() will return garbage.
00345  *
00346  *  See EVP_CipherFinal_ex for further information.
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  *  call-seq:
00367  *     cipher.name -> string
00368  *
00369  *  Returns the name of the cipher which may differ slightly from the original name provided.
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  *  call-seq:
00383  *     cipher.key = string -> string
00384  *
00385  *  Sets the cipher key.
00386  *
00387  *  Only call this method after calling cipher.encrypt or cipher.decrypt.
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  *  call-seq:
00408  *     cipher.iv = string -> string
00409  *
00410  *  Sets the cipher iv.
00411  *
00412  *  Only call this method after calling cipher.encrypt or cipher.decrypt.
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  *  call-seq:
00434  *     cipher.key_length = integer -> integer
00435  *
00436  *  Sets the key length of the cipher.  If the cipher is a fixed length cipher then attempting to set the key
00437  *  length to any value other than the fixed value is an error.
00438  *
00439  *  Under normal circumstances you do not need to call this method (and probably shouldn't).
00440  *
00441  *  See EVP_CIPHER_CTX_set_key_length for further information.
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  *  call-seq:
00459  *     cipher.padding = integer -> integer
00460  *
00461  *  Enables or disables padding. By default encryption operations are padded using standard block padding and the
00462  *  padding is checked and removed when decrypting. If the pad parameter is zero then no padding is performed, the
00463  *  total amount of data encrypted or decrypted must then be a multiple of the block size or an error will occur.
00464  *
00465  *  See EVP_CIPHER_CTX_set_padding for further information.
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  *  call-seq:
00497  *     cipher.key_length -> integer
00498  *
00499  */
00500 static VALUE ossl_cipher_key_length() { }
00501 /*
00502  *  call-seq:
00503  *     cipher.iv_length -> integer
00504  *
00505  */
00506 static VALUE ossl_cipher_iv_length() { }
00507 /*
00508  *  call-seq:
00509  *     cipher.block_size -> integer
00510  *
00511  */
00512 static VALUE ossl_cipher_block_size() { }
00513 #endif
00514 
00515 /*
00516  * INIT
00517  */
00518 void
00519 Init_ossl_cipher(void)
00520 {
00521 #if 0 /* let rdoc know about mOSSL */
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 

Generated on Sat Jul 7 2012 15:29:10 for Ruby by  doxygen 1.7.1