From 18ced11d6cdca0071111a1018206a232f535ece7 Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 9 Dec 2004 21:20:23 +0000 Subject: [PATCH] convert express to new config system; add more options to pencrypt and OEncryptStream --- panda/src/downloadertools/multify.cxx | 2 +- panda/src/downloadertools/pencrypt.cxx | 58 ++++- panda/src/express/Sources.pp | 4 +- panda/src/express/clockObject.cxx | 60 ++++- panda/src/express/clockObject.h | 3 + panda/src/express/config_express.cxx | 304 ++++++++++++------------ panda/src/express/config_express.h | 34 +-- panda/src/express/encryptStream.I | 88 +++++++ panda/src/express/encryptStream.h | 8 + panda/src/express/encryptStreamBuf.I | 110 +++++++++ panda/src/express/encryptStreamBuf.cxx | 38 ++- panda/src/express/encryptStreamBuf.h | 15 ++ panda/src/express/memoryUsage.cxx | 22 +- panda/src/express/multifile.cxx | 7 +- panda/src/express/textEncoder.cxx | 49 +++- panda/src/express/textEncoder.h | 6 +- panda/src/express/virtualFileSystem.cxx | 113 +++++---- 17 files changed, 658 insertions(+), 263 deletions(-) create mode 100644 panda/src/express/encryptStreamBuf.I diff --git a/panda/src/downloadertools/multify.cxx b/panda/src/downloadertools/multify.cxx index c672b1d5e9..3f4511e774 100644 --- a/panda/src/downloadertools/multify.cxx +++ b/panda/src/downloadertools/multify.cxx @@ -131,7 +131,7 @@ help() { " encrypted using different passwords (although this requires running\n" " multify multiple times). It is not possible to encrypt the multifile's\n" " table of contents using this interface, but see the pencrypt program to\n" - " encrypt the entire multifile after it has been generated).\n\n" + " encrypt the entire multifile after it has been generated.\n\n" " -p \"password\"\n" diff --git a/panda/src/downloadertools/pencrypt.cxx b/panda/src/downloadertools/pencrypt.cxx index 039619d016..acb12ff4a3 100644 --- a/panda/src/downloadertools/pencrypt.cxx +++ b/panda/src/downloadertools/pencrypt.cxx @@ -46,17 +46,44 @@ usage() { << " Specifies the password to use for encryption. There are no\n" << " restrictions on the password length or contents, but longer passwords\n" << " are more secure. If this is not specified, the user is prompted from\n" - << " standard input.\n\n"; + << " standard input.\n\n" + + << " -a \"algorithm\"\n" + << " Specifies the particular encryption algorithm to use. The complete\n" + << " set of available algorithms is defined by the current version of\n" + << " OpenSSL. The default algorithm is taken from the encryption-\n" + << " algorithm config variable.\n\n" + + << " -k key_length\n" + << " Specifies the key length, in bits, for the selected encryption\n" + << " algorithm. This only makes sense for those algorithms that support\n" + << " a variable key length. The default value is taken from the\n" + << " encryption-key-length config variable.\n\n" + + << " -i iteration_count\n" + << " Specifies the number of times the password is hashed to generate\n" + << " a key. The only purpose of this is to make it computationally\n" + << " more expensive for an attacker to search the key space exhaustively.\n" + << " This should be a multiple of 1,000 and should not exceed about 65\n" + << " million; the value 0 indicates just one application of the hashing\n" + << " algorithm. The default value is taken from the encryption-iteration-\n" + << " count config variable.\n\n"; } int main(int argc, char *argv[]) { extern char *optarg; extern int optind; - const char *optstr = "p:h"; + const char *optstr = "p:a:k:i:h"; string password; bool got_password = false; + string algorithm; + bool got_algorithm = false; + int key_length = 0; + bool got_key_length = false; + int iteration_count = 0; + bool got_iteration_count = false; int flag = getopt(argc, argv, optstr); @@ -67,6 +94,21 @@ main(int argc, char *argv[]) { got_password = true; break; + case 'a': + algorithm = optarg; + got_algorithm = true; + break; + + case 'k': + key_length = atoi(optarg); + got_key_length = true; + break; + + case 'i': + iteration_count = atoi(optarg); + got_iteration_count = true; + break; + case 'h': case '?': default: @@ -119,7 +161,17 @@ main(int argc, char *argv[]) { bool fail = false; { - OEncryptStream encrypt(&write_stream, false, password); + OEncryptStream encrypt; + if (got_algorithm) { + encrypt.set_algorithm(algorithm); + } + if (got_key_length) { + encrypt.set_key_length(key_length); + } + if (got_iteration_count) { + encrypt.set_iteration_count(iteration_count); + } + encrypt.open(&write_stream, false, password); int ch = read_stream.get(); while (!read_stream.eof() && !read_stream.fail()) { diff --git a/panda/src/express/Sources.pp b/panda/src/express/Sources.pp index b5cf7a01fc..b0c4d5d235 100644 --- a/panda/src/express/Sources.pp +++ b/panda/src/express/Sources.pp @@ -23,7 +23,7 @@ datagramGenerator.h \ datagramIterator.I datagramIterator.h datagramSink.I datagramSink.h \ dcast.T dcast.h \ - encryptStreamBuf.h encryptStream.h encryptStream.I \ + encryptStreamBuf.h encryptStreamBuf.I encryptStream.h encryptStream.I \ error_utils.h \ get_config_path.h \ hashGeneratorBase.I hashGeneratorBase.h \ @@ -144,7 +144,7 @@ datagramGenerator.I datagramGenerator.h \ datagramIterator.I datagramIterator.h \ datagramSink.I datagramSink.h dcast.T dcast.h \ - encryptStreamBuf.h encryptStream.h encryptStream.I \ + encryptStreamBuf.h encryptStreamBuf.I encryptStream.h encryptStream.I \ error_utils.h get_config_path.h \ hashGeneratorBase.I \ hashGeneratorBase.h hashVal.I hashVal.h \ diff --git a/panda/src/express/clockObject.cxx b/panda/src/express/clockObject.cxx index 66ff9381eb..535d7ab7b1 100644 --- a/panda/src/express/clockObject.cxx +++ b/panda/src/express/clockObject.cxx @@ -19,6 +19,7 @@ #include "clockObject.h" #include "config_express.h" +#include "configVariableEnum.h" #if defined(WIN32) #define WINDOWS_LEAN_AND_MEAN @@ -243,10 +244,12 @@ void ClockObject:: make_global_clock() { nassertv(_global_clock == (ClockObject *)NULL); - // Make sure we have run init_libexpress() by this time. This - // function is responsible for initializing the clock_mode Configrc - // variable. - init_libexpress(); + ConfigVariableEnum clock_mode + ("clock-mode", ClockObject::M_normal, + "Specifies the mode of the global clock. The default mode, normal, " + "is a real-time clock; other modes allow non-real-time special " + "effects like simulated reduced frame rate. See " + "ClockObject::set_mode()."); _global_clock = new ClockObject; _global_clock->set_mode(clock_mode); @@ -259,3 +262,52 @@ make_global_clock() { void get_time_of_day(TimeVal &tv) { get_true_time_of_day(tv.tv[0], tv.tv[1]); } + +//////////////////////////////////////////////////////////////////// +// Function: ClockObject::Mode ostream operator +// Description: +//////////////////////////////////////////////////////////////////// +ostream & +operator << (ostream &out, ClockObject::Mode mode) { + switch (mode) { + case ClockObject::M_normal: + return out << "normal"; + + case ClockObject::M_non_real_time: + return out << "non-real-time"; + + case ClockObject::M_forced: + return out << "forced"; + + case ClockObject::M_degrade: + return out << "degrade"; + }; + + return out << "**invalid ClockObject::Mode(" << (int)mode << ")**"; +} + +//////////////////////////////////////////////////////////////////// +// Function: ClockObject::Mode istream operator +// Description: +//////////////////////////////////////////////////////////////////// +istream & +operator >> (istream &in, ClockObject::Mode &mode) { + string word; + in >> word; + + if (word == "normal") { + mode = ClockObject::M_normal; + } else if (word == "non-real-time") { + mode = ClockObject::M_non_real_time; + } else if (word == "forced") { + mode = ClockObject::M_forced; + } else if (word == "degrade") { + mode = ClockObject::M_degrade; + } else { + express_cat.error() + << "Invalid ClockObject::Mode: " << word << "\n"; + mode = ClockObject::M_normal; + } + + return in; +} diff --git a/panda/src/express/clockObject.h b/panda/src/express/clockObject.h index a5cddaa4ff..aec8ec787c 100644 --- a/panda/src/express/clockObject.h +++ b/panda/src/express/clockObject.h @@ -132,6 +132,9 @@ private: static ClockObject *_global_clock; }; +ostream &operator << (ostream &out, ClockObject::Mode mode); +istream &operator >> (istream &in, ClockObject::Mode &mode); + #include "clockObject.I" #endif diff --git a/panda/src/express/config_express.cxx b/panda/src/express/config_express.cxx index 357e05d55a..e477d024e0 100644 --- a/panda/src/express/config_express.cxx +++ b/panda/src/express/config_express.cxx @@ -43,83 +43,94 @@ ConfigureFn(config_express) { init_libexpress(); } -const int patchfile_window_size = - config_express.GetInt("patchfile-window-size", 16); +ConfigVariableInt patchfile_window_size +("patchfile-window-size", 16); -const int patchfile_increment_size = - config_express.GetInt("patchfile-increment-size", 8); +ConfigVariableInt patchfile_increment_size +("patchfile-increment-size", 8); -const int patchfile_buffer_size = - config_express.GetInt("patchfile-buffer-size", 4096); +ConfigVariableInt patchfile_buffer_size +("patchfile-buffer-size", 4096); -const int patchfile_zone_size = - config_express.GetInt("patchfile-zone-size", 10000); +ConfigVariableInt patchfile_zone_size +("patchfile-zone-size", 10000); -// Set this true to keep around the temporary files from downloading, -// decompressing, and patching, or false (the default) to delete -// these. Mainly useful for debugging when the process goes wrong. -const bool keep_temporary_files = -config_express.GetBool("keep-temporary-files", false); +ConfigVariableBool keep_temporary_files +("keep-temporary-files", false, + "Set this true to keep around the temporary files from downloading, " + "decompressing, and patching, or false (the default) to delete " + "these. Mainly useful for debugging when the process goes wrong."); -const double average_frame_rate_interval = -config_express.GetDouble("average-frame-rate-interval", 1.0); +ConfigVariableDouble average_frame_rate_interval +("average-frame-rate-interval", 1.0); -ClockObject::Mode clock_mode = ClockObject::M_normal; -const double clock_frame_rate = -config_express.GetDouble("clock-frame-rate", 1.0); -const double clock_degrade_factor = -config_express.GetDouble("clock-degrade-factor", 1.0); -const double max_dt = -config_express.GetDouble("max-dt", -1.0); +ConfigVariableDouble clock_frame_rate +("clock-frame-rate", 1.0); +ConfigVariableDouble clock_degrade_factor +("clock-degrade-factor", 1.0); +ConfigVariableDouble max_dt +("max-dt", -1.0); -// This is the accuracy within which we can expect select() to return -// precisely. That is, if we use select() to request a timeout of 1.0 -// seconds, we can expect to actually sleep for somewhere between 1.0 -// and 1.0 + sleep-precision seconds. -const double sleep_precision = -config_express.GetDouble("sleep-precision", 0.01); +ConfigVariableDouble sleep_precision +("sleep-precision", 0.01, + "This is the accuracy within which we can expect select() to return " + "precisely. That is, if we use select() to request a timeout of 1.0 " + "seconds, we can expect to actually sleep for somewhere between 1.0 " + "and 1.0 + sleep-precision seconds."); -// This defines the OpenSSL encryption algorithm which is used to -// encrypt any streams created by the current runtime. The default is -// Blowfish; the complete set of available algorithms is defined by -// the current version of OpenSSL. This value is used only to control -// encryption; the correct algorithm will automatically be selected on -// decryption. -const string encryption_algorithm = -config_express.GetString("encryption-algorithm", "bf-cbc"); +ConfigVariableString encryption_algorithm +("encryption-algorithm", "bf-cbc", + "This defines the OpenSSL encryption algorithm which is used to " + "encrypt any streams created by the current runtime. The default is " + "Blowfish; the complete set of available algorithms is defined by " + "the current version of OpenSSL. This value is used only to control " + "encryption; the correct algorithm will automatically be selected on " + "decryption."); -// This defines the key length, in bits, for the selected encryption -// algorithm. Some algorithms have a variable key length. Specifying -// a value of 0 here means to use the default key length for the -// algorithm as defined by OpenSSL. This value is used only to -// control encryption; the correct key length will automatically be -// selected on decryption. -const int encryption_key_length = -config_express.GetInt("encryption-key-length", 0); +ConfigVariableInt encryption_key_length +("encryption-key-length", 0, + "This defines the key length, in bits, for the selected encryption " + "algorithm. Some algorithms have a variable key length. Specifying " + "a value of 0 here means to use the default key length for the " + "algorithm as defined by OpenSSL. This value is used only to " + "control encryption; the correct key length will automatically be " + "selected on decryption."); -// This defines the number of times a password is hashed to generate a -// key when encrypting. Its purpose is to make it computationally -// more expensive for an attacker to search the key space -// exhaustively. This should be a multiple of 1,000 and should not -// exceed about 65 million; the value 0 indicates just one application -// of the hashing algorithm. This value is used only to control -// encryption; the correct count will automatically be selected on -// decryption. -const int encryption_iteration_count = -config_express.GetInt("encryption-iteration-count", 100000); +ConfigVariableInt encryption_iteration_count +("encryption-iteration-count", 100000, + "This defines the number of times a password is hashed to generate a " + "key when encrypting. Its purpose is to make it computationally " + "more expensive for an attacker to search the key space " + "exhaustively. This should be a multiple of 1,000 and should not " + "exceed about 65 million; the value 0 indicates just one application " + "of the hashing algorithm. This value is used only to control " + "encryption; the correct count will automatically be selected on " + "decryption."); -// Set this true to use the VirtualFileSystem mechanism for loading -// models, etc. Since the VirtualFileSystem maps to the same as the -// actual file system by default, there is probably no reason to set -// this false, except for testing or if you mistrust the new code. -const bool use_vfs = config_express.GetBool("use-vfs", true); +ConfigVariableInt multifile_encryption_iteration_count +("multifile-encryption-iteration-count", 0, + "This is a special value of encryption-iteration-count used to encrypt " + "subfiles within a multifile. It has a default value of 0 (just one " + "application), on the assumption that the files from a multifile must " + "be loaded quickly, without paying the cost of an expensive hash on " + "each subfile in order to decrypt it."); -// Set this true to enable accumulation of several small consecutive -// TCP datagrams into one large datagram before sending it, to reduce -// overhead from the TCP/IP protocol. See -// Connection::set_collect_tcp() or SocketStream::set_collect_tcp(). -const bool collect_tcp = config_express.GetBool("collect-tcp", false); -const double collect_tcp_interval = config_express.GetDouble("collect-tcp-interval", 0.2); +ConfigVariableBool use_vfs +("use-vfs", true, + "Set this true to use the VirtualFileSystem mechanism for loading " + "models, etc. Since the VirtualFileSystem maps to the same as the " + "actual file system by default, there is probably no reason to set " + "this false, except for testing or if you mistrust the new code."); + +ConfigVariableBool collect_tcp +("collect-tcp", false, + "Set this true to enable accumulation of several small consecutive " + "TCP datagrams into one large datagram before sending it, to reduce " + "overhead from the TCP/IP protocol. See " + "Connection::set_collect_tcp() or SocketStream::set_collect_tcp()."); + +ConfigVariableDouble collect_tcp_interval +("collect-tcp-interval", 0.2); //////////////////////////////////////////////////////////////////// // Function: init_libexpress @@ -151,115 +162,104 @@ init_libexpress() { VirtualFileSimple::init_type(); init_system_type_handles(); - - string text_encoding = config_express.GetString("text-encoding", "iso8859"); - if (text_encoding == "iso8859") { - TextEncoder::set_default_encoding(TextEncoder::E_iso8859); - } else if (text_encoding == "utf8") { - TextEncoder::set_default_encoding(TextEncoder::E_utf8); - } else if (text_encoding == "unicode") { - TextEncoder::set_default_encoding(TextEncoder::E_unicode); - } else { - express_cat.error() - << "Invalid text-encoding: " << text_encoding << "\n"; - } - - string clock_mode_str = config_express.GetString("clock-mode", "normal"); - if (clock_mode_str == "normal") { - clock_mode = ClockObject::M_normal; - } else if (clock_mode_str == "non-real-time") { - clock_mode = ClockObject::M_non_real_time; - } else if (clock_mode_str == "forced") { - clock_mode = ClockObject::M_forced; - } else if (clock_mode_str == "degrade") { - clock_mode = ClockObject::M_degrade; - } else { - express_cat.error() - << "Invalid clock-mode: " << clock_mode_str << "\n"; - } } -// Set leak-memory true to disable the actual deletion of -// ReferenceCount-derived objects. This is sometimes useful to track -// a reference counting bug, since the formerly deleted objects will -// still remain (with a reference count of -100) without being -// overwritten with a newly-allocated object, and the assertion tests -// in ReferenceCount may more accurately detect the first instance of -// an error. bool get_leak_memory() { - static bool got_leak_memory = false; - static bool leak_memory; + static ConfigVariableBool *leak_memory = NULL; - if (!got_leak_memory) { - leak_memory = config_express.GetBool("leak-memory", false); - got_leak_memory = true; + if (leak_memory == (ConfigVariableBool *)NULL) { + leak_memory = new ConfigVariableBool + ("leak-memory", false, + "Set leak-memory true to disable the actual deletion of " + "ReferenceCount-derived objects. This is sometimes useful to track " + "a reference counting bug, since the formerly deleted objects will " + "still remain (with a reference count of -100) without being " + "overwritten with a newly-allocated object, and the assertion tests " + "in ReferenceCount may more accurately detect the first instance of " + "an error."); } - return leak_memory; + return *leak_memory; } -// never-destruct is similar to leak-memory, above, except that not -// only will memory not be freed, but the destructor will not even be -// called (on ReferenceCount objects, at least). This will leak gobs -// of memory, but ensures that every pointer to a ReferenceCount -// object will always be valid, and may be useful for tracking down -// certain kinds of errors. - -// never-destruct is only respected if leak-memory, above, is true. bool get_never_destruct() { - static bool got_never_destruct = false; - static bool never_destruct; + static ConfigVariableBool *never_destruct = NULL; - if (!got_never_destruct) { - never_destruct = config_express.GetBool("never-destruct", false); - got_never_destruct = true; + if (never_destruct == (ConfigVariableBool *)NULL) { + never_destruct = new ConfigVariableBool + ("never-destruct", false, + "never-destruct is similar to leak-memory, except that not " + "only will memory not be freed, but the destructor will not even be " + "called (on ReferenceCount objects, at least). This will leak gobs " + "of memory, but ensures that every pointer to a ReferenceCount " + "object will always be valid, and may be useful for tracking down " + "certain kinds of errors. " + "never-destruct is only respected if leak-memory is true."); } - return never_destruct; + return *never_destruct; } -//const bool track_memory_usage = config_express.GetBool("track-memory-usage", false); - -// Set this to false to avoid using the high-precision clock, even if -// it is available. bool get_use_high_res_clock() { - return config_express.GetBool("use-high-res-clock", true); -} + static ConfigVariableBool *use_high_res_clock = NULL; -// Set this to true to double-check the results of the high-resolution -// clock against the system clock. This has no effect if NDEBUG is -// defined. -bool -get_paranoid_clock() { - return config_express.GetBool("paranoid-clock", false); -} - -// Set this to true to double-check the test for inheritance of -// TypeHandles, e.g. via is_of_type(). This has no effect if NDEBUG -// is defined. -bool -get_paranoid_inheritance() { - return config_express.GetBool("paranoid-inheritance", true); -} - -// Set this to true to verify that every attempted DCAST operation in -// fact references the correct type, or false otherwise. This has no -// effect if NDEBUG is defined, in which case it is never tested. -bool -get_verify_dcast() { - static bool got_verify_dcast = false; - static bool verify_dcast; - - if (!got_verify_dcast) { - verify_dcast = config_express.GetBool("verify-dcast", true); - got_verify_dcast = true; + if (use_high_res_clock == (ConfigVariableBool *)NULL) { + use_high_res_clock = new ConfigVariableBool + ("use-high-res-clock", true, + "Set this to false to avoid using the high-precision clock, even if " + "it is available."); } - return verify_dcast; + return *use_high_res_clock; +} + +bool +get_paranoid_clock() { + static ConfigVariableBool *paranoid_clock = NULL; + + if (paranoid_clock == (ConfigVariableBool *)NULL) { + paranoid_clock = new ConfigVariableBool + ("paranoid-clock", false, + "Set this to true to double-check the results of the high-resolution " + "clock against the system clock. This has no effect if NDEBUG is " + "defined."); + } + + return *paranoid_clock; +} + +bool +get_paranoid_inheritance() { + static ConfigVariableBool *paranoid_inheritance = NULL; + + if (paranoid_inheritance == (ConfigVariableBool *)NULL) { + paranoid_inheritance = new ConfigVariableBool + ("paranoid-inheritance", true, + "Set this to true to double-check the test for inheritance of " + "TypeHandles, e.g. via is_of_type(). This has no effect if NDEBUG " + "is defined."); + } + + return *paranoid_inheritance; +} + +bool +get_verify_dcast() { + static ConfigVariableBool *verify_dcast = NULL; + + if (verify_dcast == (ConfigVariableBool *)NULL) { + verify_dcast = new ConfigVariableBool + ("verify-dcast", true, + "Set this to true to verify that every attempted DCAST operation in " + "fact references the correct type, or false otherwise. This has no " + "effect if NDEBUG is defined, in which case it is never tested."); + } + + return *verify_dcast; } // Returns the configure object for accessing config variables from a diff --git a/panda/src/express/config_express.h b/panda/src/express/config_express.h index c1709e9008..9827b8e775 100644 --- a/panda/src/express/config_express.h +++ b/panda/src/express/config_express.h @@ -59,28 +59,28 @@ EXPCL_PANDAEXPRESS bool get_paranoid_clock(); EXPCL_PANDAEXPRESS bool get_paranoid_inheritance(); EXPCL_PANDAEXPRESS bool get_verify_dcast(); -extern const int patchfile_window_size; -extern const int patchfile_increment_size; -extern const int patchfile_buffer_size; -extern const int patchfile_zone_size; +extern ConfigVariableInt patchfile_window_size; +extern ConfigVariableInt patchfile_increment_size; +extern ConfigVariableInt patchfile_buffer_size; +extern ConfigVariableInt patchfile_zone_size; -extern const bool keep_temporary_files; -extern const double average_frame_rate_interval; +extern ConfigVariableBool keep_temporary_files; +extern ConfigVariableDouble average_frame_rate_interval; -extern ClockObject::Mode clock_mode; -extern const double clock_frame_rate; -extern const double clock_degrade_factor; -extern const double max_dt; -extern const double sleep_precision; +extern ConfigVariableDouble clock_frame_rate; +extern ConfigVariableDouble clock_degrade_factor; +extern ConfigVariableDouble max_dt; +extern ConfigVariableDouble sleep_precision; -extern const string encryption_algorithm; -extern const int encryption_key_length; -extern const int encryption_iteration_count; +extern ConfigVariableString encryption_algorithm; +extern ConfigVariableInt encryption_key_length; +extern ConfigVariableInt encryption_iteration_count; +extern ConfigVariableInt multifile_encryption_iteration_count; -extern EXPCL_PANDAEXPRESS const bool use_vfs; +extern EXPCL_PANDAEXPRESS ConfigVariableBool use_vfs; -extern EXPCL_PANDAEXPRESS const bool collect_tcp; -extern EXPCL_PANDAEXPRESS const double collect_tcp_interval; +extern EXPCL_PANDAEXPRESS ConfigVariableBool collect_tcp; +extern EXPCL_PANDAEXPRESS ConfigVariableDouble collect_tcp_interval; // Expose the Config variable for Python access. BEGIN_PUBLISH diff --git a/panda/src/express/encryptStream.I b/panda/src/express/encryptStream.I index 23871cb234..c8e2ffd521 100644 --- a/panda/src/express/encryptStream.I +++ b/panda/src/express/encryptStream.I @@ -61,6 +61,38 @@ close() { return *this; } +//////////////////////////////////////////////////////////////////// +// Function: IDecryptStream::get_algorithm +// Access: Public +// Description: Returns the encryption algorithm that was read from +// the stream. +//////////////////////////////////////////////////////////////////// +INLINE const string &IDecryptStream:: +get_algorithm() const { + return _buf.get_algorithm(); +} + +//////////////////////////////////////////////////////////////////// +// Function: IDecryptStream::get_key_length +// Access: Public +// Description: Returns the encryption key length, in bits, that was +// read from the stream. +//////////////////////////////////////////////////////////////////// +INLINE int IDecryptStream:: +get_key_length() const { + return _buf.get_key_length(); +} + +//////////////////////////////////////////////////////////////////// +// Function: IDecryptStream::get_iteration_count +// Access: Public +// Description: Returns the value that was was read from the stream. +//////////////////////////////////////////////////////////////////// +INLINE int IDecryptStream:: +get_iteration_count() const { + return _buf.get_iteration_count(); +} + //////////////////////////////////////////////////////////////////// // Function: OEncryptStream::Constructor @@ -107,3 +139,59 @@ close() { return *this; } + +//////////////////////////////////////////////////////////////////// +// Function: OEncryptStream::set_algorithm +// Access: Public +// Description: Specifies the encryption algorithm that should be +// used for future calls to open(). The default +// is whatever is specified by the encryption-algorithm +// config variable. The complete set of available +// algorithms is defined by the current version of +// OpenSSL. +// +// If an invalid algorithm is specified, there is no +// immediate error return code, but open() will +// fail. +//////////////////////////////////////////////////////////////////// +INLINE void OEncryptStream:: +set_algorithm(const string &algorithm) { + _buf.set_algorithm(algorithm); +} + +//////////////////////////////////////////////////////////////////// +// Function: OEncryptStream::set_key_length +// Access: Public +// Description: Specifies the length of the key, in bits, that should +// be used to encrypt the stream in future calls to +// open(). The default is whatever is specified +// by the encryption-key-length config variable. +// +// If an invalid key_length for the chosen algorithm is +// specified, there is no immediate error return code, +// but open() will fail. +//////////////////////////////////////////////////////////////////// +INLINE void OEncryptStream:: +set_key_length(int key_length) { + _buf.set_key_length(key_length); +} + +//////////////////////////////////////////////////////////////////// +// Function: OEncryptStream::set_iteration_count +// Access: Public +// Description: Specifies the number of times to repeatedly hash the +// key before writing it to the stream in future calls +// to open(). Its purpose is to make it +// computationally more expensive for an attacker to +// search the key space exhaustively. This should be a +// multiple of 1,000 and should not exceed about 65 +// million; the value 0 indicates just one application +// of the hashing algorithm. +// +// The default is whatever is specified by the +// encryption-iteration-count config variable. +//////////////////////////////////////////////////////////////////// +INLINE void OEncryptStream:: +set_iteration_count(int iteration_count) { + _buf.set_iteration_count(iteration_count); +} diff --git a/panda/src/express/encryptStream.h b/panda/src/express/encryptStream.h index 60ef9be259..96680a9974 100644 --- a/panda/src/express/encryptStream.h +++ b/panda/src/express/encryptStream.h @@ -48,6 +48,10 @@ public: const string &password); INLINE IDecryptStream &close(); + INLINE const string &get_algorithm() const; + INLINE int get_key_length() const; + INLINE int get_iteration_count() const; + private: EncryptStreamBuf _buf; }; @@ -73,6 +77,10 @@ public: const string &password); INLINE OEncryptStream &close(); + INLINE void set_algorithm(const string &algorithm); + INLINE void set_key_length(int key_length); + INLINE void set_iteration_count(int iteration_count); + private: EncryptStreamBuf _buf; }; diff --git a/panda/src/express/encryptStreamBuf.I b/panda/src/express/encryptStreamBuf.I new file mode 100644 index 0000000000..c335501b43 --- /dev/null +++ b/panda/src/express/encryptStreamBuf.I @@ -0,0 +1,110 @@ +// Filename: encryptStreamBuf.I +// Created by: drose (09Dec04) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: EncryptStreamBuf::set_algorithm +// Access: Public +// Description: Specifies the encryption algorithm that should be +// used for future calls to open_write(). The default +// is whatever is specified by the encryption-algorithm +// config variable. The complete set of available +// algorithms is defined by the current version of +// OpenSSL. +// +// If an invalid algorithm is specified, there is no +// immediate error return code, but open_write() will +// fail. +//////////////////////////////////////////////////////////////////// +INLINE void EncryptStreamBuf:: +set_algorithm(const string &algorithm) { + _algorithm = algorithm; +} + +//////////////////////////////////////////////////////////////////// +// Function: EncryptStreamBuf::get_algorithm +// Access: Public +// Description: Returns the encryption algorithm that was specified +// by set_algorithm(), or was read from the stream by +// the last successful open_read(). +//////////////////////////////////////////////////////////////////// +INLINE const string &EncryptStreamBuf:: +get_algorithm() const { + return _algorithm; +} + +//////////////////////////////////////////////////////////////////// +// Function: EncryptStreamBuf::set_key_length +// Access: Public +// Description: Specifies the length of the key, in bits, that should +// be used to encrypt the stream in future calls to +// open_write(). The default is whatever is specified +// by the encryption-key-length config variable. +// +// If an invalid key_length for the chosen algorithm is +// specified, there is no immediate error return code, +// but open_write() will fail. +//////////////////////////////////////////////////////////////////// +INLINE void EncryptStreamBuf:: +set_key_length(int key_length) { + _key_length = key_length; +} + +//////////////////////////////////////////////////////////////////// +// Function: EncryptStreamBuf::get_key_length +// Access: Public +// Description: Returns the encryption key length, in bits, that was +// specified by set_key_length(), or was read from the +// stream by the last successful open_read(). +//////////////////////////////////////////////////////////////////// +INLINE int EncryptStreamBuf:: +get_key_length() const { + return _key_length; +} + +//////////////////////////////////////////////////////////////////// +// Function: EncryptStreamBuf::set_iteration_count +// Access: Public +// Description: Specifies the number of times to repeatedly hash the +// key before writing it to the stream in future calls +// to open_write(). Its purpose is to make it +// computationally more expensive for an attacker to +// search the key space exhaustively. This should be a +// multiple of 1,000 and should not exceed about 65 +// million; the value 0 indicates just one application +// of the hashing algorithm. +// +// The default is whatever is specified by the +// encryption-iteration-count config variable. +//////////////////////////////////////////////////////////////////// +INLINE void EncryptStreamBuf:: +set_iteration_count(int iteration_count) { + _iteration_count = iteration_count; +} + +//////////////////////////////////////////////////////////////////// +// Function: EncryptStreamBuf::get_iteration_count +// Access: Public +// Description: Returns the value that was specified by +// set_iteration_count(), or was read from the stream by +// the last successful open_read(). +//////////////////////////////////////////////////////////////////// +INLINE int EncryptStreamBuf:: +get_iteration_count() const { + return _iteration_count; +} diff --git a/panda/src/express/encryptStreamBuf.cxx b/panda/src/express/encryptStreamBuf.cxx index ded0c3e138..7a0d080789 100644 --- a/panda/src/express/encryptStreamBuf.cxx +++ b/panda/src/express/encryptStreamBuf.cxx @@ -46,6 +46,10 @@ EncryptStreamBuf() { _dest = (ostream *)NULL; _owns_dest = false; + _algorithm = encryption_algorithm; + _key_length = encryption_key_length; + _iteration_count = encryption_iteration_count; + _read_valid = false; _write_valid = false; @@ -103,9 +107,17 @@ open_read(istream *source, bool owns_source, const string &password) { return; } - express_cat.debug() - << "Using decryption algorithm " << OBJ_nid2sn(nid) << " with key length " - << key_length * 8 << " bits.\n"; + _algorithm = OBJ_nid2sn(nid); + _key_length = key_length * 8; + _iteration_count = count * iteration_count_factor; + + if (express_cat.is_debug()) { + express_cat.debug() + << "Using decryption algorithm " << _algorithm << " with key length " + << _key_length << " bits.\n"; + express_cat.debug() + << "Key is hashed " << _iteration_count << " extra times.\n"; + } int iv_length = EVP_CIPHER_iv_length(cipher); _read_block_size = EVP_CIPHER_block_size(cipher); @@ -186,11 +198,11 @@ open_write(ostream *dest, bool owns_dest, const string &password) { _write_valid = false; const EVP_CIPHER *cipher = - EVP_get_cipherbyname(encryption_algorithm.c_str()); + EVP_get_cipherbyname(_algorithm.c_str()); if (cipher == NULL) { express_cat.error() - << "Unknown encryption algorithm: " << encryption_algorithm << "\n"; + << "Unknown encryption algorithm: " << _algorithm << "\n"; return; }; @@ -210,7 +222,7 @@ open_write(ostream *dest, bool owns_dest, const string &password) { nassertv(result > 0); // Store the appropriate key length in the context. - int key_length = (encryption_key_length + 7) / 8; + int key_length = (_key_length + 7) / 8; if (key_length == 0) { key_length = EVP_CIPHER_CTX_key_length(cipher); } @@ -223,12 +235,18 @@ open_write(ostream *dest, bool owns_dest, const string &password) { return; } - express_cat.debug() - << "Using encryption algorithm " << OBJ_nid2sn(nid) << " with key length " - << key_length * 8 << " bits.\n"; + int count = _iteration_count / iteration_count_factor; + + if (express_cat.is_debug()) { + express_cat.debug() + << "Using encryption algorithm " << OBJ_nid2sn(nid) << " with key length " + << key_length * 8 << " bits.\n"; + express_cat.debug() + << "Hashing key " << count * iteration_count_factor + << " extra times.\n"; + } // Hash the supplied password into a key of the appropriate length. - int count = encryption_iteration_count / iteration_count_factor; unsigned char *key = (unsigned char *)alloca(key_length); result = PKCS5_PBKDF2_HMAC_SHA1((const char *)password.data(), password.length(), diff --git a/panda/src/express/encryptStreamBuf.h b/panda/src/express/encryptStreamBuf.h index c7febf95f8..6e63c1f59c 100644 --- a/panda/src/express/encryptStreamBuf.h +++ b/panda/src/express/encryptStreamBuf.h @@ -42,6 +42,15 @@ public: void open_write(ostream *dest, bool owns_dest, const string &password); void close_write(); + INLINE void set_algorithm(const string &algorithm); + INLINE const string &get_algorithm() const; + + INLINE void set_key_length(int key_length); + INLINE int get_key_length() const; + + INLINE void set_iteration_count(int iteration_count); + INLINE int get_iteration_count() const; + protected: virtual int overflow(int c); virtual int sync(void); @@ -57,6 +66,10 @@ private: ostream *_dest; bool _owns_dest; + + string _algorithm; + int _key_length; + int _iteration_count; bool _read_valid; EVP_CIPHER_CTX _read_ctx; @@ -69,6 +82,8 @@ private: size_t _write_block_size; }; +#include "encryptStreamBuf.I" + #endif // HAVE_SSL #endif diff --git a/panda/src/express/memoryUsage.cxx b/panda/src/express/memoryUsage.cxx index ec0d946cba..d1d3057787 100644 --- a/panda/src/express/memoryUsage.cxx +++ b/panda/src/express/memoryUsage.cxx @@ -379,19 +379,19 @@ MemoryUsage() { // time, and who knows when the code in config_express will be // executed. - // track-memory-usage should be true to enable full-force tracking - // of C++ allocations and recordkeeping by type. It's quite - // expensive. - _track_memory_usage = - config_express.GetBool("track-memory-usage", false); + _track_memory_usage = ConfigVariableBool + ("track-memory-usage", false, + "Set this to true to enable full-force tracking of C++ allocations " + "and recordkeeping by type. It's quite expensive."); - // count-memory-usage is a much lighter-weight version, and only - // tracks the total memory allocation. However, it only works for - // certain build environments (in particular, only in an Opt1 or - // Opt2 build on Windows). #if defined(WIN32_VC) && defined(_DEBUG) - _count_memory_usage = config_express.GetBool("count-memory-usage", - _track_memory_usage); + _count_memory_usage = ConfigVariableBool + ("count-memory-usage", _track_memory_usage, + "This is a much lighter-weight version of track-memory-usage, and it " + "only tracks the total memory allocation. However, it only exists in " + "certain build environments (in particular, only in an Opt1 or " + "Opt2 build on Windows."); + #else _count_memory_usage = false; #endif diff --git a/panda/src/express/multifile.cxx b/panda/src/express/multifile.cxx index 5dc9b599f7..0ffa99fa4f 100644 --- a/panda/src/express/multifile.cxx +++ b/panda/src/express/multifile.cxx @@ -1573,8 +1573,11 @@ write_data(ostream &write, istream *read, streampos fpos, #else // HAVE_ZLIB if ((_flags & SF_encrypted) != 0) { // Write it encrypted. - putter = new OEncryptStream(putter, delete_putter, - multifile->_encryption_password); + OEncryptStream *encrypt = new OEncryptStream; + encrypt->set_iteration_count(multifile_encryption_iteration_count); + encrypt->open(putter, delete_putter, multifile->_encryption_password); + + putter = encrypt; delete_putter = true; // Also write the encrypt_header to the beginning of the diff --git a/panda/src/express/textEncoder.cxx b/panda/src/express/textEncoder.cxx index 7a9da805de..83ec848368 100644 --- a/panda/src/express/textEncoder.cxx +++ b/panda/src/express/textEncoder.cxx @@ -21,7 +21,10 @@ #include "unicodeLatinMap.h" TypeHandle TextEncoder::_type_handle; -TextEncoder::Encoding TextEncoder::_default_encoding; +ConfigVariableEnum TextEncoder::_default_encoding +("default-encoding", TextEncoder::E_iso8859, + "Specifies how international characters are represented in strings " + "of 8-byte characters presented to Panda. See TextEncoder::set_encoding()."); //////////////////////////////////////////////////////////////////// // Function: TextEncoder::make_upper @@ -321,3 +324,47 @@ expand_amp_sequence(StringDecoder &decoder) const { } */ + +//////////////////////////////////////////////////////////////////// +// Function: TextEncoder::Encoding ostream operator +// Description: +//////////////////////////////////////////////////////////////////// +ostream & +operator << (ostream &out, TextEncoder::Encoding encoding) { + switch (encoding) { + case TextEncoder::E_iso8859: + return out << "iso8859"; + + case TextEncoder::E_utf8: + return out << "utf8"; + + case TextEncoder::E_unicode: + return out << "unicode"; + }; + + return out << "**invalid TextEncoder::Encoding(" << (int)encoding << ")**"; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextEncoder::Encoding istream operator +// Description: +//////////////////////////////////////////////////////////////////// +istream & +operator >> (istream &in, TextEncoder::Encoding &encoding) { + string word; + in >> word; + + if (word == "iso8859") { + encoding = TextEncoder::E_iso8859; + } else if (word == "utf8") { + encoding = TextEncoder::E_utf8; + } else if (word == "unicode") { + encoding = TextEncoder::E_unicode; + } else { + express_cat.error() + << "Invalid TextEncoder::Encoding: " << word << "\n"; + encoding = TextEncoder::E_iso8859; + } + + return in; +} diff --git a/panda/src/express/textEncoder.h b/panda/src/express/textEncoder.h index dac803d7e4..739f7e108e 100644 --- a/panda/src/express/textEncoder.h +++ b/panda/src/express/textEncoder.h @@ -21,6 +21,7 @@ #include "pandabase.h" #include "unicodeLatinMap.h" +#include "configVariableEnum.h" class StringDecoder; @@ -112,7 +113,7 @@ private: string _text; wstring _wtext; - static Encoding _default_encoding; + static ConfigVariableEnum _default_encoding; public: static TypeHandle get_class_type() { @@ -126,6 +127,9 @@ private: static TypeHandle _type_handle; }; +ostream &operator << (ostream &out, TextEncoder::Encoding encoding); +istream &operator >> (istream &in, TextEncoder::Encoding &encoding); + #include "textEncoder.I" #endif diff --git a/panda/src/express/virtualFileSystem.cxx b/panda/src/express/virtualFileSystem.cxx index 3103b9410f..9cad1b4bfe 100644 --- a/panda/src/express/virtualFileSystem.cxx +++ b/panda/src/express/virtualFileSystem.cxx @@ -504,72 +504,67 @@ get_global_ptr() { _global_ptr->chdir(ExecutionEnvironment::get_cwd()); // Then, we add whatever mounts are listed in the Configrc file. - Config::ConfigTable::Symbol mounts; - config_express.GetAll("vfs-mount", mounts); + ConfigVariableList mounts + ("vfs-mount", + "vfs-mount system-filename mount-point [options]"); - // When we use GetAll(), we might inadvertently read duplicate - // lines. Filter them out with a set. - pset already_read; + int num_unique_values = mounts.get_num_unique_values(); + for (int i = 0; i < num_unique_values; i++) { + string mount_desc = mounts.get_unique_value(i); - Config::ConfigTable::Symbol::iterator si; - for (si = mounts.begin(); si != mounts.end(); ++si) { - string mount_desc = (*si).Val(); - if (already_read.insert(mount_desc).second) { - - // The vfs-mount syntax is: - - // vfs-mount system-filename mount-point [options] - - // The last two spaces mark the beginning of the mount point, - // and of the options, respectively. There might be multiple - // spaces in the system filename, which are part of the - // filename. - - // The last space marks the beginning of the mount point. - // Spaces before that are part of the system filename. - size_t space = mount_desc.rfind(' '); - if (space == string::npos) { - express_cat.warning() - << "No space in vfs-mount descriptor: " << mount_desc << "\n"; - - } else { - string mount_point = mount_desc.substr(space + 1); + // The vfs-mount syntax is: + + // vfs-mount system-filename mount-point [options] + + // The last two spaces mark the beginning of the mount point, + // and of the options, respectively. There might be multiple + // spaces in the system filename, which are part of the + // filename. + + // The last space marks the beginning of the mount point. + // Spaces before that are part of the system filename. + size_t space = mount_desc.rfind(' '); + if (space == string::npos) { + express_cat.warning() + << "No space in vfs-mount descriptor: " << mount_desc << "\n"; + + } else { + string mount_point = mount_desc.substr(space + 1); + while (space > 0 && isspace(mount_desc[space - 1])) { + space--; + } + mount_desc = mount_desc.substr(0, space); + string options; + + space = mount_desc.rfind(' '); + if (space != string::npos) { + // If there's another space, we have the optional options field. + options = mount_point; + mount_point = mount_desc.substr(space + 1); while (space > 0 && isspace(mount_desc[space - 1])) { space--; } mount_desc = mount_desc.substr(0, space); - string options; - - space = mount_desc.rfind(' '); - if (space != string::npos) { - // If there's another space, we have the optional options field. - options = mount_point; - mount_point = mount_desc.substr(space + 1); - while (space > 0 && isspace(mount_desc[space - 1])) { - space--; - } - mount_desc = mount_desc.substr(0, space); - } - - mount_desc = ExecutionEnvironment::expand_string(mount_desc); - Filename physical_filename = Filename::from_os_specific(mount_desc); - - int flags = 0; - string password; - - // Split the options up by commas. - size_t p = 0; - size_t q = options.find(',', p); - while (q != string::npos) { - parse_option(options.substr(p, q - p), - flags, password); - p = q + 1; - q = options.find(',', p); - } - parse_option(options.substr(p), flags, password); - - _global_ptr->mount(physical_filename, mount_point, flags, password); } + + mount_desc = ExecutionEnvironment::expand_string(mount_desc); + Filename physical_filename = Filename::from_os_specific(mount_desc); + + int flags = 0; + string password; + + // Split the options up by commas. + size_t p = 0; + size_t q = options.find(',', p); + while (q != string::npos) { + parse_option(options.substr(p, q - p), + flags, password); + p = q + 1; + q = options.find(',', p); + } + parse_option(options.substr(p), flags, password); + + _global_ptr->mount(physical_filename, mount_point, flags, password); } } }