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

This commit is contained in:
David Rose 2004-09-02 16:29:26 +00:00
parent e51ecacdee
commit 62f45b292c
11 changed files with 113 additions and 97 deletions

View File

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

View File

@ -79,6 +79,32 @@ config_express.GetDouble("max-dt", -1.0);
const double sleep_precision =
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
// models, etc. Since the VirtualFileSystem maps to the same as the
// actual file system by default, there is probably no reason to set

View File

@ -56,6 +56,10 @@ extern const double clock_degrade_factor;
extern const double max_dt;
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 collect_tcp;

View File

@ -77,11 +77,10 @@ OEncryptStream() : ostream(&_buf) {
// Description:
////////////////////////////////////////////////////////////////////
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)
{
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:
////////////////////////////////////////////////////////////////////
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);
_buf.open_write(dest, owns_dest, password, encryption_algorithm);
_buf.open_write(dest, owns_dest, password);
return *this;
}

View File

@ -22,16 +22,14 @@
// Function: encrypt_string
// Access: Published
// 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
encrypt_string(const string &source, const string &password,
const string &algorithm) {
encrypt_string(const string &source, const string &password) {
ostringstream output;
{
OEncryptStream encrypt(&output, false, password, algorithm);
OEncryptStream encrypt(&output, false, password);
encrypt.write(source.data(), source.length());
}

View File

@ -67,12 +67,10 @@ class EXPCL_PANDAEXPRESS OEncryptStream : public ostream {
public:
INLINE OEncryptStream();
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,
const string &password,
const string &encryption_algorithm = "");
const string &password);
INLINE OEncryptStream &close();
private:
@ -80,8 +78,7 @@ private:
};
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);
END_PUBLISH

View File

@ -30,6 +30,10 @@
typedef int 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
// Access: Public
@ -88,6 +92,8 @@ open_read(istream *source, bool owns_source, const string &password) {
// Now read the header information.
StreamReader sr(_source, false);
int nid = sr.get_uint16();
int key_length = sr.get_uint16();
int count = sr.get_uint16();
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()
<< "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 key_length = EVP_CIPHER_key_length(cipher);
_read_block_size = EVP_CIPHER_block_size(cipher);
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.
int result;
unsigned char *key = (unsigned char *)alloca(key_length);
result =
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);
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);
_read_valid = true;
@ -157,8 +177,7 @@ close_read() {
// Description:
////////////////////////////////////////////////////////////////////
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();
close_write();
@ -166,14 +185,8 @@ open_write(ostream *dest, bool owns_dest, const string &password,
_owns_dest = owns_dest;
_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) {
express_cat.error()
@ -182,36 +195,62 @@ open_write(ostream *dest, bool owns_dest, const string &password,
};
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);
_write_block_size = EVP_CIPHER_block_size(cipher);
unsigned char *key = (unsigned char *)alloca(key_length);
unsigned char *iv = (unsigned char *)alloca(iv_length);
// Generate a random IV. It doesn't need to be cryptographically
// secure, just unique.
RAND_pseudo_bytes(iv, iv_length);
// Hash the supplied password into a key of the appropriate length.
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 =
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);
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);
_write_valid = true;
// Now write the header information to the stream.
StreamWriter sw(_dest);
nassertv((PN_uint16)nid == 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);
_write_valid = true;
}
////////////////////////////////////////////////////////////////////

View File

@ -39,8 +39,7 @@ public:
void open_read(istream *source, bool owns_source, const string &password);
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();
protected:

View File

@ -84,12 +84,11 @@ get_scale_factor() const {
// encryption.
//
// 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::
set_encryption_flag(bool flag) {
@ -141,36 +140,6 @@ get_encryption_password() const {
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
// Access: Published

View File

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

View File

@ -59,8 +59,6 @@ PUBLISHED:
INLINE bool get_encryption_flag() const;
INLINE void set_encryption_password(const string &password);
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,
int compression_level);
@ -167,7 +165,6 @@ private:
bool _encryption_flag;
string _encryption_password;
string _encryption_algorithm;
ifstream _read_file;
ofstream _write_file;