Panda3D

encryptStreamBuf.cxx

00001 // Filename: encryptStreamBuf.cxx
00002 // Created by:  drose (01Sep04)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "encryptStreamBuf.h"
00016 #include "config_prc.h"
00017 #include "streamReader.h"
00018 #include "streamWriter.h"
00019 #include "configVariableInt.h"
00020 #include "configVariableString.h"
00021 
00022 #ifdef HAVE_OPENSSL
00023 
00024 #include "openssl/rand.h"
00025 
00026 #ifndef HAVE_STREAMSIZE
00027 // Some compilers (notably SGI) don't define this for us
00028 typedef int streamsize;
00029 #endif /* HAVE_STREAMSIZE */
00030 
00031 // The iteration count is scaled by this factor for writing to the
00032 // stream.
00033 static const int iteration_count_factor = 1000;
00034 
00035 ////////////////////////////////////////////////////////////////////
00036 //     Function: EncryptStreamBuf::Constructor
00037 //       Access: Public
00038 //  Description:
00039 ////////////////////////////////////////////////////////////////////
00040 EncryptStreamBuf::
00041 EncryptStreamBuf() {
00042   _source = (istream *)NULL;
00043   _owns_source = false;
00044   _dest = (ostream *)NULL;
00045   _owns_dest = false;
00046 
00047   ConfigVariableString encryption_algorithm
00048     ("encryption-algorithm", "bf-cbc",
00049      PRC_DESC("This defines the OpenSSL encryption algorithm which is used to "
00050               "encrypt any streams created by the current runtime.  The default is "
00051               "Blowfish; the complete set of available algorithms is defined by "
00052               "the current version of OpenSSL.  This value is used only to control "
00053               "encryption; the correct algorithm will automatically be selected on "
00054               "decryption."));
00055 
00056   ConfigVariableInt encryption_key_length
00057     ("encryption-key-length", 0,
00058      PRC_DESC("This defines the key length, in bits, for the selected encryption "
00059               "algorithm.  Some algorithms have a variable key length.  Specifying "
00060               "a value of 0 here means to use the default key length for the "
00061               "algorithm as defined by OpenSSL.  This value is used only to "
00062               "control encryption; the correct key length will automatically be "
00063               "selected on decryption."));
00064 
00065   ConfigVariableInt encryption_iteration_count
00066     ("encryption-iteration-count", 100000,
00067      PRC_DESC("This defines the number of times a password is hashed to generate a "
00068               "key when encrypting.  Its purpose is to make it computationally "
00069               "more expensive for an attacker to search the key space "
00070               "exhaustively.  This should be a multiple of 1,000 and should not "
00071               "exceed about 65 million; the value 0 indicates just one application "
00072               "of the hashing algorithm.  This value is used only to control "
00073               "encryption; the correct count will automatically be selected on "
00074               "decryption."));
00075 
00076   _algorithm = encryption_algorithm;
00077   _key_length = encryption_key_length;
00078   _iteration_count = encryption_iteration_count;
00079 
00080   _read_valid = false;
00081   _write_valid = false;
00082 
00083   _read_overflow_buffer = NULL;
00084   _in_read_overflow_buffer = 0;
00085 
00086 #ifdef PHAVE_IOSTREAM
00087   char *buf = new char[4096];
00088   char *ebuf = buf + 4096;
00089   setg(buf, ebuf, ebuf);
00090   setp(buf, ebuf);
00091 
00092 #else
00093   allocate();
00094   setg(base(), ebuf(), ebuf());
00095   setp(base(), ebuf());
00096 #endif
00097 }
00098 
00099 ////////////////////////////////////////////////////////////////////
00100 //     Function: EncryptStreamBuf::Destructor
00101 //       Access: Public, Virtual
00102 //  Description:
00103 ////////////////////////////////////////////////////////////////////
00104 EncryptStreamBuf::
00105 ~EncryptStreamBuf() {
00106   close_read();
00107   close_write();
00108 }
00109 
00110 ////////////////////////////////////////////////////////////////////
00111 //     Function: EncryptStreamBuf::open_read
00112 //       Access: Public
00113 //  Description:
00114 ////////////////////////////////////////////////////////////////////
00115 void EncryptStreamBuf::
00116 open_read(istream *source, bool owns_source, const string &password) {
00117   OpenSSL_add_all_algorithms();
00118 
00119   _source = source;
00120   _owns_source = owns_source;
00121   _read_valid = false;
00122 
00123   // Now read the header information.
00124   StreamReader sr(_source, false);
00125   int nid = sr.get_uint16();
00126   int key_length = sr.get_uint16();
00127   int count = sr.get_uint16();
00128 
00129   const EVP_CIPHER *cipher = EVP_get_cipherbynid(nid);
00130 
00131   if (cipher == NULL) {
00132     prc_cat.error()
00133       << "Unknown encryption algorithm in stream.\n";
00134     return;
00135   }
00136 
00137   _algorithm = OBJ_nid2sn(nid);
00138   _key_length = key_length * 8;
00139   _iteration_count = count * iteration_count_factor;
00140 
00141   if (prc_cat.is_debug()) {
00142     prc_cat.debug()
00143       << "Using decryption algorithm " << _algorithm << " with key length "
00144       << _key_length << " bits.\n";
00145     prc_cat.debug()
00146       << "Key is hashed " << _iteration_count << " extra times.\n";
00147   }
00148 
00149   int iv_length = EVP_CIPHER_iv_length(cipher);
00150   _read_block_size = EVP_CIPHER_block_size(cipher);
00151 
00152   string iv = sr.extract_bytes(iv_length);
00153 
00154   // Initialize the context
00155   int result;
00156   result = EVP_DecryptInit(&_read_ctx, cipher, NULL, (unsigned char *)iv.data());
00157   nassertv(result > 0);
00158 
00159   result = EVP_CIPHER_CTX_set_key_length(&_read_ctx, key_length);
00160   if (result <= 0) {
00161     prc_cat.error()
00162       << "Invalid key length " << key_length * 8 << " bits for algorithm "
00163       << OBJ_nid2sn(nid) << "\n";
00164     EVP_CIPHER_CTX_cleanup(&_read_ctx);
00165     return;
00166   }
00167 
00168   // Hash the supplied password into a key of the appropriate length.
00169   unsigned char *key = (unsigned char *)alloca(key_length);
00170   result =
00171     PKCS5_PBKDF2_HMAC_SHA1((const char *)password.data(), password.length(),
00172                            (unsigned char *)iv.data(), iv.length(), 
00173                            count * iteration_count_factor + 1, 
00174                            key_length, key);
00175   nassertv(result > 0);
00176 
00177   // Store the key within the context.
00178   result = EVP_DecryptInit(&_read_ctx, NULL, key, NULL);
00179   nassertv(result > 0);
00180 
00181   _read_valid = true;
00182 
00183   _read_overflow_buffer = new unsigned char[_read_block_size];
00184   _in_read_overflow_buffer = 0;
00185   thread_consider_yield();
00186 }
00187 
00188 ////////////////////////////////////////////////////////////////////
00189 //     Function: EncryptStreamBuf::close_read
00190 //       Access: Public
00191 //  Description:
00192 ////////////////////////////////////////////////////////////////////
00193 void EncryptStreamBuf::
00194 close_read() {
00195   if (_read_valid) {
00196     EVP_CIPHER_CTX_cleanup(&_read_ctx);
00197     _read_valid = false;
00198   }
00199 
00200   if (_read_overflow_buffer != (unsigned char *)NULL) {
00201     delete[] _read_overflow_buffer;
00202     _read_overflow_buffer = NULL;
00203   }
00204 
00205   if (_source != (istream *)NULL) {
00206     if (_owns_source) {
00207       delete _source;
00208       _owns_source = false;
00209     }
00210     _source = (istream *)NULL;
00211   }
00212 }
00213 
00214 ////////////////////////////////////////////////////////////////////
00215 //     Function: EncryptStreamBuf::open_write
00216 //       Access: Public
00217 //  Description:
00218 ////////////////////////////////////////////////////////////////////
00219 void EncryptStreamBuf::
00220 open_write(ostream *dest, bool owns_dest, const string &password) {
00221   OpenSSL_add_all_algorithms();
00222 
00223   close_write();
00224   _dest = dest;
00225   _owns_dest = owns_dest;
00226   _write_valid = false;
00227 
00228   const EVP_CIPHER *cipher = 
00229     EVP_get_cipherbyname(_algorithm.c_str());
00230 
00231   if (cipher == NULL) {
00232     prc_cat.error()
00233       << "Unknown encryption algorithm: " << _algorithm << "\n";
00234     return;
00235   };
00236 
00237   int nid = EVP_CIPHER_nid(cipher);
00238     
00239   int iv_length = EVP_CIPHER_iv_length(cipher);
00240   _write_block_size = EVP_CIPHER_block_size(cipher);
00241 
00242   unsigned char *iv = (unsigned char *)alloca(iv_length);
00243 
00244   // Generate a random IV.  It doesn't need to be cryptographically
00245   // secure, just unique.
00246   RAND_pseudo_bytes(iv, iv_length);
00247 
00248   int result;
00249   result = EVP_EncryptInit(&_write_ctx, cipher, NULL, iv);
00250   nassertv(result > 0);
00251 
00252   // Store the appropriate key length in the context.
00253   int key_length = (_key_length + 7) / 8;
00254   if (key_length == 0) {
00255     key_length = EVP_CIPHER_key_length(cipher);
00256   }
00257   result = EVP_CIPHER_CTX_set_key_length(&_write_ctx, key_length);
00258   if (result <= 0) {
00259     prc_cat.error()
00260       << "Invalid key length " << key_length * 8 << " bits for algorithm "
00261       << OBJ_nid2sn(nid) << "\n";
00262     EVP_CIPHER_CTX_cleanup(&_write_ctx);
00263     return;
00264   }
00265 
00266   int count = _iteration_count / iteration_count_factor;
00267 
00268   if (prc_cat.is_debug()) {
00269     prc_cat.debug()
00270       << "Using encryption algorithm " << OBJ_nid2sn(nid) << " with key length "
00271       << key_length * 8 << " bits.\n";
00272     prc_cat.debug()
00273       << "Hashing key " << count * iteration_count_factor
00274       << " extra times.\n";
00275   }
00276 
00277   // Hash the supplied password into a key of the appropriate length.
00278   unsigned char *key = (unsigned char *)alloca(key_length);
00279   result =
00280     PKCS5_PBKDF2_HMAC_SHA1((const char *)password.data(), password.length(),
00281                            iv, iv_length, count * iteration_count_factor + 1,
00282                            key_length, key);
00283   nassertv(result > 0);
00284 
00285   // Store the key in the context.
00286   result = EVP_EncryptInit(&_write_ctx, NULL, key, NULL);
00287   nassertv(result > 0);
00288 
00289   // Now write the header information to the stream.
00290   StreamWriter sw(_dest, false);
00291   nassertv((PN_uint16)nid == nid);
00292   sw.add_uint16(nid);
00293   nassertv((PN_uint16)key_length == key_length);
00294   sw.add_uint16(key_length);
00295   nassertv((PN_uint16)count == count);
00296   sw.add_uint16(count);
00297   sw.append_data(iv, iv_length);
00298 
00299   _write_valid = true;
00300   thread_consider_yield();
00301 }
00302 
00303 ////////////////////////////////////////////////////////////////////
00304 //     Function: EncryptStreamBuf::close_write
00305 //       Access: Public
00306 //  Description:
00307 ////////////////////////////////////////////////////////////////////
00308 void EncryptStreamBuf::
00309 close_write() {
00310   if (_dest != (ostream *)NULL) {
00311     size_t n = pptr() - pbase();
00312     write_chars(pbase(), n);
00313     pbump(-(int)n);
00314     
00315     if (_write_valid) {
00316       unsigned char *write_buffer = (unsigned char *)alloca(_write_block_size);
00317       int bytes_written = 0;
00318       EVP_EncryptFinal(&_write_ctx, write_buffer, &bytes_written);
00319       thread_consider_yield();
00320       
00321       _dest->write((const char *)write_buffer, bytes_written);
00322       
00323       _write_valid = false;
00324     }
00325 
00326     if (_owns_dest) {
00327       delete _dest;
00328       _owns_dest = false;
00329     }
00330     _dest = (ostream *)NULL;
00331   }
00332 }
00333 
00334 ////////////////////////////////////////////////////////////////////
00335 //     Function: EncryptStreamBuf::overflow
00336 //       Access: Protected, Virtual
00337 //  Description: Called by the system ostream implementation when its
00338 //               internal buffer is filled, plus one character.
00339 ////////////////////////////////////////////////////////////////////
00340 int EncryptStreamBuf::
00341 overflow(int ch) {
00342   size_t n = pptr() - pbase();
00343   if (n != 0) {
00344     write_chars(pbase(), n);
00345     pbump(-(int)n);
00346   }
00347 
00348   if (ch != EOF) {
00349     // Write one more character.
00350     char c = ch;
00351     write_chars(&c, 1);
00352   }
00353 
00354   return 0;
00355 }
00356 
00357 ////////////////////////////////////////////////////////////////////
00358 //     Function: EncryptStreamBuf::sync
00359 //       Access: Protected, Virtual
00360 //  Description: Called by the system iostream implementation to
00361 //               implement a flush operation.
00362 ////////////////////////////////////////////////////////////////////
00363 int EncryptStreamBuf::
00364 sync() {
00365   if (_source != (istream *)NULL) {
00366     size_t n = egptr() - gptr();
00367     gbump(n);
00368   }
00369 
00370   if (_dest != (ostream *)NULL) {
00371     size_t n = pptr() - pbase();
00372     write_chars(pbase(), n);
00373     pbump(-(int)n);
00374   }
00375   
00376   _dest->flush();
00377   return 0;
00378 }
00379 
00380 ////////////////////////////////////////////////////////////////////
00381 //     Function: EncryptStreamBuf::underflow
00382 //       Access: Protected, Virtual
00383 //  Description: Called by the system istream implementation when its
00384 //               internal buffer needs more characters.
00385 ////////////////////////////////////////////////////////////////////
00386 int EncryptStreamBuf::
00387 underflow() {
00388   // Sometimes underflow() is called even if the buffer is not empty.
00389   if (gptr() >= egptr()) {
00390     size_t buffer_size = egptr() - eback();
00391     gbump(-(int)buffer_size);
00392 
00393     size_t num_bytes = buffer_size;
00394     size_t read_count = read_chars(gptr(), buffer_size);
00395 
00396     if (read_count != num_bytes) {
00397       // Oops, we didn't read what we thought we would.
00398       if (read_count == 0) {
00399         gbump(num_bytes);
00400         return EOF;
00401       }
00402 
00403       // Slide what we did read to the top of the buffer.
00404       nassertr(read_count < num_bytes, EOF);
00405       size_t delta = num_bytes - read_count;
00406       memmove(gptr() + delta, gptr(), read_count);
00407       gbump(delta);
00408     }
00409   }
00410 
00411   return (unsigned char)*gptr();
00412 }
00413 
00414 
00415 ////////////////////////////////////////////////////////////////////
00416 //     Function: EncryptStreamBuf::read_chars
00417 //       Access: Private
00418 //  Description: Gets some characters from the source stream.
00419 ////////////////////////////////////////////////////////////////////
00420 size_t EncryptStreamBuf::
00421 read_chars(char *start, size_t length) {
00422   if (length == 0) {
00423     return 0;
00424   }
00425 
00426   if (_in_read_overflow_buffer != 0) {
00427     // Take from the overflow buffer.
00428     length = min(length, _in_read_overflow_buffer);
00429     memcpy(start, _read_overflow_buffer, length);
00430     _in_read_overflow_buffer -= length;
00431     memcpy(_read_overflow_buffer + length, _read_overflow_buffer, _in_read_overflow_buffer);
00432     return length;
00433   }
00434 
00435   unsigned char *source_buffer = (unsigned char *)alloca(length);
00436   size_t max_read_buffer = length + _read_block_size;
00437   unsigned char *read_buffer = (unsigned char *)alloca(max_read_buffer);
00438 
00439   int bytes_read = 0;
00440     
00441   do {
00442     // Get more bytes from the stream.    
00443     if (!_read_valid) {
00444       return 0;
00445     }
00446     
00447     _source->read((char *)source_buffer, length);
00448     size_t source_length = _source->gcount();
00449 
00450     bytes_read = 0;
00451     int result;
00452     if (source_length != 0) {
00453       result =
00454         EVP_DecryptUpdate(&_read_ctx, read_buffer, &bytes_read,
00455                           source_buffer, source_length);
00456     } else {
00457       result =
00458         EVP_DecryptFinal(&_read_ctx, read_buffer, &bytes_read);
00459       _read_valid = false;
00460     }
00461 
00462     if (result <= 0) {
00463       prc_cat.error()
00464         << "Error decrypting stream.\n";
00465       if (_read_valid) {
00466         EVP_CIPHER_CTX_cleanup(&_read_ctx);
00467         _read_valid = false;
00468       }
00469     }
00470     thread_consider_yield();
00471 
00472   } while (bytes_read == 0);
00473 
00474   // Now store the read bytes in the output stream.
00475   if ((size_t)bytes_read <= length) {
00476     // No overflow.
00477     memcpy(start, read_buffer, bytes_read);
00478     return bytes_read;
00479 
00480   } else {
00481     // We have to save some of the returned bytes in the overflow
00482     // buffer.
00483     _in_read_overflow_buffer = bytes_read - length;
00484     nassertr(_in_read_overflow_buffer <= _read_block_size, 0);
00485 
00486     memcpy(_read_overflow_buffer, read_buffer + length, 
00487            _in_read_overflow_buffer);
00488     memcpy(start, read_buffer, length);
00489     return length;
00490   }
00491 }
00492 
00493 ////////////////////////////////////////////////////////////////////
00494 //     Function: EncryptStreamBuf::write_chars
00495 //       Access: Private
00496 //  Description: Sends some characters to the dest stream.
00497 ////////////////////////////////////////////////////////////////////
00498 void EncryptStreamBuf::
00499 write_chars(const char *start, size_t length) {
00500   if (_write_valid && length != 0) {
00501     size_t max_write_buffer = length + _write_block_size;
00502     unsigned char *write_buffer = (unsigned char *)alloca(max_write_buffer);
00503     
00504     int bytes_written = 0;
00505     int result = 
00506       EVP_EncryptUpdate(&_write_ctx, write_buffer, &bytes_written,
00507                         (unsigned char *)start, length);
00508     if (result <= 0) {
00509       prc_cat.error() 
00510         << "Error encrypting stream.\n";
00511     }
00512     thread_consider_yield();
00513     _dest->write((const char *)write_buffer, bytes_written);
00514   }
00515 }
00516 
00517 #endif  // HAVE_OPENSSL
 All Classes Functions Variables Enumerations