23 #include <openssl/rand.h> 24 #include <openssl/evp.h> 27 static const int iteration_count_factor = 1000;
40 (
"encryption-algorithm",
"bf-cbc",
41 PRC_DESC(
"This defines the OpenSSL encryption algorithm which is used to " 42 "encrypt any streams created by the current runtime. The default is " 43 "Blowfish; the complete set of available algorithms is defined by " 44 "the current version of OpenSSL. This value is used only to control " 45 "encryption; the correct algorithm will automatically be selected on " 49 (
"encryption-key-length", 0,
50 PRC_DESC(
"This defines the key length, in bits, for the selected encryption " 51 "algorithm. Some algorithms have a variable key length. Specifying " 52 "a value of 0 here means to use the default key length for the " 53 "algorithm as defined by OpenSSL. This value is used only to " 54 "control encryption; the correct key length will automatically be " 55 "selected on decryption."));
58 (
"encryption-iteration-count", 100000,
59 PRC_DESC(
"This defines the number of times a password is hashed to generate a " 60 "key when encrypting. Its purpose is to make it computationally " 61 "more expensive for an attacker to search the key space " 62 "exhaustively. This should be a multiple of 1,000 and should not " 63 "exceed about 65 million; the value 0 indicates just one application " 64 "of the hashing algorithm. This value is used only to control " 65 "encryption; the correct count will automatically be selected on " 68 _algorithm = encryption_algorithm;
69 _key_length = encryption_key_length;
70 _iteration_count = encryption_iteration_count;
75 _read_overflow_buffer =
nullptr;
76 _in_read_overflow_buffer = 0;
79 char *buf =
new char[4096];
80 char *ebuf = buf + 4096;
81 setg(buf, ebuf, ebuf);
86 setg(base(), ebuf(), ebuf());
103 void EncryptStreamBuf::
104 open_read(std::istream *source,
bool owns_source,
const std::string &password) {
105 OpenSSL_add_all_algorithms();
108 _owns_source = owns_source;
110 if (_read_ctx !=
nullptr) {
111 EVP_CIPHER_CTX_free(_read_ctx);
117 int nid = sr.get_uint16();
118 int key_length = sr.get_uint16();
119 int count = sr.get_uint16();
121 const EVP_CIPHER *cipher = EVP_get_cipherbynid(nid);
123 if (cipher ==
nullptr) {
125 <<
"Unknown encryption algorithm in stream.\n";
129 _algorithm = OBJ_nid2sn(nid);
130 _key_length = key_length * 8;
131 _iteration_count = count * iteration_count_factor;
133 if (prc_cat.is_debug()) {
135 <<
"Using decryption algorithm " << _algorithm <<
" with key length " 136 << _key_length <<
" bits.\n";
138 <<
"Key is hashed " << _iteration_count <<
" extra times.\n";
141 int iv_length = EVP_CIPHER_iv_length(cipher);
142 _read_block_size = EVP_CIPHER_block_size(cipher);
144 unsigned char *iv = (
unsigned char *)alloca(iv_length);
145 iv_length = (int)sr.extract_bytes(iv, iv_length);
147 _read_ctx = EVP_CIPHER_CTX_new();
148 nassertv(_read_ctx !=
nullptr);
152 result = EVP_DecryptInit(_read_ctx, cipher,
nullptr, (
unsigned char *)iv);
153 nassertv(result > 0);
155 result = EVP_CIPHER_CTX_set_key_length(_read_ctx, key_length);
158 <<
"Invalid key length " << key_length * 8 <<
" bits for algorithm " 159 << OBJ_nid2sn(nid) <<
"\n";
160 EVP_CIPHER_CTX_free(_read_ctx);
166 unsigned char *key = (
unsigned char *)alloca(key_length);
168 PKCS5_PBKDF2_HMAC_SHA1((
const char *)password.data(), password.length(),
170 count * iteration_count_factor + 1,
172 nassertv(result > 0);
175 result = EVP_DecryptInit(_read_ctx,
nullptr, key,
nullptr);
176 nassertv(result > 0);
178 _read_overflow_buffer =
new unsigned char[_read_block_size];
179 _in_read_overflow_buffer = 0;
180 thread_consider_yield();
186 void EncryptStreamBuf::
188 if (_read_ctx !=
nullptr) {
189 EVP_CIPHER_CTX_free(_read_ctx);
193 if (_read_overflow_buffer !=
nullptr) {
194 delete[] _read_overflow_buffer;
195 _read_overflow_buffer =
nullptr;
198 if (_source !=
nullptr) {
201 _owns_source =
false;
210 void EncryptStreamBuf::
211 open_write(std::ostream *dest,
bool owns_dest,
const std::string &password) {
212 OpenSSL_add_all_algorithms();
216 _owns_dest = owns_dest;
218 const EVP_CIPHER *cipher =
219 EVP_get_cipherbyname(_algorithm.c_str());
221 if (cipher ==
nullptr) {
223 <<
"Unknown encryption algorithm: " << _algorithm <<
"\n";
227 int nid = EVP_CIPHER_nid(cipher);
229 int iv_length = EVP_CIPHER_iv_length(cipher);
230 _write_block_size = EVP_CIPHER_block_size(cipher);
234 unsigned char *iv = (
unsigned char *)alloca(iv_length);
235 RAND_bytes(iv, iv_length);
237 _write_ctx = EVP_CIPHER_CTX_new();
238 nassertv(_write_ctx !=
nullptr);
241 result = EVP_EncryptInit(_write_ctx, cipher,
nullptr, iv);
242 nassertv(result > 0);
245 int key_length = (_key_length + 7) / 8;
246 if (key_length == 0) {
247 key_length = EVP_CIPHER_key_length(cipher);
249 result = EVP_CIPHER_CTX_set_key_length(_write_ctx, key_length);
252 <<
"Invalid key length " << key_length * 8 <<
" bits for algorithm " 253 << OBJ_nid2sn(nid) <<
"\n";
254 EVP_CIPHER_CTX_free(_write_ctx);
255 _write_ctx =
nullptr;
259 int count = _iteration_count / iteration_count_factor;
261 if (prc_cat.is_debug()) {
263 <<
"Using encryption algorithm " << OBJ_nid2sn(nid) <<
" with key length " 264 << key_length * 8 <<
" bits.\n";
266 <<
"Hashing key " << count * iteration_count_factor
267 <<
" extra times.\n";
271 unsigned char *key = (
unsigned char *)alloca(key_length);
273 PKCS5_PBKDF2_HMAC_SHA1((
const char *)password.data(), password.length(),
274 iv, iv_length, count * iteration_count_factor + 1,
276 nassertv(result > 0);
279 result = EVP_EncryptInit(_write_ctx,
nullptr, key,
nullptr);
280 nassertv(result > 0);
284 nassertv((uint16_t)nid == nid);
285 sw.add_uint16((uint16_t)nid);
286 nassertv((uint16_t)key_length == key_length);
287 sw.add_uint16((uint16_t)key_length);
288 nassertv((uint16_t)count == count);
289 sw.add_uint16((uint16_t)count);
290 sw.append_data(iv, iv_length);
292 thread_consider_yield();
298 void EncryptStreamBuf::
300 if (_dest !=
nullptr) {
301 size_t n = pptr() - pbase();
302 write_chars(pbase(), n);
305 if (_write_ctx !=
nullptr) {
306 unsigned char *write_buffer = (
unsigned char *)alloca(_write_block_size);
307 int bytes_written = 0;
308 EVP_EncryptFinal(_write_ctx, write_buffer, &bytes_written);
309 thread_consider_yield();
311 _dest->write((
const char *)write_buffer, bytes_written);
313 EVP_CIPHER_CTX_free(_write_ctx);
314 _write_ctx =
nullptr;
329 int EncryptStreamBuf::
331 size_t n = pptr() - pbase();
333 write_chars(pbase(), n);
350 int EncryptStreamBuf::
352 if (_source !=
nullptr) {
353 size_t n = egptr() - gptr();
357 if (_dest !=
nullptr) {
358 size_t n = pptr() - pbase();
359 write_chars(pbase(), n);
371 int EncryptStreamBuf::
374 if (gptr() >= egptr()) {
375 size_t buffer_size = egptr() - eback();
376 gbump(-(
int)buffer_size);
378 size_t num_bytes = buffer_size;
379 size_t read_count = read_chars(gptr(), buffer_size);
381 if (read_count != num_bytes) {
383 if (read_count == 0) {
384 gbump((
int)num_bytes);
389 nassertr(read_count < num_bytes, EOF);
390 size_t delta = num_bytes - read_count;
391 memmove(gptr() + delta, gptr(), read_count);
396 return (
unsigned char)*gptr();
403 size_t EncryptStreamBuf::
404 read_chars(
char *start,
size_t length) {
409 if (_in_read_overflow_buffer != 0) {
411 length = std::min(length, _in_read_overflow_buffer);
412 memcpy(start, _read_overflow_buffer, length);
413 _in_read_overflow_buffer -= length;
414 memcpy(_read_overflow_buffer + length, _read_overflow_buffer, _in_read_overflow_buffer);
418 unsigned char *source_buffer = (
unsigned char *)alloca(length);
419 size_t max_read_buffer = length + _read_block_size;
420 unsigned char *read_buffer = (
unsigned char *)alloca(max_read_buffer);
426 if (_read_ctx ==
nullptr) {
430 _source->read((
char *)source_buffer, length);
431 size_t source_length = _source->gcount();
435 if (source_length != 0) {
437 EVP_DecryptUpdate(_read_ctx, read_buffer, &bytes_read,
438 source_buffer, source_length);
441 EVP_DecryptFinal(_read_ctx, read_buffer, &bytes_read);
442 EVP_CIPHER_CTX_free(_read_ctx);
448 <<
"Error decrypting stream.\n";
449 if (_read_ctx !=
nullptr) {
450 EVP_CIPHER_CTX_free(_read_ctx);
454 thread_consider_yield();
456 }
while (bytes_read == 0);
459 if ((
size_t)bytes_read <= length) {
461 memcpy(start, read_buffer, bytes_read);
466 _in_read_overflow_buffer = bytes_read - length;
467 nassertr(_in_read_overflow_buffer <= _read_block_size, 0);
469 memcpy(_read_overflow_buffer, read_buffer + length,
470 _in_read_overflow_buffer);
471 memcpy(start, read_buffer, length);
479 void EncryptStreamBuf::
480 write_chars(
const char *start,
size_t length) {
481 if (_write_ctx !=
nullptr && length != 0) {
482 size_t max_write_buffer = length + _write_block_size;
483 unsigned char *write_buffer = (
unsigned char *)alloca(max_write_buffer);
485 int bytes_written = 0;
487 EVP_EncryptUpdate(_write_ctx, write_buffer, &bytes_written,
488 (
unsigned char *)start, length);
491 <<
"Error encrypting stream.\n";
493 thread_consider_yield();
494 _dest->write((
const char *)write_buffer, bytes_written);
498 #endif // HAVE_OPENSSL A StreamWriter object is used to write sequential binary data directly to an ostream.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a convenience class to specialize ConfigVariable as a string type.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a convenience class to specialize ConfigVariable as an integer type.
A class to read sequential binary data directly from an istream.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.