Panda3D
|
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