support encryption/decryption streams
This commit is contained in:
parent
9bd9b1a99b
commit
e51ecacdee
|
|
@ -88,3 +88,23 @@
|
|||
pdecompress.cxx
|
||||
|
||||
#end bin_target
|
||||
|
||||
#begin bin_target
|
||||
#define TARGET pencrypt
|
||||
#define BUILD_TARGET $[HAVE_SSL]
|
||||
#define USE_PACKAGES $[USE_PACKAGES] ssl
|
||||
|
||||
#define SOURCES \
|
||||
pencrypt.cxx
|
||||
|
||||
#end bin_target
|
||||
|
||||
#begin bin_target
|
||||
#define TARGET pdecrypt
|
||||
#define BUILD_TARGET $[HAVE_SSL]
|
||||
#define USE_PACKAGES $[USE_PACKAGES] ssl
|
||||
|
||||
#define SOURCES \
|
||||
pdecrypt.cxx
|
||||
|
||||
#end bin_target
|
||||
|
|
|
|||
|
|
@ -28,21 +28,24 @@
|
|||
#include <stdio.h>
|
||||
|
||||
|
||||
bool create = false; // -c
|
||||
bool append = false; // -r
|
||||
bool update = false; // -u
|
||||
bool list = false; // -t
|
||||
bool extract = false; // -x
|
||||
bool verbose = false; // -v
|
||||
bool compress = false; // -z
|
||||
bool create = false; // -c
|
||||
bool append = false; // -r
|
||||
bool update = false; // -u
|
||||
bool list = false; // -t
|
||||
bool extract = false; // -x
|
||||
bool verbose = false; // -v
|
||||
bool compress = false; // -z
|
||||
int default_compression_level = 6;
|
||||
Filename multifile_name; // -f
|
||||
Filename multifile_name; // -f
|
||||
bool got_multifile_name = false;
|
||||
bool to_stdout = false; // -O
|
||||
Filename chdir_to; // -C
|
||||
bool to_stdout = false; // -O
|
||||
bool encryption_flag = false; // -e
|
||||
string password; // -p
|
||||
bool got_password = false;
|
||||
Filename chdir_to; // -C
|
||||
bool got_chdir_to = false;
|
||||
size_t scale_factor = 0; // -F
|
||||
pset<string> dont_compress; // -Z
|
||||
size_t scale_factor = 0; // -F
|
||||
pset<string> dont_compress; // -Z
|
||||
|
||||
// Default extensions not to compress. May be overridden with -Z.
|
||||
string dont_compress_str = "jpg,mp3";
|
||||
|
|
@ -120,6 +123,21 @@ help() {
|
|||
" decompressed automatically. Also see -Z, which restricts which\n"
|
||||
" subfiles will be compressed based on the filename extension.\n\n"
|
||||
|
||||
" -e\n"
|
||||
" Encrypt subfiles as they are written to the Multifile using the password\n"
|
||||
" specified with -p, below. Subfiles are encrypted individually, rather\n"
|
||||
" than encrypting the entire multifile, and different subfiles may be\n"
|
||||
" 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"
|
||||
|
||||
|
||||
" -p \"password\"\n"
|
||||
" Specifies the password to encrypt or decrypt subfiles. If this is not\n"
|
||||
" specified, and passwords are required, the user will be prompted from\n"
|
||||
" standard input.\n\n"
|
||||
|
||||
" -F <scale_factor>\n"
|
||||
" Specify a Multifile scale factor. This is only necessary to support\n"
|
||||
" Multifiles that will exceed 4GB in size. The default scale factor is\n"
|
||||
|
|
@ -146,6 +164,18 @@ help() {
|
|||
" default is -" << default_compression_level << ".\n\n";
|
||||
}
|
||||
|
||||
const string &
|
||||
get_password() {
|
||||
if (!got_password) {
|
||||
cerr << "Enter password: ";
|
||||
getline(cin, password);
|
||||
got_password = true;
|
||||
}
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
is_named(const string &subfile_name, int argc, char *argv[]) {
|
||||
// Returns true if the indicated subfile appears on the list of
|
||||
|
|
@ -243,6 +273,11 @@ add_files(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
if (encryption_flag) {
|
||||
multifile.set_encryption_flag(true);
|
||||
multifile.set_encryption_password(get_password());
|
||||
}
|
||||
|
||||
if (scale_factor != 0 && scale_factor != multifile.get_scale_factor()) {
|
||||
cerr << "Setting scale factor to " << scale_factor << "\n";
|
||||
multifile.set_scale_factor(scale_factor);
|
||||
|
|
@ -309,7 +344,26 @@ extract_files(int argc, char *argv[]) {
|
|||
|
||||
int num_subfiles = multifile.get_num_subfiles();
|
||||
|
||||
for (int i = 0; i < num_subfiles; i++) {
|
||||
// First, check to see whether any of the named subfiles have been
|
||||
// encrypted. If any have, we may need to prompt the user to enter
|
||||
// a password before we can extract them.
|
||||
int i;
|
||||
bool any_encrypted = false;
|
||||
for (i = 0; i < num_subfiles && !any_encrypted; i++) {
|
||||
string subfile_name = multifile.get_subfile_name(i);
|
||||
if (is_named(subfile_name, argc, argv)) {
|
||||
if (multifile.is_subfile_encrypted(i)) {
|
||||
any_encrypted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (any_encrypted) {
|
||||
multifile.set_encryption_password(get_password());
|
||||
}
|
||||
|
||||
// Now walk back through the list and this time do the extraction.
|
||||
for (i = 0; i < num_subfiles; i++) {
|
||||
string subfile_name = multifile.get_subfile_name(i);
|
||||
if (is_named(subfile_name, argc, argv)) {
|
||||
Filename filename = subfile_name;
|
||||
|
|
@ -352,21 +406,32 @@ list_files(int argc, char *argv[]) {
|
|||
for (int i = 0; i < num_subfiles; i++) {
|
||||
string subfile_name = multifile.get_subfile_name(i);
|
||||
if (is_named(subfile_name, argc, argv)) {
|
||||
char encrypted_symbol = ' ';
|
||||
if (multifile.is_subfile_encrypted(i)) {
|
||||
encrypted_symbol = 'e';
|
||||
}
|
||||
if (multifile.is_subfile_compressed(i)) {
|
||||
size_t orig_length = multifile.get_subfile_length(i);
|
||||
size_t compressed_length = multifile.get_subfile_compressed_length(i);
|
||||
size_t internal_length = multifile.get_subfile_internal_length(i);
|
||||
double ratio = 1.0;
|
||||
if (orig_length != 0) {
|
||||
ratio = (double)compressed_length / (double)orig_length;
|
||||
ratio = (double)internal_length / (double)orig_length;
|
||||
}
|
||||
if (ratio > 1.0) {
|
||||
printf("%12d worse %c %s\n",
|
||||
multifile.get_subfile_length(i),
|
||||
encrypted_symbol,
|
||||
subfile_name.c_str());
|
||||
} else {
|
||||
printf("%12d %3.0f%% %c %s\n",
|
||||
multifile.get_subfile_length(i),
|
||||
100.0 - ratio * 100.0, encrypted_symbol,
|
||||
subfile_name.c_str());
|
||||
}
|
||||
printf("%12d %3.0f%% %s\n",
|
||||
multifile.get_subfile_length(i),
|
||||
100.0 - ratio * 100.0,
|
||||
subfile_name.c_str());
|
||||
} else {
|
||||
printf("%12d %s\n",
|
||||
printf("%12d %c %s\n",
|
||||
multifile.get_subfile_length(i),
|
||||
subfile_name.c_str());
|
||||
encrypted_symbol, subfile_name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -424,7 +489,7 @@ main(int argc, char *argv[]) {
|
|||
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
static const char *optflags = "crutxvz123456789Z:f:OC:F:h";
|
||||
static const char *optflags = "crutxvz123456789Z:f:OC:ep:F:h";
|
||||
int flag = getopt(argc, argv, optflags);
|
||||
Filename rel_path;
|
||||
while (flag != EOF) {
|
||||
|
|
@ -500,6 +565,13 @@ main(int argc, char *argv[]) {
|
|||
case 'O':
|
||||
to_stdout = true;
|
||||
break;
|
||||
case 'e':
|
||||
encryption_flag = true;
|
||||
break;
|
||||
case 'p':
|
||||
password = optarg;
|
||||
got_password = true;
|
||||
break;
|
||||
case 'F':
|
||||
{
|
||||
char *endptr;
|
||||
|
|
|
|||
|
|
@ -46,16 +46,6 @@ main(int argc, char *argv[]) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Determine source file length
|
||||
read_stream.seekg(0, ios::end);
|
||||
int source_file_length = read_stream.tellg();
|
||||
read_stream.seekg(0, ios::beg);
|
||||
|
||||
if (source_file_length == 0) {
|
||||
cerr << "zero length file: " << source_file << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Open destination file
|
||||
ofstream write_stream;
|
||||
dest_file.set_binary();
|
||||
|
|
@ -64,6 +54,7 @@ main(int argc, char *argv[]) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
bool fail = false;
|
||||
{
|
||||
OCompressStream compress(&write_stream, false);
|
||||
|
||||
|
|
@ -72,13 +63,20 @@ main(int argc, char *argv[]) {
|
|||
compress.put(ch);
|
||||
ch = read_stream.get();
|
||||
}
|
||||
|
||||
fail = compress.fail() && !compress.eof();
|
||||
}
|
||||
|
||||
read_stream.close();
|
||||
write_stream.close();
|
||||
|
||||
if (implicit_dest_file) {
|
||||
source_file.unlink();
|
||||
if (fail) {
|
||||
dest_file.unlink();
|
||||
|
||||
} else {
|
||||
if (implicit_dest_file) {
|
||||
source_file.unlink();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,151 @@
|
|||
// Filename: pdecrypt.cxx
|
||||
// Created by: drose (01Sep04)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "filename.h"
|
||||
#include "encryptStream.h"
|
||||
#include "notify.h"
|
||||
|
||||
#ifndef HAVE_GETOPT
|
||||
#include "gnu_getopt.h"
|
||||
#else
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void
|
||||
usage() {
|
||||
cerr
|
||||
<< "\n"
|
||||
<< "Usage: pdecrypt [opts] <file> [<dest_file>]\n\n"
|
||||
|
||||
<< "This program reverses the operation of a previous pencrypt command. It\n"
|
||||
<< "decrypts the contents of the source file by applying the indicated password.\n"
|
||||
<< "The encryption algorithm need not be specified; it can be determined by\n"
|
||||
<< "examining the header of the encrypted file. The password must match exactly.\n"
|
||||
<< "If it does not, an error may or may not be reported; but the file will not be\n"
|
||||
<< "decrypted correctly even if no error is reported.\n\n"
|
||||
|
||||
<< "Options:\n\n"
|
||||
|
||||
<< " -p \"password\"\n"
|
||||
<< " Specifies the password to use for descryption. If this is not specified,\n"
|
||||
<< " the user is prompted from standard input.\n\n";
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
const char *optstr = "p:h";
|
||||
|
||||
string password;
|
||||
bool got_password = false;
|
||||
|
||||
int flag = getopt(argc, argv, optstr);
|
||||
|
||||
while (flag != EOF) {
|
||||
switch (flag) {
|
||||
case 'p':
|
||||
password = optarg;
|
||||
got_password = true;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
flag = getopt(argc, argv, optstr);
|
||||
}
|
||||
|
||||
argc -= (optind-1);
|
||||
argv += (optind-1);
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool implicit_dest_file;
|
||||
Filename source_file = Filename::from_os_specific(argv[1]);
|
||||
Filename dest_file;
|
||||
if (argc < 3) {
|
||||
if (source_file.get_extension() == "pe") {
|
||||
dest_file = source_file;
|
||||
dest_file.set_extension("");
|
||||
} else {
|
||||
cerr << "Input filename doesn't end in .pe; can't derive filename of output file.\n";
|
||||
return 1;
|
||||
}
|
||||
implicit_dest_file = true;
|
||||
} else {
|
||||
dest_file = Filename::from_os_specific(argv[2]);
|
||||
implicit_dest_file = false;
|
||||
}
|
||||
|
||||
// Open source file
|
||||
ifstream read_stream;
|
||||
source_file.set_binary();
|
||||
if (!source_file.open_read(read_stream)) {
|
||||
cerr << "failed to open: " << source_file << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Open destination file
|
||||
ofstream write_stream;
|
||||
dest_file.set_binary();
|
||||
if (!dest_file.open_write(write_stream, true)) {
|
||||
cerr << "failed to open: " << dest_file << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Prompt for password.
|
||||
if (!got_password) {
|
||||
cerr << "Enter password: ";
|
||||
getline(cin, password);
|
||||
}
|
||||
|
||||
bool fail = false;
|
||||
{
|
||||
IDecryptStream decrypt(&read_stream, false, password);
|
||||
|
||||
int ch = decrypt.get();
|
||||
while (!decrypt.eof() && !decrypt.fail()) {
|
||||
write_stream.put(ch);
|
||||
ch = decrypt.get();
|
||||
}
|
||||
|
||||
fail = decrypt.fail() && !decrypt.eof();
|
||||
}
|
||||
|
||||
read_stream.close();
|
||||
write_stream.close();
|
||||
|
||||
if (fail) {
|
||||
dest_file.unlink();
|
||||
|
||||
} else {
|
||||
if (implicit_dest_file) {
|
||||
source_file.unlink();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
// Filename: pencrypt.cxx
|
||||
// Created by: drose (01Sep04)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "filename.h"
|
||||
#include "encryptStream.h"
|
||||
#include "notify.h"
|
||||
|
||||
#ifndef HAVE_GETOPT
|
||||
#include "gnu_getopt.h"
|
||||
#else
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void
|
||||
usage() {
|
||||
cerr
|
||||
<< "\n"
|
||||
<< "Usage: pencrypt [opts] <file> [<dest_file>]\n\n"
|
||||
|
||||
<< "This program will apply an encryption algorithm to a file, creating an\n"
|
||||
<< "encrypted version of the file which can only be recovered using pdecrypt and\n"
|
||||
<< "the same password that was supplied to pencrypt. If the dest_file name is\n"
|
||||
<< "not specified, a default output name is generated by appending .pe to the\n"
|
||||
<< "input file name.\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"
|
||||
<< " 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";
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
const char *optstr = "a:p:h";
|
||||
|
||||
string algorithm;
|
||||
string password;
|
||||
bool got_password = false;
|
||||
|
||||
int flag = getopt(argc, argv, optstr);
|
||||
|
||||
while (flag != EOF) {
|
||||
switch (flag) {
|
||||
case 'a':
|
||||
algorithm = optarg;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
password = optarg;
|
||||
got_password = true;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
flag = getopt(argc, argv, optstr);
|
||||
}
|
||||
|
||||
argc -= (optind-1);
|
||||
argv += (optind-1);
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool implicit_dest_file;
|
||||
Filename source_file = Filename::from_os_specific(argv[1]);
|
||||
Filename dest_file;
|
||||
if (argc < 3) {
|
||||
dest_file = source_file.get_fullpath() + ".pe";
|
||||
implicit_dest_file = true;
|
||||
} else {
|
||||
dest_file = Filename::from_os_specific(argv[2]);
|
||||
implicit_dest_file = false;
|
||||
}
|
||||
|
||||
// Open source file
|
||||
ifstream read_stream;
|
||||
source_file.set_binary();
|
||||
if (!source_file.open_read(read_stream)) {
|
||||
cerr << "failed to open: " << source_file << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Open destination file
|
||||
ofstream write_stream;
|
||||
dest_file.set_binary();
|
||||
if (!dest_file.open_write(write_stream, true)) {
|
||||
cerr << "failed to open: " << dest_file << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Prompt for password.
|
||||
if (!got_password) {
|
||||
cerr << "Enter password: ";
|
||||
getline(cin, password);
|
||||
}
|
||||
|
||||
bool fail = false;
|
||||
{
|
||||
OEncryptStream encrypt(&write_stream, false, password, algorithm);
|
||||
|
||||
int ch = read_stream.get();
|
||||
while (!read_stream.eof() && !read_stream.fail()) {
|
||||
encrypt.put(ch);
|
||||
ch = read_stream.get();
|
||||
}
|
||||
|
||||
fail = encrypt.fail() && !encrypt.eof();
|
||||
}
|
||||
|
||||
read_stream.close();
|
||||
write_stream.close();
|
||||
|
||||
if (fail) {
|
||||
dest_file.unlink();
|
||||
|
||||
} else {
|
||||
if (implicit_dest_file) {
|
||||
source_file.unlink();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
datagramGenerator.h \
|
||||
datagramIterator.I datagramIterator.h datagramSink.I datagramSink.h \
|
||||
dcast.T dcast.h \
|
||||
encryptStreamBuf.h encryptStream.h encryptStream.I \
|
||||
error_utils.h \
|
||||
get_config_path.h \
|
||||
hashGeneratorBase.I hashGeneratorBase.h \
|
||||
|
|
@ -40,6 +41,7 @@
|
|||
namable.h nativeNumericData.I nativeNumericData.h \
|
||||
numeric_types.h \
|
||||
ordered_vector.h ordered_vector.I ordered_vector.T \
|
||||
password_hash.h \
|
||||
patchfile.I patchfile.h \
|
||||
pointerTo.I pointerTo.h \
|
||||
pointerToArray.I pointerToArray.h \
|
||||
|
|
@ -79,7 +81,9 @@
|
|||
conditionVar.cxx conditionVarDummyImpl.cxx conditionVarNsprImpl.cxx \
|
||||
config_express.cxx datagram.cxx datagramGenerator.cxx \
|
||||
datagramIterator.cxx \
|
||||
datagramSink.cxx dcast.cxx error_utils.cxx \
|
||||
datagramSink.cxx dcast.cxx \
|
||||
encryptStreamBuf.cxx encryptStream.cxx \
|
||||
error_utils.cxx \
|
||||
get_config_path.cxx \
|
||||
hashGeneratorBase.cxx hashVal.cxx indent.cxx \
|
||||
memoryInfo.cxx memoryUsage.cxx memoryUsagePointerCounts.cxx \
|
||||
|
|
@ -88,6 +92,7 @@
|
|||
namable.cxx \
|
||||
nativeNumericData.cxx \
|
||||
ordered_vector.cxx \
|
||||
password_hash.cxx \
|
||||
patchfile.cxx \
|
||||
profileTimer.cxx \
|
||||
pta_uchar.cxx \
|
||||
|
|
@ -125,6 +130,7 @@
|
|||
datagramGenerator.I datagramGenerator.h \
|
||||
datagramIterator.I datagramIterator.h \
|
||||
datagramSink.I datagramSink.h dcast.T dcast.h \
|
||||
encryptStreamBuf.h encryptStream.h encryptStream.I \
|
||||
error_utils.h get_config_path.h \
|
||||
hashGeneratorBase.I \
|
||||
hashGeneratorBase.h hashVal.I hashVal.h \
|
||||
|
|
@ -139,6 +145,7 @@
|
|||
namable.I namable.h \
|
||||
nativeNumericData.I nativeNumericData.h numeric_types.h \
|
||||
ordered_vector.h ordered_vector.I ordered_vector.T \
|
||||
password_hash.h \
|
||||
patchfile.I patchfile.h pointerTo.I pointerTo.h \
|
||||
pointerToArray.I pointerToArray.h profileTimer.I \
|
||||
profileTimer.h pta_uchar.h \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,111 @@
|
|||
// Filename: encryptStream.I
|
||||
// Created by: drose (01Sep04)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: IDecryptStream::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE IDecryptStream::
|
||||
IDecryptStream() : istream(&_buf) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IDecryptStream::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE IDecryptStream::
|
||||
IDecryptStream(istream *source, bool owns_source,
|
||||
const string &password) : istream(&_buf) {
|
||||
open(source, owns_source, password);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IDecryptStream::open
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE IDecryptStream &IDecryptStream::
|
||||
open(istream *source, bool owns_source, const string &password) {
|
||||
clear((ios_iostate)0);
|
||||
_buf.open_read(source, owns_source, password);
|
||||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IDecryptStream::close
|
||||
// Access: Public
|
||||
// Description: Resets the EncryptStream to empty, but does not actually
|
||||
// close the source istream unless owns_source was true.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE IDecryptStream &IDecryptStream::
|
||||
close() {
|
||||
_buf.close_read();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: OEncryptStream::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE OEncryptStream::
|
||||
OEncryptStream() : ostream(&_buf) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: OEncryptStream::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE OEncryptStream::
|
||||
OEncryptStream(ostream *dest, bool owns_dest, const string &password,
|
||||
const string &encryption_algorithm) :
|
||||
ostream(&_buf)
|
||||
{
|
||||
open(dest, owns_dest, password, encryption_algorithm);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: OEncryptStream::open
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE OEncryptStream &OEncryptStream::
|
||||
open(ostream *dest, bool owns_dest, const string &password,
|
||||
const string &encryption_algorithm) {
|
||||
clear((ios_iostate)0);
|
||||
_buf.open_write(dest, owns_dest, password, encryption_algorithm);
|
||||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: OEncryptStream::close
|
||||
// Access: Public
|
||||
// Description: Resets the EncryptStream to empty, but does not actually
|
||||
// close the dest ostream unless owns_dest was true.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE OEncryptStream &OEncryptStream::
|
||||
close() {
|
||||
_buf.close_write();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// Filename: encryptStream.cxx
|
||||
// Created by: drose (01Sep04)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "encryptStream.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string
|
||||
encrypt_string(const string &source, const string &password,
|
||||
const string &algorithm) {
|
||||
ostringstream output;
|
||||
|
||||
{
|
||||
OEncryptStream encrypt(&output, false, password, algorithm);
|
||||
encrypt.write(source.data(), source.length());
|
||||
}
|
||||
|
||||
return output.str();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: decrypt_string
|
||||
// Access: Published
|
||||
// Description: Decrypts the previously-encrypted string using the
|
||||
// given password (which must be the same password
|
||||
// passed to encrypt()). The return value is the
|
||||
// decrypted string. Note that a decryption error,
|
||||
// including an incorrect password, cannot easily be
|
||||
// detected, and the return value may simply be a
|
||||
// garbage string.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string
|
||||
decrypt_string(const string &source, const string &password) {
|
||||
istringstream input(source);
|
||||
ostringstream output;
|
||||
|
||||
{
|
||||
IDecryptStream decrypt(&input, false, password);
|
||||
|
||||
int ch = decrypt.get();
|
||||
while (!decrypt.eof() && !decrypt.fail()) {
|
||||
output.put(ch);
|
||||
ch = decrypt.get();
|
||||
}
|
||||
}
|
||||
|
||||
return output.str();
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
// Filename: encryptStream.h
|
||||
// Created by: drose (01Sep04)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ENCRYPTSTREAM_H
|
||||
#define ENCRYPTSTREAM_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
// This module is not compiled if OpenSSL is not available.
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
#include "encryptStreamBuf.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : IDecryptStream
|
||||
// Description : An input stream object that uses OpenSSL to decrypt
|
||||
// the input from another source stream on-the-fly.
|
||||
//
|
||||
// Attach an IDecryptStream to an existing istream that
|
||||
// provides encrypted data, as generated by an
|
||||
// OEncryptStream, and read the corresponding
|
||||
// unencrypted data from the IDecryptStream.
|
||||
//
|
||||
// Seeking is not supported.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDAEXPRESS IDecryptStream : public istream {
|
||||
public:
|
||||
INLINE IDecryptStream();
|
||||
INLINE IDecryptStream(istream *source, bool owns_source,
|
||||
const string &password);
|
||||
|
||||
INLINE IDecryptStream &open(istream *source, bool owns_source,
|
||||
const string &password);
|
||||
INLINE IDecryptStream &close();
|
||||
|
||||
private:
|
||||
EncryptStreamBuf _buf;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : OEncryptStream
|
||||
// Description : An input stream object that uses OpenSSL to encrypt
|
||||
// data to another destination stream on-the-fly.
|
||||
//
|
||||
// Attach an OEncryptStream to an existing ostream that
|
||||
// will accept encrypted data, and write your
|
||||
// unencrypted source data to the OEncryptStream.
|
||||
//
|
||||
// Seeking is not supported.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDAEXPRESS OEncryptStream : public ostream {
|
||||
public:
|
||||
INLINE OEncryptStream();
|
||||
INLINE OEncryptStream(ostream *dest, bool owns_dest,
|
||||
const string &password,
|
||||
const string &encryption_algorithm = "");
|
||||
|
||||
INLINE OEncryptStream &open(ostream *dest, bool owns_dest,
|
||||
const string &password,
|
||||
const string &encryption_algorithm = "");
|
||||
INLINE OEncryptStream &close();
|
||||
|
||||
private:
|
||||
EncryptStreamBuf _buf;
|
||||
};
|
||||
|
||||
BEGIN_PUBLISH
|
||||
string encrypt_string(const string &source, const string &password,
|
||||
const string &algorithm = "");
|
||||
string decrypt_string(const string &source, const string &password);
|
||||
END_PUBLISH
|
||||
|
||||
#include "encryptStream.I"
|
||||
|
||||
#endif // HAVE_SSL
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,423 @@
|
|||
// Filename: encryptStreamBuf.cxx
|
||||
// Created by: drose (01Sep04)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "encryptStreamBuf.h"
|
||||
#include "config_express.h"
|
||||
#include "streamReader.h"
|
||||
#include "streamWriter.h"
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#ifndef HAVE_STREAMSIZE
|
||||
// Some compilers (notably SGI) don't define this for us
|
||||
typedef int streamsize;
|
||||
#endif /* HAVE_STREAMSIZE */
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EncryptStreamBuf::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
EncryptStreamBuf::
|
||||
EncryptStreamBuf() {
|
||||
_source = (istream *)NULL;
|
||||
_owns_source = false;
|
||||
_dest = (ostream *)NULL;
|
||||
_owns_dest = false;
|
||||
|
||||
_read_valid = false;
|
||||
_write_valid = false;
|
||||
|
||||
_read_overflow_buffer = NULL;
|
||||
_in_read_overflow_buffer = 0;
|
||||
|
||||
#ifdef HAVE_IOSTREAM
|
||||
char *buf = new char[4096];
|
||||
char *ebuf = buf + 4096;
|
||||
setg(buf, ebuf, ebuf);
|
||||
setp(buf, ebuf);
|
||||
|
||||
#else
|
||||
allocate();
|
||||
setg(base(), ebuf(), ebuf());
|
||||
setp(base(), ebuf());
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EncryptStreamBuf::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
EncryptStreamBuf::
|
||||
~EncryptStreamBuf() {
|
||||
close_read();
|
||||
close_write();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EncryptStreamBuf::open_read
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EncryptStreamBuf::
|
||||
open_read(istream *source, bool owns_source, const string &password) {
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
_source = source;
|
||||
_owns_source = owns_source;
|
||||
_read_valid = false;
|
||||
|
||||
// Now read the header information.
|
||||
StreamReader sr(_source, false);
|
||||
int nid = sr.get_uint16();
|
||||
|
||||
const EVP_CIPHER *cipher = EVP_get_cipherbynid(nid);
|
||||
|
||||
if (cipher == NULL) {
|
||||
express_cat.error()
|
||||
<< "Unknown encryption algorithm in stream.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
express_cat.debug()
|
||||
<< "Using decryption algorithm " << OBJ_nid2sn(nid) << "\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);
|
||||
|
||||
// Hash the supplied password into a key of the appropriate length.
|
||||
int result;
|
||||
result =
|
||||
PKCS5_PBKDF2_HMAC_SHA1((const char *)password.data(), password.length(),
|
||||
(unsigned char *)iv.data(), iv.length(), 1,
|
||||
key_length, key);
|
||||
nassertv(result > 0);
|
||||
|
||||
result = EVP_DecryptInit(&_read_ctx, cipher, key, (unsigned char *)iv.data());
|
||||
nassertv(result > 0);
|
||||
|
||||
_read_valid = true;
|
||||
|
||||
_read_overflow_buffer = new unsigned char[_read_block_size];
|
||||
_in_read_overflow_buffer = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EncryptStreamBuf::close_read
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EncryptStreamBuf::
|
||||
close_read() {
|
||||
if (_read_valid) {
|
||||
EVP_CIPHER_CTX_cleanup(&_read_ctx);
|
||||
_read_valid = false;
|
||||
}
|
||||
|
||||
if (_read_overflow_buffer != (unsigned char *)NULL) {
|
||||
delete[] _read_overflow_buffer;
|
||||
_read_overflow_buffer = NULL;
|
||||
}
|
||||
|
||||
if (_source != (istream *)NULL) {
|
||||
if (_owns_source) {
|
||||
delete _source;
|
||||
_owns_source = false;
|
||||
}
|
||||
_source = (istream *)NULL;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EncryptStreamBuf::open_write
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EncryptStreamBuf::
|
||||
open_write(ostream *dest, bool owns_dest, const string &password,
|
||||
const string &encryption_algorithm) {
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
close_write();
|
||||
_dest = dest;
|
||||
_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());
|
||||
}
|
||||
|
||||
if (cipher == NULL) {
|
||||
express_cat.error()
|
||||
<< "Unknown encryption algorithm: " << encryption_algorithm << "\n";
|
||||
return;
|
||||
};
|
||||
|
||||
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 =
|
||||
PKCS5_PBKDF2_HMAC_SHA1((const char *)password.data(), password.length(),
|
||||
iv, iv_length, 1, key_length, key);
|
||||
nassertv(result > 0);
|
||||
|
||||
result = EVP_EncryptInit(&_write_ctx, cipher, key, iv);
|
||||
nassertv(result > 0);
|
||||
|
||||
_write_valid = true;
|
||||
|
||||
// Now write the header information to the stream.
|
||||
StreamWriter sw(_dest);
|
||||
sw.add_uint16(nid);
|
||||
sw.append_data(iv, iv_length);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EncryptStreamBuf::close_write
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EncryptStreamBuf::
|
||||
close_write() {
|
||||
if (_dest != (ostream *)NULL) {
|
||||
size_t n = pptr() - pbase();
|
||||
write_chars(pbase(), n);
|
||||
pbump(-(int)n);
|
||||
|
||||
if (_write_valid) {
|
||||
unsigned char *write_buffer = (unsigned char *)alloca(_write_block_size);
|
||||
int bytes_written = 0;
|
||||
EVP_EncryptFinal(&_write_ctx, write_buffer, &bytes_written);
|
||||
|
||||
_dest->write((const char *)write_buffer, bytes_written);
|
||||
|
||||
_write_valid = false;
|
||||
}
|
||||
|
||||
if (_owns_dest) {
|
||||
delete _dest;
|
||||
_owns_dest = false;
|
||||
}
|
||||
_dest = (ostream *)NULL;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EncryptStreamBuf::overflow
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called by the system ostream implementation when its
|
||||
// internal buffer is filled, plus one character.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int EncryptStreamBuf::
|
||||
overflow(int ch) {
|
||||
size_t n = pptr() - pbase();
|
||||
if (n != 0) {
|
||||
write_chars(pbase(), n);
|
||||
pbump(-(int)n);
|
||||
}
|
||||
|
||||
if (ch != EOF) {
|
||||
// Write one more character.
|
||||
char c = ch;
|
||||
write_chars(&c, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EncryptStreamBuf::sync
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called by the system iostream implementation to
|
||||
// implement a flush operation.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int EncryptStreamBuf::
|
||||
sync() {
|
||||
if (_source != (istream *)NULL) {
|
||||
size_t n = egptr() - gptr();
|
||||
gbump(n);
|
||||
}
|
||||
|
||||
if (_dest != (ostream *)NULL) {
|
||||
size_t n = pptr() - pbase();
|
||||
write_chars(pbase(), n);
|
||||
pbump(-(int)n);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EncryptStreamBuf::underflow
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called by the system istream implementation when its
|
||||
// internal buffer needs more characters.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int EncryptStreamBuf::
|
||||
underflow() {
|
||||
// Sometimes underflow() is called even if the buffer is not empty.
|
||||
if (gptr() >= egptr()) {
|
||||
size_t buffer_size = egptr() - eback();
|
||||
gbump(-(int)buffer_size);
|
||||
|
||||
size_t num_bytes = buffer_size;
|
||||
size_t read_count = read_chars(gptr(), buffer_size);
|
||||
|
||||
if (read_count != num_bytes) {
|
||||
// Oops, we didn't read what we thought we would.
|
||||
if (read_count == 0) {
|
||||
gbump(num_bytes);
|
||||
return EOF;
|
||||
}
|
||||
|
||||
// Slide what we did read to the top of the buffer.
|
||||
nassertr(read_count < num_bytes, EOF);
|
||||
size_t delta = num_bytes - read_count;
|
||||
memmove(gptr() + delta, gptr(), read_count);
|
||||
gbump(delta);
|
||||
}
|
||||
}
|
||||
|
||||
return (unsigned char)*gptr();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EncryptStreamBuf::read_chars
|
||||
// Access: Private
|
||||
// Description: Gets some characters from the source stream.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
size_t EncryptStreamBuf::
|
||||
read_chars(char *start, size_t length) {
|
||||
if (_in_read_overflow_buffer != 0) {
|
||||
// Take from the overflow buffer.
|
||||
length = min(length, _in_read_overflow_buffer);
|
||||
memcpy(start, _read_overflow_buffer, length);
|
||||
_in_read_overflow_buffer -= length;
|
||||
memcpy(_read_overflow_buffer + length, _read_overflow_buffer, _in_read_overflow_buffer);
|
||||
return length;
|
||||
}
|
||||
|
||||
unsigned char *source_buffer = (unsigned char *)alloca(length);
|
||||
size_t max_read_buffer = length + _read_block_size;
|
||||
unsigned char *read_buffer = (unsigned char *)alloca(max_read_buffer);
|
||||
|
||||
int bytes_read = 0;
|
||||
|
||||
do {
|
||||
// Get more bytes from the stream.
|
||||
if (!_read_valid) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_source->read((char *)source_buffer, length);
|
||||
size_t source_length = _source->gcount();
|
||||
|
||||
bytes_read = 0;
|
||||
int result;
|
||||
if (source_length != 0) {
|
||||
result =
|
||||
EVP_DecryptUpdate(&_read_ctx, read_buffer, &bytes_read,
|
||||
source_buffer, source_length);
|
||||
} else {
|
||||
result =
|
||||
EVP_DecryptFinal(&_read_ctx, read_buffer, &bytes_read);
|
||||
_read_valid = false;
|
||||
}
|
||||
|
||||
if (result <= 0) {
|
||||
express_cat.error()
|
||||
<< "Error decrypting stream.\n";
|
||||
if (_read_valid) {
|
||||
EVP_CIPHER_CTX_cleanup(&_read_ctx);
|
||||
_read_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
} while (bytes_read == 0);
|
||||
|
||||
// Now store the read bytes in the output stream.
|
||||
if ((size_t)bytes_read <= length) {
|
||||
// No overflow.
|
||||
memcpy(start, read_buffer, bytes_read);
|
||||
return bytes_read;
|
||||
|
||||
} else {
|
||||
// We have to save some of the returned bytes in the overflow
|
||||
// buffer.
|
||||
_in_read_overflow_buffer = bytes_read - length;
|
||||
nassertr(_in_read_overflow_buffer <= _read_block_size, 0);
|
||||
|
||||
memcpy(_read_overflow_buffer, read_buffer + length,
|
||||
_in_read_overflow_buffer);
|
||||
memcpy(start, read_buffer, length);
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EncryptStreamBuf::write_chars
|
||||
// Access: Private
|
||||
// Description: Sends some characters to the dest stream.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EncryptStreamBuf::
|
||||
write_chars(const char *start, size_t length) {
|
||||
if (_write_valid) {
|
||||
size_t max_write_buffer = length + _write_block_size;
|
||||
unsigned char *write_buffer = (unsigned char *)alloca(max_write_buffer);
|
||||
|
||||
int bytes_written = 0;
|
||||
int result =
|
||||
EVP_EncryptUpdate(&_write_ctx, write_buffer, &bytes_written,
|
||||
(unsigned char *)start, length);
|
||||
if (result <= 0) {
|
||||
express_cat.error()
|
||||
<< "Error encrypting stream.\n";
|
||||
}
|
||||
_dest->write((const char *)write_buffer, bytes_written);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAVE_SSL
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
// Filename: encryptStreamBuf.h
|
||||
// Created by: drose (01Sep04)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ENCRYPTSTREAMBUF_H
|
||||
#define ENCRYPTSTREAMBUF_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
// This module is not compiled if OpenSSL is not available.
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : EncryptStreamBuf
|
||||
// Description : The streambuf object that implements
|
||||
// IDecompressStream and OCompressStream.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDAEXPRESS EncryptStreamBuf : public streambuf {
|
||||
public:
|
||||
EncryptStreamBuf();
|
||||
virtual ~EncryptStreamBuf();
|
||||
|
||||
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 close_write();
|
||||
|
||||
protected:
|
||||
virtual int overflow(int c);
|
||||
virtual int sync(void);
|
||||
virtual int underflow(void);
|
||||
|
||||
private:
|
||||
size_t read_chars(char *start, size_t length);
|
||||
void write_chars(const char *start, size_t length);
|
||||
|
||||
private:
|
||||
istream *_source;
|
||||
bool _owns_source;
|
||||
|
||||
ostream *_dest;
|
||||
bool _owns_dest;
|
||||
|
||||
bool _read_valid;
|
||||
EVP_CIPHER_CTX _read_ctx;
|
||||
size_t _read_block_size;
|
||||
unsigned char *_read_overflow_buffer;
|
||||
size_t _in_read_overflow_buffer;
|
||||
|
||||
bool _write_valid;
|
||||
EVP_CIPHER_CTX _write_ctx;
|
||||
size_t _write_block_size;
|
||||
};
|
||||
|
||||
#endif // HAVE_SSL
|
||||
|
||||
#endif
|
||||
|
|
@ -14,6 +14,8 @@
|
|||
#include "datagramSink.cxx"
|
||||
#include "dcast.cxx"
|
||||
#include "error_utils.cxx"
|
||||
#include "encryptStreamBuf.cxx"
|
||||
#include "encryptStream.cxx"
|
||||
#include "get_config_path.cxx"
|
||||
#include "hashGeneratorBase.cxx"
|
||||
#include "hashVal.cxx"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "patchfile.cxx"
|
||||
#include "password_hash.cxx"
|
||||
#include "pmutex.cxx"
|
||||
#include "profileTimer.cxx"
|
||||
#include "pta_uchar.cxx"
|
||||
|
|
|
|||
|
|
@ -74,6 +74,103 @@ get_scale_factor() const {
|
|||
return _new_scale_factor;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Multifile::set_encryption_flag
|
||||
// Access: Published
|
||||
// Description: Sets the flag indicating whether subsequently-added
|
||||
// subfiles should be encrypted before writing them to
|
||||
// the multifile. If true, subfiles will be encrypted;
|
||||
// if false (the default), they will be written without
|
||||
// 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.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void Multifile::
|
||||
set_encryption_flag(bool flag) {
|
||||
#ifndef HAVE_SSL
|
||||
if (flag) {
|
||||
express_cat.warning()
|
||||
<< "OpenSSL not compiled in; cannot generated compressed multifiles.\n";
|
||||
flag = false;
|
||||
}
|
||||
#endif // HAVE_SSL
|
||||
_encryption_flag = flag;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Multifile::get_encryption_flag
|
||||
// Access: Published
|
||||
// Description: Returns the flag indicating whether
|
||||
// subsequently-added subfiles should be encrypted
|
||||
// before writing them to the multifile. See
|
||||
// set_encryption_flag().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool Multifile::
|
||||
get_encryption_flag() const {
|
||||
return _encryption_flag;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Multifile::set_encryption_password
|
||||
// Access: Published
|
||||
// Description: Specifies the password that will be used to encrypt
|
||||
// subfiles subsequently added to the multifile, if the
|
||||
// encryption flag is also set true (see
|
||||
// set_encryption_flag()).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void Multifile::
|
||||
set_encryption_password(const string &password) {
|
||||
_encryption_password = password;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Multifile::get_encryption_password
|
||||
// Access: Published
|
||||
// Description: Returns the password that will be used to encrypt
|
||||
// subfiles subsequently added to the multifile. See
|
||||
// set_encryption_password().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const string &Multifile::
|
||||
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
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "streamReader.h"
|
||||
#include "datagram.h"
|
||||
#include "zStream.h"
|
||||
#include "encryptStream.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
|
@ -37,6 +38,18 @@ const size_t Multifile::_header_size = 6;
|
|||
const int Multifile::_current_major_ver = 1;
|
||||
const int Multifile::_current_minor_ver = 0;
|
||||
|
||||
// To confirm that the supplied password matches, we write the
|
||||
// Mutifile magic header at the beginning of the encrypted stream.
|
||||
// I suppose this does compromise the encryption security a tiny
|
||||
// bit by making it easy for crackers to validate that a
|
||||
// particular password guess matches or doesn't match, but the
|
||||
// encryption algorithm doesn't depend on this being difficult
|
||||
// anyway.
|
||||
const char Multifile::_encrypt_header[] = "crypty";
|
||||
const size_t Multifile::_encrypt_header_size = 6;
|
||||
|
||||
|
||||
|
||||
//
|
||||
// A Multifile consists of the following elements:
|
||||
//
|
||||
|
|
@ -65,9 +78,10 @@ const int Multifile::_current_minor_ver = 0;
|
|||
// uint32 The address of this subfile's data record.
|
||||
// uint32 The length in bytes of this subfile's data record.
|
||||
// uint16 The Subfile::_flags member.
|
||||
// [uint32] The original, uncompressed length of the subfile, if it
|
||||
// is compressed. This field is only present if the
|
||||
// SF_compressed bit is set in _flags.
|
||||
// [uint32] The original, uncompressed and unencrypted length of the
|
||||
// subfile, if it is compressed or encrypted. This field
|
||||
// is only present if one or both of the SF_compressed
|
||||
// or SF_encrypted bits are set in _flags.
|
||||
// uint16 The length in bytes of the subfile's name.
|
||||
// char[n] The subfile's name.
|
||||
//
|
||||
|
|
@ -93,6 +107,7 @@ Multifile() {
|
|||
_needs_repack = false;
|
||||
_scale_factor = 1;
|
||||
_new_scale_factor = 1;
|
||||
_encryption_flag = false;
|
||||
_file_major_ver = 0;
|
||||
_file_minor_ver = 0;
|
||||
}
|
||||
|
|
@ -441,6 +456,7 @@ flush() {
|
|||
Subfile *subfile = (*pi);
|
||||
_last_index = _next_index;
|
||||
_next_index = subfile->write_index(*_write, _next_index, this);
|
||||
nassertr(_next_index == _write->tellp(), false);
|
||||
_next_index = pad_to_streampos(_next_index);
|
||||
nassertr(_next_index == _write->tellp(), false);
|
||||
}
|
||||
|
|
@ -450,12 +466,15 @@ flush() {
|
|||
StreamWriter writer(_write);
|
||||
writer.add_uint32(0);
|
||||
_next_index += 4;
|
||||
nassertr(_next_index == _write->tellp(), false);
|
||||
_next_index = pad_to_streampos(_next_index);
|
||||
|
||||
// All right, now write out each subfile's data.
|
||||
for (pi = _new_subfiles.begin(); pi != _new_subfiles.end(); ++pi) {
|
||||
Subfile *subfile = (*pi);
|
||||
_next_index = subfile->write_data(*_write, _read, _next_index);
|
||||
_next_index = subfile->write_data(*_write, _read, _next_index,
|
||||
this);
|
||||
nassertr(_next_index == _write->tellp(), false);
|
||||
_next_index = pad_to_streampos(_next_index);
|
||||
if (subfile->is_data_invalid()) {
|
||||
wrote_ok = false;
|
||||
|
|
@ -751,16 +770,31 @@ is_subfile_compressed(int index) const {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Multifile::get_subfile_compressed_length
|
||||
// Function: Multifile::is_subfile_encrypted
|
||||
// Access: Published
|
||||
// Description: Returns true if the indicated subfile has been
|
||||
// encrypted when stored within the archive, false
|
||||
// otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool Multifile::
|
||||
is_subfile_encrypted(int index) const {
|
||||
nassertr(index >= 0 && index < (int)_subfiles.size(), 0);
|
||||
return (_subfiles[index]->_flags & SF_encrypted) != 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Multifile::get_subfile_internal_length
|
||||
// Access: Published
|
||||
// Description: Returns the number of bytes the indicated subfile
|
||||
// consumes within the archive. For compressed
|
||||
// subfiles, this will generally be smaller than
|
||||
// get_subfile_length(); for noncompressed subfiles, it
|
||||
// will be equal.
|
||||
// get_subfile_length(); for encrypted (but
|
||||
// noncompressed) subfiles, it may be slightly
|
||||
// different, for noncompressed and nonencrypted
|
||||
// subfiles, it will be equal.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
size_t Multifile::
|
||||
get_subfile_compressed_length(int index) const {
|
||||
get_subfile_internal_length(int index) const {
|
||||
nassertr(index >= 0 && index < (int)_subfiles.size(), 0);
|
||||
return _subfiles[index]->_data_length;
|
||||
}
|
||||
|
|
@ -811,6 +845,33 @@ open_read_subfile(int index) {
|
|||
new ISubStream(_read, subfile->_data_start,
|
||||
subfile->_data_start + (streampos)subfile->_data_length);
|
||||
|
||||
if ((subfile->_flags & SF_encrypted) != 0) {
|
||||
#ifndef HAVE_SSL
|
||||
express_cat.error()
|
||||
<< "OpenSSL not compiled in; cannot read encrypted multifiles.\n";
|
||||
delete stream;
|
||||
return NULL;
|
||||
#else // HAVE_SSL
|
||||
// The subfile is encrypted. So actually, return an
|
||||
// IDecryptStream that wraps around the ISubStream.
|
||||
IDecryptStream *wrapper =
|
||||
new IDecryptStream(stream, true, _encryption_password);
|
||||
stream = wrapper;
|
||||
|
||||
// Validate the password by confirming that the encryption header
|
||||
// matches.
|
||||
char this_header[_encrypt_header_size];
|
||||
stream->read(this_header, _encrypt_header_size);
|
||||
if (stream->fail() || stream->gcount() != (unsigned)_encrypt_header_size ||
|
||||
memcmp(this_header, _encrypt_header, _encrypt_header_size) != 0) {
|
||||
express_cat.error()
|
||||
<< "Unable to decrypt subfile " << subfile->_name << ".\n";
|
||||
delete stream;
|
||||
return NULL;
|
||||
}
|
||||
#endif // HAVE_SSL
|
||||
}
|
||||
|
||||
if ((subfile->_flags & SF_compressed) != 0) {
|
||||
#ifndef HAVE_ZLIB
|
||||
express_cat.error()
|
||||
|
|
@ -1086,8 +1147,8 @@ extract_subfile_to(int index, ostream &out) {
|
|||
// Description: Assumes the _write pointer is at the indicated fpos,
|
||||
// rounds the fpos up to the next legitimate address
|
||||
// (using normalize_streampos()), and writes enough
|
||||
// zeros to the stream to fill the gap. Returns the new
|
||||
// fpos.
|
||||
// zeroes to the stream to fill the gap. Returns the
|
||||
// new fpos.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
streampos Multifile::
|
||||
pad_to_streampos(streampos fpos) {
|
||||
|
|
@ -1098,6 +1159,7 @@ pad_to_streampos(streampos fpos) {
|
|||
_write->put(0);
|
||||
fpos += 1; // VC++ doesn't define streampos++ (!)
|
||||
}
|
||||
nassertr(_write->tellp() == fpos, fpos);
|
||||
return fpos;
|
||||
}
|
||||
|
||||
|
|
@ -1120,6 +1182,12 @@ add_new_subfile(Subfile *subfile, int compression_level) {
|
|||
#endif // HAVE_ZLIB
|
||||
}
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
if (_encryption_flag) {
|
||||
subfile->_flags |= SF_encrypted;
|
||||
}
|
||||
#endif // HAVE_SSL
|
||||
|
||||
if (_next_index != (streampos)0) {
|
||||
// If we're adding a Subfile to an already-existing Multifile, we
|
||||
// will eventually need to repack the file.
|
||||
|
|
@ -1348,7 +1416,7 @@ read_index(istream &read, streampos fpos, Multifile *multifile) {
|
|||
_data_start = multifile->word_to_streampos(reader.get_uint32());
|
||||
_data_length = reader.get_uint32();
|
||||
_flags = reader.get_uint16();
|
||||
if ((_flags & SF_compressed) != 0) {
|
||||
if ((_flags & (SF_compressed | SF_encrypted)) != 0) {
|
||||
_uncompressed_length = reader.get_uint32();
|
||||
} else {
|
||||
_uncompressed_length = _data_length;
|
||||
|
|
@ -1400,7 +1468,7 @@ write_index(ostream &write, streampos fpos, Multifile *multifile) {
|
|||
dg.add_uint32(multifile->streampos_to_word(_data_start));
|
||||
dg.add_uint32(_data_length);
|
||||
dg.add_uint16(_flags);
|
||||
if ((_flags & SF_compressed) != 0) {
|
||||
if ((_flags & (SF_compressed | SF_encrypted)) != 0) {
|
||||
dg.add_uint32(_uncompressed_length);
|
||||
}
|
||||
dg.add_uint16(_name.length());
|
||||
|
|
@ -1449,7 +1517,8 @@ write_index(ostream &write, streampos fpos, Multifile *multifile) {
|
|||
// contents of the Subfile during a repack() operation.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
streampos Multifile::Subfile::
|
||||
write_data(ostream &write, istream *read, streampos fpos) {
|
||||
write_data(ostream &write, istream *read, streampos fpos,
|
||||
Multifile *multifile) {
|
||||
nassertr(write.tellp() == fpos, fpos);
|
||||
|
||||
istream *source = _source;
|
||||
|
|
@ -1494,6 +1563,28 @@ write_data(ostream &write, istream *read, streampos fpos) {
|
|||
} else {
|
||||
// We do have source data. Copy it in, and also measure its
|
||||
// length.
|
||||
ostream *putter = &write;
|
||||
bool delete_putter = false;
|
||||
|
||||
#ifndef HAVE_SSL
|
||||
// Without OpenSSL, we can't support encryption. The flag had
|
||||
// better not be set.
|
||||
nassertr((_flags & SF_encrypted) == 0, fpos);
|
||||
#else // HAVE_ZLIB
|
||||
if ((_flags & SF_encrypted) != 0) {
|
||||
// Write it encrypted.
|
||||
putter = new OEncryptStream(putter, delete_putter,
|
||||
multifile->_encryption_password,
|
||||
multifile->_encryption_algorithm);
|
||||
delete_putter = true;
|
||||
|
||||
// Also write the encrypt_header to the beginning of the
|
||||
// encrypted stream, so we can validate the password on
|
||||
// decryption.
|
||||
putter->write(_encrypt_header, _encrypt_header_size);
|
||||
}
|
||||
#endif // HAVE_ZLIB
|
||||
|
||||
#ifndef HAVE_ZLIB
|
||||
// Without ZLIB, we can't support compression. The flag had
|
||||
// better not be set.
|
||||
|
|
@ -1501,31 +1592,27 @@ write_data(ostream &write, istream *read, streampos fpos) {
|
|||
#else // HAVE_ZLIB
|
||||
if ((_flags & SF_compressed) != 0) {
|
||||
// Write it compressed.
|
||||
streampos write_start = write.tellp();
|
||||
_uncompressed_length = 0;
|
||||
OCompressStream zstream(&write, false, _compression_level);
|
||||
int byte = source->get();
|
||||
while (!source->eof() && !source->fail()) {
|
||||
_uncompressed_length++;
|
||||
zstream.put(byte);
|
||||
byte = source->get();
|
||||
}
|
||||
zstream.close();
|
||||
streampos write_end = write.tellp();
|
||||
_data_length = (size_t)(write_end - write_start);
|
||||
} else
|
||||
putter = new OCompressStream(putter, delete_putter, _compression_level);
|
||||
delete_putter = true;
|
||||
}
|
||||
#endif // HAVE_ZLIB
|
||||
{
|
||||
// Write it uncompressed.
|
||||
_uncompressed_length = 0;
|
||||
int byte = source->get();
|
||||
while (!source->eof() && !source->fail()) {
|
||||
_uncompressed_length++;
|
||||
write.put(byte);
|
||||
byte = source->get();
|
||||
}
|
||||
_data_length = _uncompressed_length;
|
||||
}
|
||||
|
||||
streampos write_start = fpos;
|
||||
_uncompressed_length = 0;
|
||||
|
||||
int byte = source->get();
|
||||
while (!source->eof() && !source->fail()) {
|
||||
_uncompressed_length++;
|
||||
putter->put(byte);
|
||||
byte = source->get();
|
||||
}
|
||||
|
||||
if (delete_putter) {
|
||||
delete putter;
|
||||
}
|
||||
|
||||
streampos write_end = write.tellp();
|
||||
_data_length = (size_t)(write_end - write_start);
|
||||
}
|
||||
|
||||
// We can't set _data_start until down here, after we have read the
|
||||
|
|
@ -1559,7 +1646,7 @@ rewrite_index_data_start(ostream &write, Multifile *multifile) {
|
|||
writer.add_uint32(multifile->streampos_to_word(_data_start));
|
||||
writer.add_uint32(_data_length);
|
||||
writer.add_uint16(_flags);
|
||||
if ((_flags & SF_compressed) != 0) {
|
||||
if ((_flags & (SF_compressed | SF_encrypted)) != 0) {
|
||||
writer.add_uint32(_uncompressed_length);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,13 @@ PUBLISHED:
|
|||
void set_scale_factor(size_t scale_factor);
|
||||
INLINE size_t get_scale_factor() const;
|
||||
|
||||
INLINE void set_encryption_flag(bool flag);
|
||||
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);
|
||||
string update_subfile(const string &subfile_name, const Filename &filename,
|
||||
|
|
@ -71,7 +78,8 @@ PUBLISHED:
|
|||
const string &get_subfile_name(int index) const;
|
||||
size_t get_subfile_length(int index) const;
|
||||
bool is_subfile_compressed(int index) const;
|
||||
size_t get_subfile_compressed_length(int index) const;
|
||||
bool is_subfile_encrypted(int index) const;
|
||||
size_t get_subfile_internal_length(int index) const;
|
||||
|
||||
INLINE string read_subfile(int index);
|
||||
istream *open_read_subfile(int index);
|
||||
|
|
@ -99,6 +107,7 @@ private:
|
|||
SF_index_invalid = 0x0002,
|
||||
SF_data_invalid = 0x0004,
|
||||
SF_compressed = 0x0008,
|
||||
SF_encrypted = 0x0010,
|
||||
};
|
||||
|
||||
class Subfile {
|
||||
|
|
@ -109,7 +118,8 @@ private:
|
|||
Multifile *multfile);
|
||||
streampos write_index(ostream &write, streampos fpos,
|
||||
Multifile *multifile);
|
||||
streampos write_data(ostream &write, istream *read, streampos fpos);
|
||||
streampos write_data(ostream &write, istream *read, streampos fpos,
|
||||
Multifile *multifile);
|
||||
void rewrite_index_data_start(ostream &write, Multifile *multifile);
|
||||
void rewrite_index_flags(ostream &write);
|
||||
INLINE bool is_deleted() const;
|
||||
|
|
@ -155,6 +165,10 @@ private:
|
|||
size_t _scale_factor;
|
||||
size_t _new_scale_factor;
|
||||
|
||||
bool _encryption_flag;
|
||||
string _encryption_password;
|
||||
string _encryption_algorithm;
|
||||
|
||||
ifstream _read_file;
|
||||
ofstream _write_file;
|
||||
fstream _read_write_file;
|
||||
|
|
@ -168,6 +182,9 @@ private:
|
|||
static const int _current_major_ver;
|
||||
static const int _current_minor_ver;
|
||||
|
||||
static const char _encrypt_header[];
|
||||
static const size_t _encrypt_header_size;
|
||||
|
||||
friend class Subfile;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
// Filename: password_hash.cxx
|
||||
// Created by: drose (01Sep04)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "password_hash.h"
|
||||
|
||||
// The functions defined within this file rely on algorithms defined
|
||||
// within OpenSSL.
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: password_hash
|
||||
// Access: Published
|
||||
// Description: Generates a non-reversible hash of a particular
|
||||
// length based on an arbitrary password and a random
|
||||
// salt. This is much stronger than the algorithm
|
||||
// implemented by the standard Unix crypt().
|
||||
//
|
||||
// The resulting hash can be useful for two primary
|
||||
// purposes: (1) the hash may be recorded to disk in
|
||||
// lieu of recording plaintext passwords, for validation
|
||||
// against a password entered by the user later (which
|
||||
// should produce the same hash given a particular
|
||||
// salt), or (2) the hash may be used as input to an
|
||||
// encryption algorithm that requires a key of a
|
||||
// particular length.
|
||||
//
|
||||
// password is the text password provided by a user.
|
||||
//
|
||||
// salt should be a string of arbitrary random bytes (it
|
||||
// need not be crypotographically secure, just different
|
||||
// for each different hash).
|
||||
//
|
||||
// iters should be a number in the thousands to indicate
|
||||
// the number of times the hash algorithm should be
|
||||
// applied. In general, iters should be chosen to make
|
||||
// the computation as expensive as it can be and still
|
||||
// be tolerable, to reduce the attractiveness of a
|
||||
// brute-force attack.
|
||||
//
|
||||
// keylen is the length in bytes of the required key
|
||||
// hash.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string
|
||||
password_hash(const string &password, const string &salt,
|
||||
int iters, int keylen) {
|
||||
nassertr(iters > 0 && keylen > 0, string());
|
||||
unsigned char *dk = new unsigned char[keylen];
|
||||
int result =
|
||||
PKCS5_PBKDF2_HMAC_SHA1((const char *)password.data(), password.length(),
|
||||
(unsigned char *)salt.data(), salt.length(),
|
||||
iters, keylen, dk);
|
||||
nassertr(result > 0, string());
|
||||
|
||||
string hash((char *)dk, keylen);
|
||||
delete[] dk;
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // HAVE_SSL
|
||||
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// Filename: password_hash.h
|
||||
// Created by: drose (01Sep04)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef PASSWORD_HASH_H
|
||||
#define PASSWORD_HASH_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
// The functions defined within this file rely on algorithms defined
|
||||
// within OpenSSL.
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
BEGIN_PUBLISH
|
||||
|
||||
string password_hash(const string &password, const string &salt,
|
||||
int iters, int keylen);
|
||||
|
||||
END_PUBLISH
|
||||
|
||||
#endif // HAVE_SSL
|
||||
|
||||
#endif
|
||||
|
|
@ -83,7 +83,7 @@ mount(Multifile *multifile, const string &mount_point, int flags) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool VirtualFileSystem::
|
||||
mount(const Filename &physical_filename, const string &mount_point,
|
||||
int flags) {
|
||||
int flags, const string &password) {
|
||||
if (!physical_filename.exists()) {
|
||||
express_cat.warning()
|
||||
<< "Attempt to mount " << physical_filename << ", not found.\n";
|
||||
|
|
@ -103,6 +103,8 @@ mount(const Filename &physical_filename, const string &mount_point,
|
|||
// It's not a directory; it must be a Multifile.
|
||||
Multifile *multifile = new Multifile;
|
||||
|
||||
multifile->set_encryption_password(password);
|
||||
|
||||
// For now these are always opened read only. Maybe later we'll
|
||||
// support read-write on Multifiles.
|
||||
flags |= MF_read_only;
|
||||
|
|
@ -550,7 +552,21 @@ get_global_ptr() {
|
|||
mount_desc = ExecutionEnvironment::expand_string(mount_desc);
|
||||
Filename physical_filename = Filename::from_os_specific(mount_desc);
|
||||
|
||||
_global_ptr->mount(physical_filename, mount_point, 0);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -668,3 +684,25 @@ found_match(PT(VirtualFile) &found_file, VirtualFileComposite *&composite_file,
|
|||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VirtualFileSystem::parse_option
|
||||
// Access: Private, Static
|
||||
// Description: Parses one of the option flags in the options list on
|
||||
// the vfs-mount Config.prc line.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VirtualFileSystem::
|
||||
parse_option(const string &option, int &flags, string &password) {
|
||||
if (option == "0" || option.empty()) {
|
||||
// 0 is the null option.
|
||||
|
||||
} else if (option == "ro") {
|
||||
flags |= MF_read_only;
|
||||
|
||||
} else if (option.substr(0, 3) == "pw:") {
|
||||
password = option.substr(3);
|
||||
|
||||
} else {
|
||||
express_cat.warning()
|
||||
<< "Invalid option on vfs-mount: \"" << option << "\"\n";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,8 @@ PUBLISHED:
|
|||
};
|
||||
|
||||
bool mount(Multifile *multifile, const string &mount_point, int flags);
|
||||
bool mount(const Filename &physical_filename, const string &mount_point, int flags);
|
||||
bool mount(const Filename &physical_filename, const string &mount_point,
|
||||
int flags, const string &password = "");
|
||||
int unmount(Multifile *multifile);
|
||||
int unmount(const Filename &physical_filename);
|
||||
int unmount_point(const string &mount_point);
|
||||
|
|
@ -94,6 +95,8 @@ private:
|
|||
Filename normalize_mount_point(const string &mount_point) const;
|
||||
bool found_match(PT(VirtualFile) &found_file, VirtualFileComposite *&composite_file,
|
||||
VirtualFileMount *mount, const string &local_filename) const;
|
||||
static void parse_option(const string &option,
|
||||
int &flags, string &password);
|
||||
|
||||
typedef pvector<VirtualFileMount *> Mounts;
|
||||
Mounts _mounts;
|
||||
|
|
|
|||
Loading…
Reference in New Issue