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());
107 void EncryptStreamBuf::
108 open_read(std::istream *source,
bool owns_source,
const std::string &password) {
109 OpenSSL_add_all_algorithms();
112 _owns_source = owns_source;
114 if (_read_ctx !=
nullptr) {
115 EVP_CIPHER_CTX_free(_read_ctx);
121 int nid = sr.get_uint16();
122 int key_length = sr.get_uint16();
123 int count = sr.get_uint16();
125 const EVP_CIPHER *cipher = EVP_get_cipherbynid(nid);
127 if (cipher ==
nullptr) {
129 <<
"Unknown encryption algorithm in stream.\n";
133 _algorithm = OBJ_nid2sn(nid);
134 _key_length = key_length * 8;
135 _iteration_count = count * iteration_count_factor;
137 if (prc_cat.is_debug()) {
139 <<
"Using decryption algorithm " << _algorithm <<
" with key length "
140 << _key_length <<
" bits.\n";
142 <<
"Key is hashed " << _iteration_count <<
" extra times.\n";
145 int iv_length = EVP_CIPHER_iv_length(cipher);
146 _read_block_size = EVP_CIPHER_block_size(cipher);
148 unsigned char *iv = (
unsigned char *)alloca(iv_length);
149 iv_length = (int)sr.extract_bytes(iv, iv_length);
151 _read_ctx = EVP_CIPHER_CTX_new();
152 nassertv(_read_ctx !=
nullptr);
156 result = EVP_DecryptInit(_read_ctx, cipher,
nullptr, (
unsigned char *)iv);
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_free(_read_ctx);
170 unsigned char *key = (
unsigned char *)alloca(key_length);
172 PKCS5_PBKDF2_HMAC_SHA1((
const char *)password.data(), password.length(),
174 count * iteration_count_factor + 1,
176 nassertv(result > 0);
179 result = EVP_DecryptInit(_read_ctx,
nullptr, key,
nullptr);
180 nassertv(result > 0);
182 _read_overflow_buffer =
new unsigned char[_read_block_size];
183 _in_read_overflow_buffer = 0;
184 thread_consider_yield();
190 void EncryptStreamBuf::
192 if (_read_ctx !=
nullptr) {
193 EVP_CIPHER_CTX_free(_read_ctx);
197 if (_read_overflow_buffer !=
nullptr) {
198 delete[] _read_overflow_buffer;
199 _read_overflow_buffer =
nullptr;
202 if (_source !=
nullptr) {
205 _owns_source =
false;
214 void EncryptStreamBuf::
215 open_write(std::ostream *dest,
bool owns_dest,
const std::string &password) {
216 OpenSSL_add_all_algorithms();
220 _owns_dest = owns_dest;
222 const EVP_CIPHER *cipher =
223 EVP_get_cipherbyname(_algorithm.c_str());
225 if (cipher ==
nullptr) {
227 <<
"Unknown encryption algorithm: " << _algorithm <<
"\n";
231 int nid = EVP_CIPHER_nid(cipher);
233 int iv_length = EVP_CIPHER_iv_length(cipher);
234 _write_block_size = EVP_CIPHER_block_size(cipher);
238 unsigned char *iv = (
unsigned char *)alloca(iv_length);
239 RAND_bytes(iv, iv_length);
241 _write_ctx = EVP_CIPHER_CTX_new();
242 nassertv(_write_ctx !=
nullptr);
245 result = EVP_EncryptInit(_write_ctx, cipher,
nullptr, iv);
246 nassertv(result > 0);
249 int key_length = (_key_length + 7) / 8;
250 if (key_length == 0) {
251 key_length = EVP_CIPHER_key_length(cipher);
253 result = EVP_CIPHER_CTX_set_key_length(_write_ctx, key_length);
256 <<
"Invalid key length " << key_length * 8 <<
" bits for algorithm "
257 << OBJ_nid2sn(nid) <<
"\n";
258 EVP_CIPHER_CTX_free(_write_ctx);
259 _write_ctx =
nullptr;
263 int count = _iteration_count / iteration_count_factor;
265 if (prc_cat.is_debug()) {
267 <<
"Using encryption algorithm " << OBJ_nid2sn(nid) <<
" with key length "
268 << key_length * 8 <<
" bits.\n";
270 <<
"Hashing key " << count * iteration_count_factor
271 <<
" extra times.\n";
275 unsigned char *key = (
unsigned char *)alloca(key_length);
277 PKCS5_PBKDF2_HMAC_SHA1((
const char *)password.data(), password.length(),
278 iv, iv_length, count * iteration_count_factor + 1,
280 nassertv(result > 0);
283 result = EVP_EncryptInit(_write_ctx,
nullptr, key,
nullptr);
284 nassertv(result > 0);
288 nassertv((uint16_t)nid == nid);
289 sw.add_uint16((uint16_t)nid);
290 nassertv((uint16_t)key_length == key_length);
291 sw.add_uint16((uint16_t)key_length);
292 nassertv((uint16_t)count == count);
293 sw.add_uint16((uint16_t)count);
294 sw.append_data(iv, iv_length);
296 thread_consider_yield();
302 void EncryptStreamBuf::
304 if (_dest !=
nullptr) {
305 size_t n = pptr() - pbase();
306 write_chars(pbase(), n);
309 if (_write_ctx !=
nullptr) {
310 unsigned char *write_buffer = (
unsigned char *)alloca(_write_block_size);
311 int bytes_written = 0;
312 EVP_EncryptFinal(_write_ctx, write_buffer, &bytes_written);
313 thread_consider_yield();
315 _dest->write((
const char *)write_buffer, bytes_written);
317 EVP_CIPHER_CTX_free(_write_ctx);
318 _write_ctx =
nullptr;
333 int EncryptStreamBuf::
335 size_t n = pptr() - pbase();
337 write_chars(pbase(), n);
354 int EncryptStreamBuf::
356 if (_source !=
nullptr) {
357 size_t n = egptr() - gptr();
361 if (_dest !=
nullptr) {
362 size_t n = pptr() - pbase();
363 write_chars(pbase(), n);
375 int EncryptStreamBuf::
378 if (gptr() >= egptr()) {
379 size_t buffer_size = egptr() - eback();
380 gbump(-(
int)buffer_size);
382 size_t num_bytes = buffer_size;
383 size_t read_count = read_chars(gptr(), buffer_size);
385 if (read_count != num_bytes) {
387 if (read_count == 0) {
388 gbump((
int)num_bytes);
393 nassertr(read_count < num_bytes, EOF);
394 size_t delta = num_bytes - read_count;
395 memmove(gptr() + delta, gptr(), read_count);
400 return (
unsigned char)*gptr();
407 size_t EncryptStreamBuf::
408 read_chars(
char *start,
size_t length) {
413 if (_in_read_overflow_buffer != 0) {
415 length = std::min(length, _in_read_overflow_buffer);
416 memcpy(start, _read_overflow_buffer, length);
417 _in_read_overflow_buffer -= length;
418 memcpy(_read_overflow_buffer + length, _read_overflow_buffer, _in_read_overflow_buffer);
422 unsigned char *source_buffer = (
unsigned char *)alloca(length);
423 size_t max_read_buffer = length + _read_block_size;
424 unsigned char *read_buffer = (
unsigned char *)alloca(max_read_buffer);
430 if (_read_ctx ==
nullptr) {
434 _source->read((
char *)source_buffer, length);
435 size_t source_length = _source->gcount();
439 if (source_length != 0) {
441 EVP_DecryptUpdate(_read_ctx, read_buffer, &bytes_read,
442 source_buffer, source_length);
445 EVP_DecryptFinal(_read_ctx, read_buffer, &bytes_read);
446 EVP_CIPHER_CTX_free(_read_ctx);
452 <<
"Error decrypting stream.\n";
453 if (_read_ctx !=
nullptr) {
454 EVP_CIPHER_CTX_free(_read_ctx);
458 thread_consider_yield();
460 }
while (bytes_read == 0);
463 if ((
size_t)bytes_read <= length) {
465 memcpy(start, read_buffer, bytes_read);
470 _in_read_overflow_buffer = bytes_read - length;
471 nassertr(_in_read_overflow_buffer <= _read_block_size, 0);
473 memcpy(_read_overflow_buffer, read_buffer + length,
474 _in_read_overflow_buffer);
475 memcpy(start, read_buffer, length);
483 void EncryptStreamBuf::
484 write_chars(
const char *start,
size_t length) {
485 if (_write_ctx !=
nullptr && length != 0) {
486 size_t max_write_buffer = length + _write_block_size;
487 unsigned char *write_buffer = (
unsigned char *)alloca(max_write_buffer);
489 int bytes_written = 0;
491 EVP_EncryptUpdate(_write_ctx, write_buffer, &bytes_written,
492 (
unsigned char *)start, length);
495 <<
"Error encrypting stream.\n";
497 thread_consider_yield();
498 _dest->write((
const char *)write_buffer, bytes_written);
This is a convenience class to specialize ConfigVariable as an integer type.
This is a convenience class to specialize ConfigVariable as a string type.
A class to read sequential binary data directly from an istream.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.