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