Browse Source

remove explicit algorithm parameter (make config variable only), add key length variable

David Rose 21 years ago
parent
commit
62f45b292c

+ 2 - 12
panda/src/downloadertools/pencrypt.cxx

@@ -42,11 +42,6 @@ usage() {
 
 
     << "Options:\n\n"
     << "Options:\n\n"
 
 
-    << "  -a algorithm\n"
-    << "      Specifies the particular encryption algorithm to use.  Available\n"
-    << "      algorithm names are defined by OpenSSL.  If this is unspecified a\n"
-    << "      default algorithm is selected.\n\n"
-    
     << "  -p \"password\"\n"
     << "  -p \"password\"\n"
     << "      Specifies the password to use for encryption.  There are no\n"
     << "      Specifies the password to use for encryption.  There are no\n"
     << "      restrictions on the password length or contents, but longer passwords\n"
     << "      restrictions on the password length or contents, but longer passwords\n"
@@ -58,9 +53,8 @@ int
 main(int argc, char *argv[]) {
 main(int argc, char *argv[]) {
   extern char *optarg;
   extern char *optarg;
   extern int optind;
   extern int optind;
-  const char *optstr = "a:p:h";
+  const char *optstr = "p:h";
 
 
-  string algorithm;
   string password;
   string password;
   bool got_password = false;
   bool got_password = false;
 
 
@@ -68,10 +62,6 @@ main(int argc, char *argv[]) {
 
 
   while (flag != EOF) {
   while (flag != EOF) {
     switch (flag) {
     switch (flag) {
-    case 'a':
-      algorithm = optarg;
-      break;
-
     case 'p':
     case 'p':
       password = optarg;
       password = optarg;
       got_password = true;
       got_password = true;
@@ -129,7 +119,7 @@ main(int argc, char *argv[]) {
     
     
   bool fail = false;
   bool fail = false;
   {
   {
-    OEncryptStream encrypt(&write_stream, false, password, algorithm);
+    OEncryptStream encrypt(&write_stream, false, password);
     
     
     int ch = read_stream.get();
     int ch = read_stream.get();
     while (!read_stream.eof() && !read_stream.fail()) {
     while (!read_stream.eof() && !read_stream.fail()) {

+ 26 - 0
panda/src/express/config_express.cxx

@@ -79,6 +79,32 @@ config_express.GetDouble("max-dt", -1.0);
 const double sleep_precision =
 const double sleep_precision =
 config_express.GetDouble("sleep-precision", 0.01);
 config_express.GetDouble("sleep-precision", 0.01);
 
 
+// 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");
+
+// 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.
+const int encryption_key_length =
+config_express.GetInt("encryption-key-length", 0);
+
+// This defines the number of times the 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.  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);
+
 // Set this true to use the VirtualFileSystem mechanism for loading
 // Set this true to use the VirtualFileSystem mechanism for loading
 // models, etc.  Since the VirtualFileSystem maps to the same as the
 // models, etc.  Since the VirtualFileSystem maps to the same as the
 // actual file system by default, there is probably no reason to set
 // actual file system by default, there is probably no reason to set

+ 4 - 0
panda/src/express/config_express.h

@@ -56,6 +56,10 @@ extern const double clock_degrade_factor;
 extern const double max_dt;
 extern const double max_dt;
 extern const double sleep_precision;
 extern const double sleep_precision;
 
 
+extern const string encryption_algorithm;
+extern const int encryption_key_length;
+extern const int encryption_iteration_count;
+
 extern EXPCL_PANDAEXPRESS const bool use_vfs;
 extern EXPCL_PANDAEXPRESS const bool use_vfs;
 
 
 extern EXPCL_PANDAEXPRESS const bool collect_tcp;
 extern EXPCL_PANDAEXPRESS const bool collect_tcp;

+ 4 - 6
panda/src/express/encryptStream.I

@@ -77,11 +77,10 @@ OEncryptStream() : ostream(&_buf) {
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE OEncryptStream::
 INLINE OEncryptStream::
-OEncryptStream(ostream *dest, bool owns_dest, const string &password,
-               const string &encryption_algorithm) :
+OEncryptStream(ostream *dest, bool owns_dest, const string &password) :
   ostream(&_buf) 
   ostream(&_buf) 
 {
 {
-  open(dest, owns_dest, password, encryption_algorithm);
+  open(dest, owns_dest, password);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -90,10 +89,9 @@ OEncryptStream(ostream *dest, bool owns_dest, const string &password,
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE OEncryptStream &OEncryptStream::
 INLINE OEncryptStream &OEncryptStream::
-open(ostream *dest, bool owns_dest, const string &password,
-     const string &encryption_algorithm) {
+open(ostream *dest, bool owns_dest, const string &password) {
   clear((ios_iostate)0);
   clear((ios_iostate)0);
-  _buf.open_write(dest, owns_dest, password, encryption_algorithm);
+  _buf.open_write(dest, owns_dest, password);
   return *this;
   return *this;
 }
 }
 
 

+ 3 - 5
panda/src/express/encryptStream.cxx

@@ -22,16 +22,14 @@
 //     Function: encrypt_string
 //     Function: encrypt_string
 //       Access: Published
 //       Access: Published
 //  Description: Encrypts the indicated source string using the given
 //  Description: Encrypts the indicated source string using the given
-//               password and algorithm (or empty string for the
-//               default algorithm).  Returns the encrypted string.
+//               password.  Returns the encrypted string.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 string
 string
-encrypt_string(const string &source, const string &password,
-               const string &algorithm) {
+encrypt_string(const string &source, const string &password) {
   ostringstream output;
   ostringstream output;
 
 
   {
   {
-    OEncryptStream encrypt(&output, false, password, algorithm);
+    OEncryptStream encrypt(&output, false, password);
     encrypt.write(source.data(), source.length());
     encrypt.write(source.data(), source.length());
   }
   }
 
 

+ 3 - 6
panda/src/express/encryptStream.h

@@ -67,12 +67,10 @@ class EXPCL_PANDAEXPRESS OEncryptStream : public ostream {
 public:
 public:
   INLINE OEncryptStream();
   INLINE OEncryptStream();
   INLINE OEncryptStream(ostream *dest, bool owns_dest, 
   INLINE OEncryptStream(ostream *dest, bool owns_dest, 
-                        const string &password,
-                        const string &encryption_algorithm = "");
+                        const string &password);
 
 
   INLINE OEncryptStream &open(ostream *dest, bool owns_dest, 
   INLINE OEncryptStream &open(ostream *dest, bool owns_dest, 
-                              const string &password,
-                              const string &encryption_algorithm = "");
+                              const string &password);
   INLINE OEncryptStream &close();
   INLINE OEncryptStream &close();
 
 
 private:
 private:
@@ -80,8 +78,7 @@ private:
 };
 };
 
 
 BEGIN_PUBLISH
 BEGIN_PUBLISH
-string encrypt_string(const string &source, const string &password,
-                      const string &algorithm = "");
+string encrypt_string(const string &source, const string &password);
 string decrypt_string(const string &source, const string &password);
 string decrypt_string(const string &source, const string &password);
 END_PUBLISH
 END_PUBLISH
 
 

+ 64 - 25
panda/src/express/encryptStreamBuf.cxx

@@ -30,6 +30,10 @@
 typedef int streamsize;
 typedef int streamsize;
 #endif /* HAVE_STREAMSIZE */
 #endif /* HAVE_STREAMSIZE */
 
 
+// The iteration count is scaled by this factor for writing to the
+// stream.
+static const int iteration_count_factor = 1000;
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EncryptStreamBuf::Constructor
 //     Function: EncryptStreamBuf::Constructor
 //       Access: Public
 //       Access: Public
@@ -88,6 +92,8 @@ open_read(istream *source, bool owns_source, const string &password) {
   // Now read the header information.
   // Now read the header information.
   StreamReader sr(_source, false);
   StreamReader sr(_source, false);
   int nid = sr.get_uint16();
   int nid = sr.get_uint16();
+  int key_length = sr.get_uint16();
+  int count = sr.get_uint16();
 
 
   const EVP_CIPHER *cipher = EVP_get_cipherbynid(nid);
   const EVP_CIPHER *cipher = EVP_get_cipherbynid(nid);
 
 
@@ -98,25 +104,39 @@ open_read(istream *source, bool owns_source, const string &password) {
   }
   }
 
 
   express_cat.debug()
   express_cat.debug()
-    << "Using decryption algorithm " << OBJ_nid2sn(nid) << "\n";
+    << "Using decryption algorithm " << OBJ_nid2sn(nid) << " with key length "
+    << key_length * 8 << " bits.\n";
 
 
   int iv_length = EVP_CIPHER_iv_length(cipher);
   int iv_length = EVP_CIPHER_iv_length(cipher);
-  int key_length = EVP_CIPHER_key_length(cipher);
   _read_block_size = EVP_CIPHER_block_size(cipher);
   _read_block_size = EVP_CIPHER_block_size(cipher);
 
 
   string iv = sr.extract_bytes(iv_length);
   string iv = sr.extract_bytes(iv_length);
 
 
-  unsigned char *key = (unsigned char *)alloca(key_length);
+  // Initialize the context
+  int result;
+  result = EVP_DecryptInit(&_read_ctx, cipher, NULL, (unsigned char *)iv.data());
+  nassertv(result > 0);
+
+  result = EVP_CIPHER_CTX_set_key_length(&_read_ctx, key_length);
+  if (result <= 0) {
+    express_cat.error()
+      << "Invalid key length " << key_length * 8 << " bits for algorithm "
+      << OBJ_nid2sn(nid) << "\n";
+    EVP_CIPHER_CTX_cleanup(&_read_ctx);
+    return;
+  }
 
 
   // Hash the supplied password into a key of the appropriate length.
   // Hash the supplied password into a key of the appropriate length.
-  int result;
+  unsigned char *key = (unsigned char *)alloca(key_length);
   result =
   result =
     PKCS5_PBKDF2_HMAC_SHA1((const char *)password.data(), password.length(),
     PKCS5_PBKDF2_HMAC_SHA1((const char *)password.data(), password.length(),
-                           (unsigned char *)iv.data(), iv.length(), 1, 
+                           (unsigned char *)iv.data(), iv.length(), 
+                           count * iteration_count_factor, 
                            key_length, key);
                            key_length, key);
   nassertv(result > 0);
   nassertv(result > 0);
 
 
-  result = EVP_DecryptInit(&_read_ctx, cipher, key, (unsigned char *)iv.data());
+  // Store the key within the context.
+  result = EVP_DecryptInit(&_read_ctx, NULL, key, NULL);
   nassertv(result > 0);
   nassertv(result > 0);
 
 
   _read_valid = true;
   _read_valid = true;
@@ -157,8 +177,7 @@ close_read() {
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void EncryptStreamBuf::
 void EncryptStreamBuf::
-open_write(ostream *dest, bool owns_dest, const string &password,
-           const string &encryption_algorithm) {
+open_write(ostream *dest, bool owns_dest, const string &password) {
   OpenSSL_add_all_algorithms();
   OpenSSL_add_all_algorithms();
 
 
   close_write();
   close_write();
@@ -166,14 +185,8 @@ open_write(ostream *dest, bool owns_dest, const string &password,
   _owns_dest = owns_dest;
   _owns_dest = owns_dest;
   _write_valid = false;
   _write_valid = false;
 
 
-  const EVP_CIPHER *cipher;
-  if (encryption_algorithm.empty()) {
-    // Blowfish is the default algorithm.
-    cipher = EVP_bf_cbc();
-
-  } else {
-    cipher = EVP_get_cipherbyname(encryption_algorithm.c_str());
-  }
+  const EVP_CIPHER *cipher = 
+    EVP_get_cipherbyname(encryption_algorithm.c_str());
 
 
   if (cipher == NULL) {
   if (cipher == NULL) {
     express_cat.error()
     express_cat.error()
@@ -182,36 +195,62 @@ open_write(ostream *dest, bool owns_dest, const string &password,
   };
   };
 
 
   int nid = EVP_CIPHER_nid(cipher);
   int nid = EVP_CIPHER_nid(cipher);
-  express_cat.debug()
-    << "Using encryption algorithm " << OBJ_nid2sn(nid) << "\n";
     
     
-  int key_length = EVP_CIPHER_key_length(cipher);
   int iv_length = EVP_CIPHER_iv_length(cipher);
   int iv_length = EVP_CIPHER_iv_length(cipher);
   _write_block_size = EVP_CIPHER_block_size(cipher);
   _write_block_size = EVP_CIPHER_block_size(cipher);
 
 
-  unsigned char *key = (unsigned char *)alloca(key_length);
   unsigned char *iv = (unsigned char *)alloca(iv_length);
   unsigned char *iv = (unsigned char *)alloca(iv_length);
 
 
   // Generate a random IV.  It doesn't need to be cryptographically
   // Generate a random IV.  It doesn't need to be cryptographically
   // secure, just unique.
   // secure, just unique.
   RAND_pseudo_bytes(iv, iv_length);
   RAND_pseudo_bytes(iv, iv_length);
 
 
-  // Hash the supplied password into a key of the appropriate length.
   int result;
   int result;
+  result = EVP_EncryptInit(&_write_ctx, cipher, NULL, iv);
+  nassertv(result > 0);
+
+  // Store the appropriate key length in the context.
+  int key_length = (encryption_key_length + 7) / 8;
+  if (key_length == 0) {
+    key_length = EVP_CIPHER_CTX_key_length(cipher);
+  }
+  result = EVP_CIPHER_CTX_set_key_length(&_write_ctx, key_length);
+  if (result <= 0) {
+    express_cat.error()
+      << "Invalid key length " << key_length * 8 << " bits for algorithm "
+      << OBJ_nid2sn(nid) << "\n";
+    EVP_CIPHER_CTX_cleanup(&_write_ctx);
+    return;
+  }
+
+  express_cat.debug()
+    << "Using encryption algorithm " << OBJ_nid2sn(nid) << " with key length "
+    << key_length * 8 << " bits.\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 =
   result =
     PKCS5_PBKDF2_HMAC_SHA1((const char *)password.data(), password.length(),
     PKCS5_PBKDF2_HMAC_SHA1((const char *)password.data(), password.length(),
-                           iv, iv_length, 1, key_length, key);
+                           iv, iv_length, count * iteration_count_factor,
+                           key_length, key);
   nassertv(result > 0);
   nassertv(result > 0);
 
 
-  result = EVP_EncryptInit(&_write_ctx, cipher, key, iv);
+  // Store the key in the context.
+  result = EVP_EncryptInit(&_write_ctx, NULL, key, NULL);
   nassertv(result > 0);
   nassertv(result > 0);
 
 
-  _write_valid = true;
-
   // Now write the header information to the stream.
   // Now write the header information to the stream.
   StreamWriter sw(_dest);
   StreamWriter sw(_dest);
+  nassertv((PN_uint16)nid == nid);
   sw.add_uint16(nid);
   sw.add_uint16(nid);
+  nassertv((PN_uint16)key_length == key_length);
+  sw.add_uint16(key_length);
+  nassertv((PN_uint16)count == count);
+  sw.add_uint16(count);
   sw.append_data(iv, iv_length);
   sw.append_data(iv, iv_length);
+
+  _write_valid = true;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 1 - 2
panda/src/express/encryptStreamBuf.h

@@ -39,8 +39,7 @@ public:
   void open_read(istream *source, bool owns_source, const string &password);
   void open_read(istream *source, bool owns_source, const string &password);
   void close_read();
   void close_read();
 
 
-  void open_write(ostream *dest, bool owns_dest, const string &password,
-                  const string &encryption_algorithm);
+  void open_write(ostream *dest, bool owns_dest, const string &password);
   void close_write();
   void close_write();
 
 
 protected:
 protected:

+ 5 - 36
panda/src/express/multifile.I

@@ -84,12 +84,11 @@ get_scale_factor() const {
 //               encryption.
 //               encryption.
 //
 //
 //               When true, subfiles will be encrypted with the
 //               When true, subfiles will be encrypted with the
-//               password and algorithm specified by
-//               set_encryption_password() and
-//               set_encryption_algorithm().  It is possible to apply
-//               a different password or algorithm to different files,
-//               but you must call flush() or repack() before changing
-//               these properties.
+//               password specified by set_encryption_password().  It
+//               is possible to apply a different password to
+//               different files, but you must call flush() or
+//               repack() before changing these properties, and the
+//               resulting file can't be mounted via VFS.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void Multifile::
 INLINE void Multifile::
 set_encryption_flag(bool flag) {
 set_encryption_flag(bool flag) {
@@ -141,36 +140,6 @@ get_encryption_password() const {
   return _encryption_password;
   return _encryption_password;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: Multifile::set_encryption_algorithm
-//       Access: Published
-//  Description: Specifies the algorithm that will be used to encrypt
-//               subfiles subsequently added to the multifile, if the
-//               encryption flag is also set true (see
-//               set_encryption_flag()).
-//
-//               The empty string, which is the initial value for this
-//               parameter, implies the default encryption algorithm.
-//               The complete list of available encryption algorithms
-//               is defined by OpenSSL.
-////////////////////////////////////////////////////////////////////
-INLINE void Multifile::
-set_encryption_algorithm(const string &algorithm) {
-  _encryption_algorithm = algorithm;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Multifile::get_encryption_algorithm
-//       Access: Published
-//  Description: Returns the algorithm that will be used to encrypt
-//               subfiles subsequently added to the multifile.  See
-//               set_encryption_algorithm().
-////////////////////////////////////////////////////////////////////
-INLINE const string &Multifile::
-get_encryption_algorithm() const {
-  return _encryption_algorithm;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Multifile::read_subfile
 //     Function: Multifile::read_subfile
 //       Access: Published
 //       Access: Published

+ 1 - 2
panda/src/express/multifile.cxx

@@ -1574,8 +1574,7 @@ write_data(ostream &write, istream *read, streampos fpos,
     if ((_flags & SF_encrypted) != 0) {
     if ((_flags & SF_encrypted) != 0) {
       // Write it encrypted.
       // Write it encrypted.
       putter = new OEncryptStream(putter, delete_putter, 
       putter = new OEncryptStream(putter, delete_putter, 
-                                  multifile->_encryption_password, 
-                                  multifile->_encryption_algorithm);
+                                  multifile->_encryption_password);
       delete_putter = true;
       delete_putter = true;
 
 
       // Also write the encrypt_header to the beginning of the
       // Also write the encrypt_header to the beginning of the

+ 0 - 3
panda/src/express/multifile.h

@@ -59,8 +59,6 @@ PUBLISHED:
   INLINE bool get_encryption_flag() const;
   INLINE bool get_encryption_flag() const;
   INLINE void set_encryption_password(const string &password);
   INLINE void set_encryption_password(const string &password);
   INLINE const string &get_encryption_password() const;
   INLINE const string &get_encryption_password() const;
-  INLINE void set_encryption_algorithm(const string &algorithm);
-  INLINE const string &get_encryption_algorithm() const;
 
 
   string add_subfile(const string &subfile_name, const Filename &filename,
   string add_subfile(const string &subfile_name, const Filename &filename,
                      int compression_level);
                      int compression_level);
@@ -167,7 +165,6 @@ private:
 
 
   bool _encryption_flag;
   bool _encryption_flag;
   string _encryption_password;
   string _encryption_password;
-  string _encryption_algorithm;
 
 
   ifstream _read_file;
   ifstream _read_file;
   ofstream _write_file;
   ofstream _write_file;