15 #include "encryptStreamBuf.h" 16 #include "config_prc.h" 17 #include "streamReader.h" 18 #include "streamWriter.h" 19 #include "configVariableInt.h" 20 #include "configVariableString.h" 24 #include "openssl/rand.h" 26 #ifndef HAVE_STREAMSIZE 28 typedef int streamsize;
33 static const int iteration_count_factor = 1000;
42 _source = (istream *)NULL;
44 _dest = (ostream *)NULL;
48 (
"encryption-algorithm",
"bf-cbc",
49 PRC_DESC(
"This defines the OpenSSL encryption algorithm which is used to " 50 "encrypt any streams created by the current runtime. The default is " 51 "Blowfish; the complete set of available algorithms is defined by " 52 "the current version of OpenSSL. This value is used only to control " 53 "encryption; the correct algorithm will automatically be selected on " 57 (
"encryption-key-length", 0,
58 PRC_DESC(
"This defines the key length, in bits, for the selected encryption " 59 "algorithm. Some algorithms have a variable key length. Specifying " 60 "a value of 0 here means to use the default key length for the " 61 "algorithm as defined by OpenSSL. This value is used only to " 62 "control encryption; the correct key length will automatically be " 63 "selected on decryption."));
66 (
"encryption-iteration-count", 100000,
67 PRC_DESC(
"This defines the number of times a password is hashed to generate a " 68 "key when encrypting. Its purpose is to make it computationally " 69 "more expensive for an attacker to search the key space " 70 "exhaustively. This should be a multiple of 1,000 and should not " 71 "exceed about 65 million; the value 0 indicates just one application " 72 "of the hashing algorithm. This value is used only to control " 73 "encryption; the correct count will automatically be selected on " 76 _algorithm = encryption_algorithm;
77 _key_length = encryption_key_length;
78 _iteration_count = encryption_iteration_count;
83 _read_overflow_buffer = NULL;
84 _in_read_overflow_buffer = 0;
87 char *buf =
new char[4096];
88 char *ebuf = buf + 4096;
89 setg(buf, ebuf, ebuf);
94 setg(base(), ebuf(), ebuf());
105 ~EncryptStreamBuf() {
115 void EncryptStreamBuf::
116 open_read(istream *source,
bool owns_source,
const string &password) {
117 OpenSSL_add_all_algorithms();
120 _owns_source = owns_source;
125 int nid = sr.get_uint16();
126 int key_length = sr.get_uint16();
127 int count = sr.get_uint16();
129 const EVP_CIPHER *cipher = EVP_get_cipherbynid(nid);
131 if (cipher == NULL) {
133 <<
"Unknown encryption algorithm in stream.\n";
137 _algorithm = OBJ_nid2sn(nid);
138 _key_length = key_length * 8;
139 _iteration_count = count * iteration_count_factor;
141 if (prc_cat.is_debug()) {
143 <<
"Using decryption algorithm " << _algorithm <<
" with key length " 144 << _key_length <<
" bits.\n";
146 <<
"Key is hashed " << _iteration_count <<
" extra times.\n";
149 int iv_length = EVP_CIPHER_iv_length(cipher);
150 _read_block_size = EVP_CIPHER_block_size(cipher);
152 string iv = sr.extract_bytes(iv_length);
156 result = EVP_DecryptInit(&_read_ctx, cipher, NULL, (
unsigned char *)iv.data());
157 nassertv(result > 0);
159 result = EVP_CIPHER_CTX_set_key_length(&_read_ctx, key_length);
162 <<
"Invalid key length " << key_length * 8 <<
" bits for algorithm " 163 << OBJ_nid2sn(nid) <<
"\n";
164 EVP_CIPHER_CTX_cleanup(&_read_ctx);
169 unsigned char *key = (
unsigned char *)alloca(key_length);
171 PKCS5_PBKDF2_HMAC_SHA1((
const char *)password.data(), password.length(),
172 (
unsigned char *)iv.data(), iv.length(),
173 count * iteration_count_factor + 1,
175 nassertv(result > 0);
178 result = EVP_DecryptInit(&_read_ctx, NULL, key, NULL);
179 nassertv(result > 0);
183 _read_overflow_buffer =
new unsigned char[_read_block_size];
184 _in_read_overflow_buffer = 0;
185 thread_consider_yield();
193 void EncryptStreamBuf::
196 EVP_CIPHER_CTX_cleanup(&_read_ctx);
200 if (_read_overflow_buffer != (
unsigned char *)NULL) {
201 delete[] _read_overflow_buffer;
202 _read_overflow_buffer = NULL;
205 if (_source != (istream *)NULL) {
208 _owns_source =
false;
210 _source = (istream *)NULL;
219 void EncryptStreamBuf::
220 open_write(ostream *dest,
bool owns_dest,
const string &password) {
221 OpenSSL_add_all_algorithms();
225 _owns_dest = owns_dest;
226 _write_valid =
false;
228 const EVP_CIPHER *cipher =
229 EVP_get_cipherbyname(_algorithm.c_str());
231 if (cipher == NULL) {
233 <<
"Unknown encryption algorithm: " << _algorithm <<
"\n";
237 int nid = EVP_CIPHER_nid(cipher);
239 int iv_length = EVP_CIPHER_iv_length(cipher);
240 _write_block_size = EVP_CIPHER_block_size(cipher);
242 unsigned char *iv = (
unsigned char *)alloca(iv_length);
246 RAND_pseudo_bytes(iv, iv_length);
249 result = EVP_EncryptInit(&_write_ctx, cipher, NULL, iv);
250 nassertv(result > 0);
253 int key_length = (_key_length + 7) / 8;
254 if (key_length == 0) {
255 key_length = EVP_CIPHER_key_length(cipher);
257 result = EVP_CIPHER_CTX_set_key_length(&_write_ctx, key_length);
260 <<
"Invalid key length " << key_length * 8 <<
" bits for algorithm " 261 << OBJ_nid2sn(nid) <<
"\n";
262 EVP_CIPHER_CTX_cleanup(&_write_ctx);
266 int count = _iteration_count / iteration_count_factor;
268 if (prc_cat.is_debug()) {
270 <<
"Using encryption algorithm " << OBJ_nid2sn(nid) <<
" with key length " 271 << key_length * 8 <<
" bits.\n";
273 <<
"Hashing key " << count * iteration_count_factor
274 <<
" extra times.\n";
278 unsigned char *key = (
unsigned char *)alloca(key_length);
280 PKCS5_PBKDF2_HMAC_SHA1((
const char *)password.data(), password.length(),
281 iv, iv_length, count * iteration_count_factor + 1,
283 nassertv(result > 0);
286 result = EVP_EncryptInit(&_write_ctx, NULL, key, NULL);
287 nassertv(result > 0);
291 nassertv((PN_uint16)nid == nid);
293 nassertv((PN_uint16)key_length == key_length);
294 sw.add_uint16(key_length);
295 nassertv((PN_uint16)count == count);
296 sw.add_uint16(count);
297 sw.append_data(iv, iv_length);
300 thread_consider_yield();
308 void EncryptStreamBuf::
310 if (_dest != (ostream *)NULL) {
311 size_t n = pptr() - pbase();
312 write_chars(pbase(), n);
316 unsigned char *write_buffer = (
unsigned char *)alloca(_write_block_size);
317 int bytes_written = 0;
318 EVP_EncryptFinal(&_write_ctx, write_buffer, &bytes_written);
319 thread_consider_yield();
321 _dest->write((
const char *)write_buffer, bytes_written);
323 _write_valid =
false;
330 _dest = (ostream *)NULL;
340 int EncryptStreamBuf::
342 size_t n = pptr() - pbase();
344 write_chars(pbase(), n);
363 int EncryptStreamBuf::
365 if (_source != (istream *)NULL) {
366 size_t n = egptr() - gptr();
370 if (_dest != (ostream *)NULL) {
371 size_t n = pptr() - pbase();
372 write_chars(pbase(), n);
386 int EncryptStreamBuf::
389 if (gptr() >= egptr()) {
390 size_t buffer_size = egptr() - eback();
391 gbump(-(
int)buffer_size);
393 size_t num_bytes = buffer_size;
394 size_t read_count = read_chars(gptr(), buffer_size);
396 if (read_count != num_bytes) {
398 if (read_count == 0) {
404 nassertr(read_count < num_bytes, EOF);
405 size_t delta = num_bytes - read_count;
406 memmove(gptr() + delta, gptr(), read_count);
411 return (
unsigned char)*gptr();
420 size_t EncryptStreamBuf::
421 read_chars(
char *start,
size_t length) {
426 if (_in_read_overflow_buffer != 0) {
428 length = min(length, _in_read_overflow_buffer);
429 memcpy(start, _read_overflow_buffer, length);
430 _in_read_overflow_buffer -= length;
431 memcpy(_read_overflow_buffer + length, _read_overflow_buffer, _in_read_overflow_buffer);
435 unsigned char *source_buffer = (
unsigned char *)alloca(length);
436 size_t max_read_buffer = length + _read_block_size;
437 unsigned char *read_buffer = (
unsigned char *)alloca(max_read_buffer);
447 _source->read((
char *)source_buffer, length);
448 size_t source_length = _source->gcount();
452 if (source_length != 0) {
454 EVP_DecryptUpdate(&_read_ctx, read_buffer, &bytes_read,
455 source_buffer, source_length);
458 EVP_DecryptFinal(&_read_ctx, read_buffer, &bytes_read);
464 <<
"Error decrypting stream.\n";
466 EVP_CIPHER_CTX_cleanup(&_read_ctx);
470 thread_consider_yield();
472 }
while (bytes_read == 0);
475 if ((
size_t)bytes_read <= length) {
477 memcpy(start, read_buffer, bytes_read);
483 _in_read_overflow_buffer = bytes_read - length;
484 nassertr(_in_read_overflow_buffer <= _read_block_size, 0);
486 memcpy(_read_overflow_buffer, read_buffer + length,
487 _in_read_overflow_buffer);
488 memcpy(start, read_buffer, length);
498 void EncryptStreamBuf::
499 write_chars(
const char *start,
size_t length) {
500 if (_write_valid && length != 0) {
501 size_t max_write_buffer = length + _write_block_size;
502 unsigned char *write_buffer = (
unsigned char *)alloca(max_write_buffer);
504 int bytes_written = 0;
506 EVP_EncryptUpdate(&_write_ctx, write_buffer, &bytes_written,
507 (
unsigned char *)start, length);
510 <<
"Error encrypting stream.\n";
512 thread_consider_yield();
513 _dest->write((
const char *)write_buffer, bytes_written);
517 #endif // HAVE_OPENSSL A StreamWriter object is used to write sequential binary data directly to an ostream.
This is a convenience class to specialize ConfigVariable as a string type.
This is a convenience class to specialize ConfigVariable as an integer type.
A class to read sequential binary data directly from an istream.