00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00028 typedef int streamsize;
00029 #endif
00030
00031
00032
00033 static const int iteration_count_factor = 1000;
00034
00035
00036
00037
00038
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
00101
00102
00103
00104 EncryptStreamBuf::
00105 ~EncryptStreamBuf() {
00106 close_read();
00107 close_write();
00108 }
00109
00110
00111
00112
00113
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
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
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
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
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
00190
00191
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
00216
00217
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
00245
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
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
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
00286 result = EVP_EncryptInit(&_write_ctx, NULL, key, NULL);
00287 nassertv(result > 0);
00288
00289
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
00305
00306
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
00336
00337
00338
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
00350 char c = ch;
00351 write_chars(&c, 1);
00352 }
00353
00354 return 0;
00355 }
00356
00357
00358
00359
00360
00361
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
00382
00383
00384
00385
00386 int EncryptStreamBuf::
00387 underflow() {
00388
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
00398 if (read_count == 0) {
00399 gbump(num_bytes);
00400 return EOF;
00401 }
00402
00403
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
00417
00418
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
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
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
00475 if ((size_t)bytes_read <= length) {
00476
00477 memcpy(start, read_buffer, bytes_read);
00478 return bytes_read;
00479
00480 } else {
00481
00482
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
00495
00496
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