new security enhancements for toontown client and server

This commit is contained in:
David Rose 2003-09-19 15:38:22 +00:00
parent a0ccebc539
commit 577c5ac28c
37 changed files with 1021 additions and 406 deletions

View File

@ -6,8 +6,7 @@
#begin lib_target
#define TARGET downloader
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx \
$[if $[HAVE_ZLIB], $[TARGET]_composite4.cxx] \
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
#define SOURCES \
config_downloader.h \
@ -16,8 +15,10 @@
bioStreamPtr.I bioStreamPtr.h \
bioStream.I bioStream.h bioStreamBuf.h \
chunkedStream.I chunkedStream.h chunkedStreamBuf.h \
decompressor.h \
documentSpec.I documentSpec.h \
downloadDb.I downloadDb.h \
download_utils.h \
extractor.h \
httpAuthorization.I httpAuthorization.h \
httpBasicAuthorization.I httpBasicAuthorization.h \
@ -30,10 +31,9 @@
identityStream.I identityStream.h identityStreamBuf.h \
multiplexStream.I multiplexStream.h \
multiplexStreamBuf.I multiplexStreamBuf.h \
patcher.h patcher.I \
socketStream.h socketStream.I \
urlSpec.I urlSpec.h \
$[if $[HAVE_ZLIB], decompressor.h download_utils.h] \
$[if $[HAVE_CRYPTO], patcher.cxx patcher.h patcher.I]
urlSpec.I urlSpec.h
#define INCLUDED_SOURCES \
config_downloader.cxx \
@ -42,8 +42,10 @@
bioStreamPtr.cxx \
bioStream.cxx bioStreamBuf.cxx \
chunkedStream.cxx chunkedStreamBuf.cxx \
decompressor.cxx \
documentSpec.cxx \
downloadDb.cxx \
download_utils.cxx \
extractor.cxx \
httpAuthorization.cxx \
httpBasicAuthorization.cxx \
@ -55,9 +57,9 @@
httpEnum.cxx \
identityStream.cxx identityStreamBuf.cxx \
multiplexStream.cxx multiplexStreamBuf.cxx \
patcher.cxx \
socketStream.cxx \
urlSpec.cxx \
$[if $[HAVE_ZLIB], decompressor.cxx download_utils.cxx]
urlSpec.cxx
#define INSTALL_HEADERS \
asyncUtility.h asyncUtility.I \

View File

@ -17,6 +17,7 @@
////////////////////////////////////////////////////////////////////
#include "bioPtr.h"
#include "urlSpec.h"
#ifdef HAVE_SSL

View File

@ -16,7 +16,7 @@
//
////////////////////////////////////////////////////////////////////
#include "bioPtr.h"
#include "bioStreamPtr.h"
#ifdef HAVE_SSL

View File

@ -115,6 +115,17 @@ config_downloader.GetDouble("http-timeout", 20.0);
const int http_max_connect_count =
config_downloader.GetInt("http-max-connect-count", 10);
// These provide a default client certificate to offer up should an
// SSL server demand one. The files references a PEM-formatted file
// that includes a public and private key specification. A
// connection-specific certificate may also be specified at runtime on
// the HTTPClient object, but this will require having a different
// HTTPClient object for each differently-certificated connection.
const string http_client_certificate_filename =
config_downloader.GetString("http-client-certificate-filename", "");
const string http_client_certificate_passphrase =
config_downloader.GetString("http-client-certificate-passphrase", "");
ConfigureFn(config_downloader) {
#ifdef HAVE_SSL
HTTPChannel::init_type();

View File

@ -51,5 +51,7 @@ extern const bool http_proxy_tunnel;
extern const double connect_timeout;
extern const double http_timeout;
extern const int http_max_connect_count;
extern const string http_client_certificate_filename;
extern const string http_client_certificate_passphrase;
#endif

View File

@ -16,13 +16,15 @@
//
////////////////////////////////////////////////////////////////////
// This file is compiled only if we have zlib installed.
#include "pandabase.h"
#ifdef HAVE_ZLIB
#include "config_downloader.h"
#include "error_utils.h"
#include "filename.h"
#include "buffer.h"
#include "ramfile.h"
#include "zStream.h"
#include "config_express.h"
@ -273,3 +275,5 @@ cleanup() {
_decompress = NULL;
}
}
#endif // HAVE_ZLIB

View File

@ -20,6 +20,9 @@
#define DECOMPRESSOR_H
#include "pandabase.h"
#ifdef HAVE_ZLIB
#include "filename.h"
class Ramfile;
@ -58,4 +61,6 @@ private:
#include "decompressor.I"
#endif // HAVE_ZLIB
#endif

View File

@ -20,6 +20,7 @@
#include "downloadDb.h"
#include "streamReader.h"
#include "streamWriter.h"
#include "ramfile.h"
#include <algorithm>
@ -481,11 +482,7 @@ write(ostream &out) const {
<< " phase: " << _phase << endl
<< " size: " << _size << endl
<< " status: " << _status << endl
<< " hash: [" << _hash.get_value(0)
<< " " << _hash.get_value(1)
<< " " << _hash.get_value(2)
<< " " << _hash.get_value(3)
<< "]" << endl;
<< " hash: " << _hash << endl;
out << "--------------------------------------------------" << endl;
pvector< PT(FileRecord) >::const_iterator i = _file_records.begin();
for(; i != _file_records.end(); ++i) {
@ -753,12 +750,7 @@ parse_mfr(const string &data) {
mfr->_name = back_to_front_slash(mfr->_name);
// Read the hash value
HashVal hash;
hash.set_value(0, di.get_uint32());
hash.set_value(1, di.get_uint32());
hash.set_value(2, di.get_uint32());
hash.set_value(3, di.get_uint32());
mfr->_hash = hash;
mfr->_hash.read_datagram(di);
downloader_cat.debug()
<< "Parsed multifile record: " << mfr->_name << " phase: " << mfr->_phase
@ -812,7 +804,7 @@ read(StreamReader &sr, bool want_server_info) {
// Read the header
string header;
header = sr.extract_bytes(_header_length);
if (header.size() != _header_length) {
if (header.size() != (size_t)_header_length) {
downloader_cat.error() << "truncated db file" << endl;
return false;
}
@ -832,7 +824,7 @@ read(StreamReader &sr, bool want_server_info) {
int mfr_header_length = sizeof(PN_int32);
string mfr_header = sr.extract_bytes(mfr_header_length);
if (mfr_header.size() != mfr_header_length) {
if (mfr_header.size() != (size_t)mfr_header_length) {
downloader_cat.error() << "invalid mfr header" << endl;
return false;
}
@ -845,7 +837,7 @@ read(StreamReader &sr, bool want_server_info) {
// do not count the header length twice
int read_length = (mfr_length - mfr_header_length);
string mfr_record = sr.extract_bytes(read_length);
if (mfr_record.size() != read_length) {
if (mfr_record.size() != (size_t)read_length) {
downloader_cat.error() << "invalid mfr record" << endl;
return false;
}
@ -864,7 +856,7 @@ read(StreamReader &sr, bool want_server_info) {
// Read the header
string fr_header = sr.extract_bytes(fr_header_length);
if (fr_header.size() != fr_header_length) {
if (fr_header.size() != (size_t)fr_header_length) {
downloader_cat.error() << "invalid fr header" << endl;
return false;
}
@ -877,7 +869,7 @@ read(StreamReader &sr, bool want_server_info) {
int read_length = (fr_length - fr_header_length);
string fr_record = sr.extract_bytes(read_length);
if (fr_record.size() != read_length) {
if (fr_record.size() != (size_t)read_length) {
downloader_cat.error() << "invalid fr record" << endl;
return false;
}
@ -914,7 +906,6 @@ write(StreamWriter &sw, bool want_server_info) {
PN_int32 num_files;
PN_int32 name_length;
PN_int32 header_length;
HashVal hash;
// Iterate over the multifiles writing them to the stream
pvector< PT(MultifileRecord) >::const_iterator i = _mfile_records.begin();
@ -949,11 +940,7 @@ write(StreamWriter &sw, bool want_server_info) {
sw.add_int32(status);
sw.add_int32(num_files);
hash = (*i)->_hash;
sw.add_uint32(hash.get_value(0));
sw.add_uint32(hash.get_value(1));
sw.add_uint32(hash.get_value(2));
sw.add_uint32(hash.get_value(3));
(*i)->_hash.write_stream(sw);
// Only write out the file information if you are the server
if (want_server_info) {
@ -1217,7 +1204,6 @@ write_version_map(StreamWriter &sw) {
VersionMap::iterator vmi;
VectorHash::iterator i;
string name;
HashVal hash;
sw.add_int32(_versions.size());
for (vmi = _versions.begin(); vmi != _versions.end(); ++vmi) {
@ -1230,12 +1216,7 @@ write_version_map(StreamWriter &sw) {
sw.add_int32((*vmi).second.size());
for (i = (*vmi).second.begin(); i != (*vmi).second.end(); ++i) {
// *i will point to a HashVal
hash = *i;
// Write out each uint separately
sw.add_uint32(hash.get_value(0));
sw.add_uint32(hash.get_value(1));
sw.add_uint32(hash.get_value(2));
sw.add_uint32(hash.get_value(3));
(*i).write_stream(sw);
}
}
}
@ -1279,10 +1260,7 @@ read_version_map(StreamReader &sr) {
for (int j = 0; j < length; j++) {
HashVal hash;
hash.set_value(0, sr.get_uint32());
hash.set_value(1, sr.get_uint32());
hash.set_value(2, sr.get_uint32());
hash.set_value(3, sr.get_uint32());
hash.read_stream(sr);
if (sr.get_istream()->fail()) {
return false;
}
@ -1306,7 +1284,7 @@ write_version_map(ostream &out) const {
out << " " << (*vmi).first << endl;
for (i = (*vmi).second.begin(); i != (*vmi).second.end(); ++i) {
HashVal hash = *i;
out << " " << hash << endl;
out << " " << hash.as_dec() << endl;
}
}
out << endl;

View File

@ -30,11 +30,11 @@
#include "pmap.h"
#include "hashVal.h"
#include "buffer.h"
class StreamReader;
class StreamWriter;
typedef float Phase;
class Ramfile;
/*
//////////////////////////////////////////////////

View File

@ -16,13 +16,15 @@
//
////////////////////////////////////////////////////////////////////
// This file is compiled only if we have zlib installed.
#include "pandabase.h"
#ifdef HAVE_ZLIB
#include "download_utils.h"
#include "config_downloader.h"
#include <zlib.h>
ulong
unsigned long
check_crc(Filename name) {
ifstream read_stream;
name.set_binary();
@ -40,7 +42,7 @@ check_crc(Filename name) {
read_stream.read(buffer, buffer_length);
// Compute the crc
ulong crc = crc32(0L, Z_NULL, 0);
unsigned long crc = crc32(0L, Z_NULL, 0);
crc = crc32(crc, (uchar *)buffer, buffer_length);
delete buffer;
@ -48,7 +50,7 @@ check_crc(Filename name) {
return crc;
}
ulong
unsigned long
check_adler(Filename name) {
ifstream read_stream;
name.set_binary();
@ -66,10 +68,12 @@ check_adler(Filename name) {
read_stream.read(buffer, buffer_length);
// Compute the adler checksum
ulong adler = adler32(0L, Z_NULL, 0);
unsigned long adler = adler32(0L, Z_NULL, 0);
adler = adler32(adler, (uchar *)buffer, buffer_length);
delete buffer;
return adler;
}
#endif // HAVE_ZLIB

View File

@ -19,16 +19,20 @@
#ifndef DOWNLOAD_UTILS_H
#define DOWNLOAD_UTILS_H
#include <pandabase.h>
#include <filename.h>
#include <typedef.h>
#include "pandabase.h"
#ifdef HAVE_ZLIB
#include "filename.h"
BEGIN_PUBLISH
EXPCL_PANDAEXPRESS ulong check_crc(Filename name);
EXPCL_PANDAEXPRESS ulong check_adler(Filename name);
EXPCL_PANDAEXPRESS unsigned long check_crc(Filename name);
EXPCL_PANDAEXPRESS unsigned long check_adler(Filename name);
END_PUBLISH
#endif // HAVE_ZLIB
#endif

View File

@ -1,14 +1,13 @@
#include "config_downloader.cxx"
#include "asyncUtility.cxx"
#include "bioPtr.cxx"
#include "bioStreamPtr.cxx"
#include "bioStream.cxx"
#include "bioStreamBuf.cxx"
#include "bioStreamPtr.cxx"
#include "chunkedStream.cxx"
#include "chunkedStreamBuf.cxx"
#include "downloadDb.cxx"
#include "extractor.cxx"
#include "httpDate.cxx"
#include "httpEntityTag.cxx"
#include "config_downloader.cxx"
#include "decompressor.cxx"
#include "documentSpec.cxx"
#include "downloadDb.cxx"
#include "download_utils.cxx"
#include "extractor.cxx"

View File

@ -1,12 +1,15 @@
#include "httpAuthorization.cxx"
#include "httpBasicAuthorization.cxx"
#include "httpClient.cxx"
#include "httpChannel.cxx"
#include "httpClient.cxx"
#include "httpDate.cxx"
#include "httpDigestAuthorization.cxx"
#include "httpEntityTag.cxx"
#include "httpEnum.cxx"
#include "identityStream.cxx"
#include "identityStreamBuf.cxx"
#include "multiplexStream.cxx"
#include "multiplexStreamBuf.cxx"
#include "patcher.cxx"
#include "socketStream.cxx"
#include "urlSpec.cxx"

View File

@ -1,3 +0,0 @@
#include "download_utils.cxx"
#include "decompressor.cxx"

View File

@ -23,7 +23,7 @@
#include "identityStream.h"
#include "config_downloader.h"
#include "clockObject.h"
#include "buffer.h" // for Ramfile
#include "ramfile.h"
#ifdef HAVE_SSL
#ifdef REPORT_OPENSSL_ERRORS
@ -54,6 +54,7 @@ HTTPChannel(HTTPClient *client) :
_max_updates_per_second = 1.0f / _seconds_per_update;
_bytes_per_update = int(_max_bytes_per_second * _seconds_per_update);
_nonblocking = false;
_want_ssl = false;
_proxy_serves_document = false;
_proxy_tunnel_now = false;
@ -646,6 +647,7 @@ downcase(const string &s) {
return result;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::reached_done_state
// Access: Private
@ -1191,6 +1193,24 @@ run_setup_ssl() {
return false;
}
// It would be nice to use something like SSL_set_client_cert_cb()
// here to set a callback to provide the certificate should it be
// requested, or even to potentially provide any of a number of
// certificates according to the server's CA presented, but that
// interface as provided by OpenSSL is broken since there's no way
// to pass additional data to the callback function (and hence no
// way to tie it back to the HTTPChannel object, other than by
// building a messy mapping of SSL pointers back to HTTPChannel
// pointers).
if (_client->load_client_certificate()) {
SSL_use_certificate(ssl, _client->_client_certificate_pub);
SSL_use_PrivateKey(ssl, _client->_client_certificate_priv);
if (!SSL_check_private_key(ssl)) {
downloader_cat.warning()
<< "Client private key does not match public key!\n";
}
}
if (downloader_cat.is_spam()) {
downloader_cat.spam()
<< "SSL Ciphers available:\n";

View File

@ -44,6 +44,52 @@ get_try_all_direct() const {
return _try_all_direct;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPClient::set_client_certificate_filename
// Access: Published
// Description: Sets the filename of the pem-formatted file that will
// be read for the client public and private keys if an
// SSL server requests a certificate. Either this or
// set_client_certificate_pem() may be used to specify a
// client certificate.
////////////////////////////////////////////////////////////////////
INLINE void HTTPClient::
set_client_certificate_filename(const Filename &filename) {
_client_certificate_filename = filename;
_client_certificate_pem = string();
unload_client_certificate();
}
////////////////////////////////////////////////////////////////////
// Function: HTTPClient::set_client_certificate_pem
// Access: Published
// Description: Sets the pem-formatted contents of the certificate
// that will be parsed for the client public and private
// keys if an SSL server requests a certificate. Either
// this or set_client_certificate_filename() may be used
// to specify a client certificate.
////////////////////////////////////////////////////////////////////
INLINE void HTTPClient::
set_client_certificate_pem(const string &pem) {
_client_certificate_pem = pem;
_client_certificate_filename = Filename();
unload_client_certificate();
}
////////////////////////////////////////////////////////////////////
// Function: HTTPClient::set_client_certificate_passphrase
// Access: Published
// Description: Sets the passphrase used to decrypt the private key
// in the certificate named by
// set_client_certificate_filename() or
// set_client_certificate_pem().
////////////////////////////////////////////////////////////////////
INLINE void HTTPClient::
set_client_certificate_passphrase(const string &passphrase) {
_client_certificate_passphrase = passphrase;
unload_client_certificate();
}
////////////////////////////////////////////////////////////////////
// Function: HTTPClient::set_http_version
// Access: Published

View File

@ -128,6 +128,13 @@ HTTPClient() {
}
}
_client_certificate_filename = http_client_certificate_filename;
_client_certificate_passphrase = http_client_certificate_passphrase;
_client_certificate_loaded = false;
_client_certificate_pub = NULL;
_client_certificate_priv = NULL;
// The first time we create an HTTPClient, we must initialize the
// OpenSSL library.
if (!_ssl_initialized) {
@ -190,6 +197,8 @@ HTTPClient::
// Free all of the expected server definitions.
clear_expected_servers();
unload_client_certificate();
}
////////////////////////////////////////////////////////////////////
@ -599,6 +608,93 @@ get_username(const string &server, const string &realm) const {
return string();
}
////////////////////////////////////////////////////////////////////
// Function: HTTPClient::load_client_certificate
// Access: Published
// Description: Attempts to load the certificate named by
// set_client_certificate_filename() immediately, and
// returns true if successful, false otherwise.
//
// Normally this need not be explicitly called, since it
// will be called automatically if the server requests a
// certificate, but it may be useful to determine ahead
// of time if the certificate can be loaded correctly.
////////////////////////////////////////////////////////////////////
bool HTTPClient::
load_client_certificate() {
if (!_client_certificate_loaded) {
_client_certificate_loaded = true;
if (!_client_certificate_filename.empty()) {
_client_certificate_filename.set_text();
// First, read the complete file into memory.
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
if (!vfs->read_file(_client_certificate_filename,
_client_certificate_pem)) {
// Could not find or read file.
downloader_cat.warning()
<< "Could not read " << _client_certificate_filename << ".\n";
return false;
}
}
// Create an in-memory BIO to read the "file" from the memory
// buffer, and call the low-level routines to read the
// keys from the BIO.
BIO *mbio = BIO_new_mem_buf((void *)_client_certificate_pem.data(),
_client_certificate_pem.length());
ERR_clear_error();
_client_certificate_priv =
PEM_read_bio_PrivateKey(mbio, NULL, NULL,
(char *)_client_certificate_passphrase.c_str());
// Rewind the "file" to the beginning in order to read the public
// key (which might appear first in the file).
BIO_reset(mbio);
ERR_clear_error();
_client_certificate_pub =
PEM_read_bio_X509(mbio, NULL, NULL, NULL);
BIO_free(mbio);
NotifySeverity sev = NS_debug;
string source = "memory";
if (!_client_certificate_filename.empty()) {
// Only report status to "info" severity if we have read the
// certificate from a file. If it came from an in-memory image,
// a failure will presumably be handled by whoever set the
// image.
sev = NS_info;
source = _client_certificate_filename;
}
if (_client_certificate_priv != (EVP_PKEY *)NULL &&
_client_certificate_pub != (X509 *)NULL) {
downloader_cat.out(sev)
<< "Read client certificate from " << source << "\n";
} else {
if (_client_certificate_priv == (EVP_PKEY *)NULL) {
downloader_cat.out(sev)
<< "Could not read private key from " << source << "\n";
}
if (_client_certificate_pub == (X509 *)NULL) {
downloader_cat.out(sev)
<< "Could not read public key from " << source << "\n";
}
}
}
return (_client_certificate_priv != (EVP_PKEY *)NULL &&
_client_certificate_pub != (X509 *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: HTTPClient::get_http_version_string
// Access: Published
@ -1108,6 +1204,28 @@ generate_auth(const URLSpec &url, bool is_proxy, const string &challenge) {
return auth;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPClient::unload_client_certificate
// Access: Private
// Description: Frees the resources allocated by a previous call to
// load_client_certificate(), and marks the certificate
// unloaded.
////////////////////////////////////////////////////////////////////
void HTTPClient::
unload_client_certificate() {
if (_client_certificate_priv != (EVP_PKEY *)NULL) {
EVP_PKEY_free(_client_certificate_priv);
_client_certificate_priv = NULL;
}
if (_client_certificate_pub != (X509 *)NULL) {
X509_free(_client_certificate_pub);
_client_certificate_pub = NULL;
}
_client_certificate_loaded = false;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPClient::initialize_ssl
// Access: Private, Static
@ -1209,6 +1327,14 @@ load_verify_locations(SSL_CTX *ctx, const Filename &ca_file) {
<< "Entry " << i << " is crl\n";
}
} else if (itmp->x_pkey) {
// X509_STORE_add_crl(store, itmp->x_pkey);
// count++;
if (downloader_cat.is_spam()) {
downloader_cat.spam()
<< "Entry " << i << " is pkey\n";
}
} else {
if (downloader_cat.is_spam()) {
downloader_cat.spam()

View File

@ -82,6 +82,11 @@ PUBLISHED:
void set_username(const string &server, const string &realm, const string &username);
string get_username(const string &server, const string &realm) const;
INLINE void set_client_certificate_filename(const Filename &filename);
INLINE void set_client_certificate_pem(const string &pem);
INLINE void set_client_certificate_passphrase(const string &passphrase);
bool load_client_certificate();
INLINE void set_http_version(HTTPEnum::HTTPVersion version);
INLINE HTTPEnum::HTTPVersion get_http_version() const;
string get_http_version_string() const;
@ -125,6 +130,8 @@ private:
PT(HTTPAuthorization) generate_auth(const URLSpec &url, bool is_proxy,
const string &challenge);
void unload_client_certificate();
static void initialize_ssl();
static int load_verify_locations(SSL_CTX *ctx, const Filename &ca_file);
@ -158,12 +165,19 @@ private:
typedef pmap<string, Domain> Domains;
Domains _proxy_domains, _www_domains;
Filename _client_certificate_filename;
string _client_certificate_pem;
string _client_certificate_passphrase;
// List of allowable SSL servers to connect to. If the list is
// empty, any server is acceptable.
typedef pvector<X509_NAME *> ExpectedServers;
ExpectedServers _expected_servers;
SSL_CTX *_ssl_ctx;
bool _client_certificate_loaded;
X509 *_client_certificate_pub;
EVP_PKEY *_client_certificate_priv;
static bool _ssl_initialized;
static X509_STORE *_x509_store;

View File

@ -16,13 +16,13 @@
//
////////////////////////////////////////////////////////////////////
#include "config_downloader.h"
#include <filename.h>
#include "patcher.h"
#include "pandabase.h"
////////////////////////////////////////////////////////////////////
// Defines
////////////////////////////////////////////////////////////////////
#ifdef HAVE_SSL
#include "config_downloader.h"
#include "patcher.h"
#include "filename.h"
////////////////////////////////////////////////////////////////////
// Function: Patcher::Constructor
@ -88,3 +88,5 @@ int Patcher::
run(void) {
return _patchfile->run();
}
#endif // HAVE_SSL

View File

@ -15,16 +15,17 @@
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef PATCHER_H
#define PATCHER_H
//
////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include <filename.h>
#include <buffer.h>
#include <patchfile.h>
#include "pandabase.h"
#ifdef HAVE_SSL
#include "filename.h"
#include "buffer.h"
#include "patchfile.h"
////////////////////////////////////////////////////////////////////
// Class : Patcher
@ -49,4 +50,6 @@ private:
#include "patcher.I"
#endif // HAVE_SSL
#endif

View File

@ -4,7 +4,7 @@
#begin bin_target
#define TARGET apply_patch
#define BUILD_TARGET $[HAVE_CRYPTO]
#define BUILD_TARGET $[HAVE_SSL]
#define SOURCES \
apply_patch.cxx
@ -15,7 +15,7 @@
#begin bin_target
#define TARGET build_patch
#define BUILD_TARGET $[HAVE_CRYPTO]
#define BUILD_TARGET $[HAVE_SSL]
#define SOURCES \
build_patch.cxx
@ -24,7 +24,7 @@
#begin bin_target
#define TARGET show_ddb
#define BUILD_TARGET $[HAVE_CRYPTO]
#define BUILD_TARGET $[HAVE_SSL]
#define SOURCES \
show_ddb.cxx
@ -53,7 +53,7 @@
#begin bin_target
#define TARGET check_md5
#define BUILD_TARGET $[HAVE_CRYPTO]
#define BUILD_TARGET $[HAVE_SSL]
#define USE_PACKAGES $[USE_PACKAGES] crypto
#define SOURCES \

View File

@ -16,34 +16,121 @@
//
////////////////////////////////////////////////////////////////////
#include "crypto_utils.h"
#include "pandabase.h"
#include "hashVal.h"
#include "filename.h"
#ifndef HAVE_GETOPT
#include <gnu_getopt.h>
#else
#include <getopt.h>
#endif
void
usage() {
cerr <<
"\n"
"Usage:\n\n"
"check_md5 [-d] [-i \"input string\"] [file1 file2 ...]\n"
"check_md5 -h\n\n";
}
void
help() {
usage();
cerr <<
"This program outputs the MD5 hash of one or more files (or of a string\n"
"passed on the command line with -i).\n\n"
"An MD5 hash is a 128-bit value. The output is presented as a 32-digit\n"
"hexadecimal string by default, but with -d, it is presented as four\n"
"big-endian unsigned 32-bit decimal integers.\n\n";
}
void
output_hash(const string &filename, const HashVal &hash, bool output_decimal) {
if (!filename.empty()) {
cout << filename << " ";
}
if (output_decimal) {
hash.output_dec(cout);
} else {
hash.output_hex(cout);
}
cout << "\n";
}
int
main(int argc, char *argv[]) {
const char *usagestr = "Usage: check_md5 <file>";
if (argc < 2) {
cerr << usagestr << endl;
return 1;
extern char *optarg;
extern int optind;
const char *optstr = "i:dh";
bool got_input_string = false;
string input_string;
bool output_decimal = false;
int flag = getopt(argc, argv, optstr);
while (flag != EOF) {
switch (flag) {
case 'i':
got_input_string = true;
input_string = optarg;
break;
case 'd':
output_decimal = true;
break;
case 'h':
help();
exit(1);
default:
exit(1);
}
flag = getopt(argc, argv, optstr);
}
Filename source_file;
source_file = Filename::from_os_specific(argv[1]);
argc -= (optind-1);
argv += (optind-1);
if(!source_file.exists()) {
cerr << usagestr << endl;
cerr << source_file << " not found!\n";
return 2;
if (argc < 2 && !got_input_string) {
usage();
exit(1);
}
HashVal hash;
md5_a_file(source_file, hash);
if (got_input_string) {
HashVal hash;
hash.hash_string(input_string);
output_hash("", hash, output_decimal);
}
bool okflag = true;
for (int i = 1; i < argc; i++) {
Filename source_file = Filename::from_os_specific(argv[i]);
if (!source_file.exists()) {
cerr << source_file << " not found!\n";
okflag = false;
} else {
HashVal hash;
if (!hash.hash_file(source_file)) {
cerr << "Unable to read " << source_file << "\n";
okflag = false;
} else {
output_hash(source_file.get_basename(), hash, output_decimal);
}
}
}
if (!okflag) {
exit(1);
}
// output base of Filename along w/md5
cout << source_file.get_basename() << " ";
hash.output(cout);
cout << endl;
return 0;
}

View File

@ -4,7 +4,7 @@
#begin lib_target
#define TARGET express
#define USE_PACKAGES nspr crypto net zlib
#define USE_PACKAGES nspr crypto net zlib ssl
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
@ -41,10 +41,13 @@
namable.h nativeNumericData.I nativeNumericData.h \
numeric_types.h \
ordered_vector.h ordered_vector.I ordered_vector.T \
patchfile.I patchfile.h \
pointerTo.I pointerTo.h \
pointerToArray.I pointerToArray.h \
profileTimer.I profileTimer.h \
pta_uchar.h referenceCount.I referenceCount.h \
pta_uchar.h \
ramfile.I ramfile.h \
referenceCount.I referenceCount.h \
register_type.I register_type.h \
reversedNumericData.I reversedNumericData.h \
selectThreadImpl.h \
@ -69,10 +72,7 @@
virtualFileMountSystem.I virtualFileSimple.h virtualFileSimple.I \
virtualFileSystem.h virtualFileSystem.I \
windowsRegistry.h \
zStream.I zStream.h zStreamBuf.h \
$[if $[HAVE_CRYPTO], \
crypto_utils.cxx crypto_utils.h patchfile.I \
patchfile.cxx patchfile.h ]
zStream.I zStream.h zStreamBuf.h
#define INCLUDED_SOURCES \
atomicAdjust.cxx atomicAdjustDummyImpl.cxx atomicAdjustNsprImpl.cxx \
@ -90,8 +90,11 @@
namable.cxx \
nativeNumericData.cxx \
ordered_vector.cxx \
patchfile.cxx \
profileTimer.cxx \
pta_uchar.cxx referenceCount.cxx register_type.cxx \
pta_uchar.cxx \
ramfile.cxx \
referenceCount.cxx register_type.cxx \
reversedNumericData.cxx \
streamReader.cxx streamWriter.cxx \
stringDecoder.cxx \
@ -141,7 +144,9 @@
ordered_vector.h ordered_vector.I ordered_vector.T \
patchfile.I patchfile.h pointerTo.I pointerTo.h \
pointerToArray.I pointerToArray.h profileTimer.I \
profileTimer.h pta_uchar.h referenceCount.I referenceCount.h \
profileTimer.h pta_uchar.h \
ramfile.I ramfile.h \
referenceCount.I referenceCount.h \
register_type.I register_type.h \
reversedNumericData.I reversedNumericData.h \
selectThreadImpl.h \

View File

@ -25,13 +25,3 @@ INLINE int Buffer::
get_length(void) const {
return _length;
}
////////////////////////////////////////////////////////////////////
// Function: Ramfile::constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE Ramfile::
Ramfile(void) {
_pos = 0;
}

View File

@ -15,11 +15,8 @@
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "buffer.h"
////////////////////////////////////////////////////////////////////
// Defines
////////////////////////////////////////////////////////////////////
#include "buffer.h"
////////////////////////////////////////////////////////////////////
// Function: Buffer::Constructor
@ -42,31 +39,3 @@ Buffer::
delete _buffer;
}
////////////////////////////////////////////////////////////////////
// Function: Ramfile::readline
// Access: Published
// Description: Assumes the stream represents a text file, and
// extracts one line up to and including the trailing
// newline character. Returns empty string when the end
// of file is reached.
//
// The interface here is intentionally designed to be
// similar to that for Python's File.readline()
// function.
////////////////////////////////////////////////////////////////////
string Ramfile::
readline() {
size_t start = _pos;
while (_pos < _data.length() && _data[_pos] != '\n') {
++_pos;
}
if (_pos < _data.length() && _data[_pos] == '\n') {
// Include the newline character also.
++_pos;
}
return _data.substr(start, _pos - start);
}

View File

@ -15,13 +15,11 @@
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef BUFFER_H
#define BUFFER_H
//
////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include "pandabase.h"
#include "typedef.h"
#include "referenceCount.h"
@ -46,21 +44,6 @@ private:
int _length;
};
////////////////////////////////////////////////////////////////////
// Class : Ramfile
// Description :
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS Ramfile {
PUBLISHED:
INLINE Ramfile();
string readline();
public:
size_t _pos;
string _data;
};
#include "buffer.I"
#endif

View File

@ -1,134 +0,0 @@
// Filename: crypto_utils.cxx
// Created by: drose (07Nov00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
// This file is compiled only if we have crypto++ installed.
#include "hashVal.h"
#include "config_express.h"
#include "crypto_utils.h"
#include <md5.h>
#include <hex.h>
#include <files.h>
// md5 defines this, but we'd rather do without it, because it
// conflicts with a similar macro defined in NSPR.
#undef IS_LITTLE_ENDIAN
USING_NAMESPACE(CryptoPP);
USING_NAMESPACE(std);
static uint
read32(istream& is) {
unsigned int ret = 0x0;
for (int i=0; i<8; ++i) {
char b;
int n = 0;
is >> b;
switch (b) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
n = b - '0';
break;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
n = b - 'A' + 10;
break;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
n = b - 'a' + 10;
break;
default:
cerr << "illegal hex nibble '" << b << "'" << endl;
}
ret = (ret << 4) | (n & 0x0f);
}
return ret;
}
void
md5_a_file(const Filename &name, HashVal &ret) {
ostringstream os;
MD5 md5;
string fs = name.to_os_specific();
try {
FileSource f(fs.c_str(), true,
new HashFilter(md5, new HexEncoder(new FileSink(os))));
} catch (...) {
express_cat.warning()
<< "Unable to read " << name << " to compute md5 hash.\n";
if (!name.exists()) {
express_cat.warning()
<< "(file does not exist.)\n";
} else {
express_cat.warning()
<< "(file exists but cannot be read.)\n";
}
ret.hv[0] = 0;
ret.hv[1] = 0;
ret.hv[2] = 0;
ret.hv[3] = 0;
return;
}
istringstream is(os.str());
ret.hv[0] = read32(is);
ret.hv[1] = read32(is);
ret.hv[2] = read32(is);
ret.hv[3] = read32(is);
}
void
md5_a_buffer(const unsigned char* buf, unsigned long len, HashVal& ret) {
MD5 md5;
HashFilter hash(md5);
hash.Put((byte*)buf, len);
hash.Close();
unsigned char* outb;
unsigned long outl = hash.MaxRetrieveable();
outb = new uchar[outl];
hash.Get((byte*)outb, outl);
ret.hv[0] = (outb[0] << 24) | (outb[1] << 16) | (outb[2] << 8) | outb[3];
ret.hv[1] = (outb[4] << 24) | (outb[5] << 16) | (outb[6] << 8) | outb[7];
ret.hv[2] = (outb[8] << 24) | (outb[9] << 16) | (outb[10] << 8) | outb[11];
ret.hv[3] = (outb[12] << 24) | (outb[13] << 16) | (outb[14] << 8) | outb[15];
delete[] outb;
}

View File

@ -24,13 +24,9 @@
#include "memoryUsagePointerCounts.cxx"
#include "memoryUsagePointers.cxx"
#include "multifile.cxx"
#include "pmutex.cxx"
#include "mutexHolder.cxx"
#include "mutexDummyImpl.cxx"
#include "mutexNsprImpl.cxx"
#include "namable.cxx"
#include "nativeNumericData.cxx"
#include "ordered_vector.cxx"
#include "profileTimer.cxx"
#include "pta_uchar.cxx"
#include "referenceCount.cxx"

View File

@ -1,3 +1,9 @@
#include "patchfile.cxx"
#include "pmutex.cxx"
#include "profileTimer.cxx"
#include "pta_uchar.cxx"
#include "ramfile.cxx"
#include "referenceCount.cxx"
#include "register_type.cxx"
#include "reversedNumericData.cxx"
#include "streamReader.cxx"

View File

@ -24,7 +24,7 @@
////////////////////////////////////////////////////////////////////
INLINE HashVal::
HashVal() {
hv[0] = hv[1] = hv[2] = hv[3] = 0;
_hv[0] = _hv[1] = _hv[2] = _hv[3] = 0;
}
////////////////////////////////////////////////////////////////////
@ -34,10 +34,23 @@ HashVal() {
////////////////////////////////////////////////////////////////////
INLINE HashVal::
HashVal(const HashVal &copy) {
hv[0] = copy.hv[0];
hv[1] = copy.hv[1];
hv[2] = copy.hv[2];
hv[3] = copy.hv[3];
_hv[0] = copy._hv[0];
_hv[1] = copy._hv[1];
_hv[2] = copy._hv[2];
_hv[3] = copy._hv[3];
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::Copy Assignment Operator
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void HashVal::
operator = (const HashVal &copy) {
_hv[0] = copy._hv[0];
_hv[1] = copy._hv[1];
_hv[2] = copy._hv[2];
_hv[3] = copy._hv[3];
}
////////////////////////////////////////////////////////////////////
@ -47,10 +60,10 @@ HashVal(const HashVal &copy) {
////////////////////////////////////////////////////////////////////
INLINE bool HashVal::
operator == (const HashVal &other) const {
return (hv[0] == other.hv[0] &&
hv[1] == other.hv[1] &&
hv[2] == other.hv[2] &&
hv[3] == other.hv[3]);
return (_hv[0] == other._hv[0] &&
_hv[1] == other._hv[1] &&
_hv[2] == other._hv[2] &&
_hv[3] == other._hv[3]);
}
////////////////////////////////////////////////////////////////////
@ -64,36 +77,189 @@ operator != (const HashVal &other) const {
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::get_value
// Function: HashVal::operator <
// Access: Published
// Description: Returns the integer value of the indicated component.
// Description:
////////////////////////////////////////////////////////////////////
INLINE uint HashVal::
get_value(int val) const {
nassertr(val >= 0 && val < 4, 0);
return hv[val];
INLINE bool HashVal::
operator < (const HashVal &other) const {
return compare_to(other) < 0;
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::compare_to
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE int HashVal::
compare_to(const HashVal &other) const {
if (_hv[0] != other._hv[0]) {
return (int)_hv[0] - (int)other._hv[0];
}
if (_hv[1] != other._hv[1]) {
return (int)_hv[1] - (int)other._hv[1];
}
if (_hv[2] != other._hv[2]) {
return (int)_hv[2] - (int)other._hv[2];
}
return (int)_hv[3] - (int)other._hv[3];
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::set_value
// Function: HashVal::merge_with
// Access: Published
// Description: Sets the hash value at index val
// Description: Generates a new HashVal representing the xor of this
// one and the other one.
////////////////////////////////////////////////////////////////////
INLINE void HashVal::
set_value(int val, uint hashval) {
nassertv(val >= 0 && val < 4);
hv[val] = hashval;
merge_with(const HashVal &other) {
_hv[0] ^= other._hv[0];
_hv[1] ^= other._hv[1];
_hv[2] ^= other._hv[2];
_hv[3] ^= other._hv[3];
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::output_dec
// Access: Published
// Description: Outputs the HashVal as four unsigned decimal
// integers.
////////////////////////////////////////////////////////////////////
INLINE void HashVal::
output_dec(ostream &out) const {
out << _hv[0] << " " << _hv[1] << " " << _hv[2] << " " << _hv[3];
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::input
// Access: Published
// Description: Inputs the HashVal as four unsigned decimal integers.
////////////////////////////////////////////////////////////////////
INLINE void HashVal::
input_dec(istream &in) {
in >> _hv[0] >> _hv[1] >> _hv[2] >> _hv[3];
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::output
// Access: Published
// Description: The output method does not itself output enclosing
// brackets, but the ostream operator << does.
// Description:
////////////////////////////////////////////////////////////////////
INLINE void HashVal::
output(ostream &out) const {
out << hv[0] << " " << hv[1] << " " << hv[2] << " " << hv[3];
output_hex(out);
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::write_datagram
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void HashVal::
write_datagram(Datagram &destination) const {
destination.add_uint32(_hv[0]);
destination.add_uint32(_hv[1]);
destination.add_uint32(_hv[2]);
destination.add_uint32(_hv[3]);
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::read_datagram
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void HashVal::
read_datagram(DatagramIterator &source) {
_hv[0] = source.get_uint32();
_hv[1] = source.get_uint32();
_hv[2] = source.get_uint32();
_hv[3] = source.get_uint32();
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::write_stream
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void HashVal::
write_stream(StreamWriter &destination) const {
destination.add_uint32(_hv[0]);
destination.add_uint32(_hv[1]);
destination.add_uint32(_hv[2]);
destination.add_uint32(_hv[3]);
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::read_stream
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void HashVal::
read_stream(StreamReader &source) {
_hv[0] = source.get_uint32();
_hv[1] = source.get_uint32();
_hv[2] = source.get_uint32();
_hv[3] = source.get_uint32();
}
#ifdef HAVE_SSL
////////////////////////////////////////////////////////////////////
// Function: HashVal::hash_ramfile
// Access: Published
// Description: Generates the hash value by hashing the indicated
// data. This method is only defined if we have the
// OpenSSL library (which provides md5 functionality)
// available.
////////////////////////////////////////////////////////////////////
INLINE void HashVal::
hash_ramfile(const Ramfile &ramfile) {
return hash_buffer(ramfile._data.data(), ramfile._data.length());
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::hash_string
// Access: Published
// Description: Generates the hash value by hashing the indicated
// data. This method is only defined if we have the
// OpenSSL library (which provides md5 functionality)
// available.
////////////////////////////////////////////////////////////////////
INLINE void HashVal::
hash_string(const string &data) {
return hash_buffer(data.data(), data.length());
}
#endif // HAVE_SSL
////////////////////////////////////////////////////////////////////
// Function: HashVal::tohex
// Access: Private, Static
// Description: Converts a single nibble to a hex digit.
////////////////////////////////////////////////////////////////////
INLINE char HashVal::
tohex(unsigned int nibble) {
nibble &= 0xf;
if (nibble < 10) {
return nibble + '0';
}
return nibble - 10 + 'a';
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::fromhex
// Access: Private, Static
// Description: Converts a single hex digit to a numerical value.
////////////////////////////////////////////////////////////////////
INLINE unsigned int HashVal::
fromhex(char digit) {
if (isdigit(digit)) {
return digit - '0';
} else {
return tolower(digit) - 'a' + 10;
}
}
INLINE ostream &operator << (ostream &out, const HashVal &hv) {
hv.output(out);
return out;
}

View File

@ -16,17 +16,233 @@
//
////////////////////////////////////////////////////////////////////
#include "hashVal.h"
#include "ctype.h"
#include "virtualFileSystem.h"
#ifdef HAVE_SSL
#include <openssl/md5.h>
#endif // HAVE_SSL
////////////////////////////////////////////////////////////////////
// Function: HashVal::as_string
// Function: HashVal::output_hex
// Access: Published
// Description: Returns the HashVal as a string with four numbers.
// Description: Outputs the HashVal as a 32-digit hexadecimal number.
////////////////////////////////////////////////////////////////////
void HashVal::
output_hex(ostream &out) const {
char buffer[32];
encode_hex(_hv[0], buffer);
encode_hex(_hv[1], buffer + 8);
encode_hex(_hv[2], buffer + 16);
encode_hex(_hv[3], buffer + 24);
out.write(buffer, 32);
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::input
// Access: Published
// Description: Inputs the HashVal as a 32-digit hexadecimal number.
////////////////////////////////////////////////////////////////////
void HashVal::
input_hex(istream &in) {
in >> ws;
char buffer[32];
size_t i = 0;
int ch = in.get();
while (!in.eof() && !in.fail() && isxdigit(ch)) {
if (i < 32) {
buffer[i] = ch;
}
i++;
ch = in.get();
}
if (i != 32) {
in.setstate(ios::failbit);
return;
}
if (!in.eof()) {
in.unget();
} else {
in.clear();
}
decode_hex(buffer, _hv[0]);
decode_hex(buffer + 8, _hv[1]);
decode_hex(buffer + 16, _hv[2]);
decode_hex(buffer + 24, _hv[3]);
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::as_dec
// Access: Published
// Description: Returns the HashVal as a string with four decimal
// numbers.
////////////////////////////////////////////////////////////////////
string HashVal::
as_string() const {
as_dec() const {
ostringstream strm;
output(strm);
output_dec(strm);
return strm.str();
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::set_from_dec
// Access: Published
// Description: Sets the HashVal from a string with four decimal
// numbers. Returns true if valid, false otherwise.
////////////////////////////////////////////////////////////////////
bool HashVal::
set_from_dec(const string &text) {
istringstream strm(text);
input_dec(strm);
return !strm.fail();
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::as_hex
// Access: Published
// Description: Returns the HashVal as a 32-byte hexadecimal string.
////////////////////////////////////////////////////////////////////
string HashVal::
as_hex() const {
char buffer[32];
encode_hex(_hv[0], buffer);
encode_hex(_hv[1], buffer + 8);
encode_hex(_hv[2], buffer + 16);
encode_hex(_hv[3], buffer + 24);
return string(buffer, 32);
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::set_from_hex
// Access: Published
// Description: Sets the HashVal from a 32-byte hexademical string.
// Returns true if successful, false otherwise.
////////////////////////////////////////////////////////////////////
bool HashVal::
set_from_hex(const string &text) {
istringstream strm(text);
input_hex(strm);
return !strm.fail();
}
#ifdef HAVE_SSL
////////////////////////////////////////////////////////////////////
// Function: HashVal::hash_file
// Access: Published
// Description: Generates the hash value from the indicated file.
// Returns true on success, false if the file cannot be
// read. This method is only defined if we have the
// OpenSSL library (which provides md5 functionality)
// available.
////////////////////////////////////////////////////////////////////
bool HashVal::
hash_file(const Filename &filename) {
Filename bin_filename = Filename::binary_filename(filename);
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
istream *istr = vfs->open_read_file(bin_filename);
if (istr == (istream *)NULL) {
(*this) = HashVal();
return false;
}
unsigned char md[16];
MD5_CTX ctx;
MD5_Init(&ctx);
static const int buffer_size = 1024;
char buffer[buffer_size];
istr->read(buffer, buffer_size);
size_t count = istr->gcount();
while (count != 0) {
MD5_Update(&ctx, buffer, count);
istr->read(buffer, buffer_size);
count = istr->gcount();
}
delete istr;
MD5_Final(md, &ctx);
// Store the individual bytes as big-endian ints, from historical
// convention.
_hv[0] = (md[0] << 24) | (md[1] << 16) | (md[2] << 8) | (md[3]);
_hv[1] = (md[4] << 24) | (md[5] << 16) | (md[6] << 8) | (md[7]);
_hv[2] = (md[8] << 24) | (md[9] << 16) | (md[10] << 8) | (md[11]);
_hv[3] = (md[12] << 24) | (md[13] << 16) | (md[14] << 8) | (md[15]);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::hash_buffer
// Access: Published
// Description: Generates the hash value by hashing the indicated
// data. This method is only defined if we have the
// OpenSSL library (which provides md5 functionality)
// available.
////////////////////////////////////////////////////////////////////
void HashVal::
hash_buffer(const char *buffer, int length) {
unsigned char md[16];
MD5((const unsigned char *)buffer, length, md);
// Store the individual bytes as big-endian ints, from historical
// convention.
_hv[0] = (md[0] << 24) | (md[1] << 16) | (md[2] << 8) | (md[3]);
_hv[1] = (md[4] << 24) | (md[5] << 16) | (md[6] << 8) | (md[7]);
_hv[2] = (md[8] << 24) | (md[9] << 16) | (md[10] << 8) | (md[11]);
_hv[3] = (md[12] << 24) | (md[13] << 16) | (md[14] << 8) | (md[15]);
}
#endif // HAVE_SSL
////////////////////////////////////////////////////////////////////
// Function: HashVal::encode_hex
// Access: Private, Static
// Description: Encodes the indicated unsigned int into an
// eight-digit hex string, stored at the indicated
// buffer and the following 8 positions.
////////////////////////////////////////////////////////////////////
void HashVal::
encode_hex(unsigned int val, char *buffer) {
buffer[0] = tohex(val >> 28);
buffer[1] = tohex(val >> 24);
buffer[2] = tohex(val >> 20);
buffer[3] = tohex(val >> 16);
buffer[4] = tohex(val >> 12);
buffer[5] = tohex(val >> 8);
buffer[6] = tohex(val >> 4);
buffer[7] = tohex(val);
}
////////////////////////////////////////////////////////////////////
// Function: HashVal::decode_hex
// Access: Private, Static
// Description: Decodes the indicated eight-digit hex string into an
// unsigned integer.
////////////////////////////////////////////////////////////////////
void HashVal::
decode_hex(const char *buffer, unsigned int &val) {
unsigned int bytes[8];
for (int i = 0; i < 8; i++) {
bytes[i] = fromhex(buffer[i]);
}
val = ((bytes[0] << 28) |
(bytes[1] << 24) |
(bytes[2] << 20) |
(bytes[3] << 16) |
(bytes[4] << 12) |
(bytes[5] << 8) |
(bytes[6] << 4) |
(bytes[7]));
}

View File

@ -19,36 +19,68 @@
#ifndef HASHVAL_H
#define HASHVAL_H
#include <pandabase.h>
#include "pandabase.h"
#include "typedef.h"
#include <notify.h>
#include "notify.h"
#include "ramfile.h"
#include "datagram.h"
#include "datagramIterator.h"
#include "streamWriter.h"
#include "streamReader.h"
////////////////////////////////////////////////////////////////////
// Class : HashVal
// Description : A sixteen-byte hash value sent to the crypt library.
// Description : Stores a 128-bit value that represents the hashed
// contents (typically MD5) of a file or buffer.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS HashVal {
PUBLISHED:
INLINE HashVal();
INLINE HashVal(const HashVal &copy);
INLINE void operator = (const HashVal &copy);
INLINE bool operator == (const HashVal &other) const;
INLINE bool operator != (const HashVal &other) const;
INLINE uint get_value(int val) const;
INLINE void set_value(int val, uint hash);
INLINE void output(ostream &out) const;
string as_string() const;
INLINE bool operator < (const HashVal &other) const;
INLINE int compare_to(const HashVal &other) const;
public:
uint hv[4];
INLINE void merge_with(const HashVal &other);
INLINE void output_dec(ostream &out) const;
INLINE void input_dec(istream &in);
void output_hex(ostream &out) const;
void input_hex(istream &in);
INLINE void output(ostream &out) const;
string as_dec() const;
bool set_from_dec(const string &text);
string as_hex() const;
bool set_from_hex(const string &text);
INLINE void write_datagram(Datagram &destination) const;
INLINE void read_datagram(DatagramIterator &source);
INLINE void write_stream(StreamWriter &destination) const;
INLINE void read_stream(StreamReader &source);
#ifdef HAVE_SSL
bool hash_file(const Filename &filename);
INLINE void hash_ramfile(const Ramfile &ramfile);
INLINE void hash_string(const string &data);
void hash_buffer(const char *buffer, int length);
#endif // HAVE_SSL
private:
static void encode_hex(unsigned int val, char *buffer);
static void decode_hex(const char *buffer, unsigned int &val);
INLINE static char tohex(unsigned int nibble);
INLINE static unsigned int fromhex(char digit);
PN_uint32 _hv[4];
};
INLINE ostream &operator << (ostream &out, const HashVal &hv) {
out << "[";
hv.output(out);
out << "]";
return out;
}
INLINE ostream &operator << (ostream &out, const HashVal &hv);
#include "hashVal.I"

View File

@ -16,15 +16,22 @@
//
////////////////////////////////////////////////////////////////////
#include "pandabase.h"
#ifdef HAVE_SSL
#include "config_express.h"
#include "error_utils.h"
#include "patchfile.h"
#include "crypto_utils.h" // MD5 stuff
#include "streamReader.h"
#include "streamWriter.h"
#include <stdio.h> // for tempnam
#ifdef WIN32_VC
#define tempnam _tempnam
#endif
// PROFILING ///////////////////////////////////////////////////////
//#define PROFILE_PATCH_BUILD
#ifdef PROFILE_PATCH_BUILD
@ -200,7 +207,7 @@ initiate(const Filename &patch_file, const Filename &file) {
// Open the temp file for write
{
char *tempfilename = _tempnam(".", "pf");
char *tempfilename = tempnam(".", "pf");
if (NULL == tempfilename) {
express_cat.error()
<< "Patchfile::initiate() - Failed to create temp file name, using default" << endl;
@ -356,7 +363,7 @@ run(void) {
// check the MD5 from the patch file against the newly patched file
{
HashVal MD5_actual;
md5_a_file(_temp_file, MD5_actual);
MD5_actual.hash_file(_temp_file);
if (_MD5_ofResult != MD5_actual) {
// Whoops, patching screwed up somehow.
_origfile_stream.close();
@ -376,7 +383,7 @@ run(void) {
<< "No source hash in patch file to verify.\n";
} else {
HashVal MD5_orig;
md5_a_file(_orig_file, MD5_orig);
MD5_orig.hash_file(_orig_file);
if (MD5_orig != get_source_hash()) {
express_cat.info()
<< "Started from incorrect source file. Got:\n"
@ -496,20 +503,14 @@ internal_read_header(const Filename &patch_file) {
_source_file_length = patch_reader.get_uint32();
// get the MD5 of the source file.
_MD5_ofSource.set_value(0, patch_reader.get_uint32());
_MD5_ofSource.set_value(1, patch_reader.get_uint32());
_MD5_ofSource.set_value(2, patch_reader.get_uint32());
_MD5_ofSource.set_value(3, patch_reader.get_uint32());
_MD5_ofSource.read_stream(patch_reader);
}
// get the length of the patched result file
_result_file_length = patch_reader.get_uint32();
// get the MD5 of the resultant patched file
_MD5_ofResult.set_value(0, patch_reader.get_uint32());
_MD5_ofResult.set_value(1, patch_reader.get_uint32());
_MD5_ofResult.set_value(2, patch_reader.get_uint32());
_MD5_ofResult.set_value(3, patch_reader.get_uint32());
_MD5_ofResult.read_stream(patch_reader);
express_cat.debug()
<< "Patchfile::initiate() - valid patchfile" << endl;
@ -530,8 +531,7 @@ PN_uint16 Patchfile::
calc_hash(const char *buffer) {
#ifdef USE_MD5_FOR_HASHTABLE_INDEX_VALUES
HashVal hash;
md5_a_buffer((const unsigned char*)buffer, (int)_footprint_length, hash);
hash.hash_buffer(buffer, _footprint_length);
//cout << PN_uint16(hash.get_value(0)) << " ";
@ -869,22 +869,16 @@ build(Filename file_orig, Filename file_new, Filename patch_name) {
patch_writer.add_uint32(_source_file_length);
{
// calc MD5 of original file
md5_a_buffer((const unsigned char*)buffer_orig, (int)_source_file_length, _MD5_ofSource);
_MD5_ofSource.hash_buffer(buffer_orig, _source_file_length);
// add it to the header
patch_writer.add_uint32(_MD5_ofSource.get_value(0));
patch_writer.add_uint32(_MD5_ofSource.get_value(1));
patch_writer.add_uint32(_MD5_ofSource.get_value(2));
patch_writer.add_uint32(_MD5_ofSource.get_value(3));
_MD5_ofSource.write_stream(patch_writer);
}
patch_writer.add_uint32(_result_file_length);
{
// calc MD5 of resultant patched file
md5_a_buffer((const unsigned char*)buffer_new, (int)_result_file_length, _MD5_ofResult);
_MD5_ofResult.hash_buffer(buffer_new, _result_file_length);
// add it to the header
patch_writer.add_uint32(_MD5_ofResult.get_value(0));
patch_writer.add_uint32(_MD5_ofResult.get_value(1));
patch_writer.add_uint32(_MD5_ofResult.get_value(2));
patch_writer.add_uint32(_MD5_ofResult.get_value(3));
_MD5_ofResult.write_stream(patch_writer);
}
END_PROFILE(writeHeader, "writing patch file header");
@ -941,7 +935,7 @@ build(Filename file_orig, Filename file_new, Filename patch_name) {
}
// are there still more bytes left in the new file?
if ((int)ADD_pos != _result_file_length) {
if (ADD_pos != _result_file_length) {
// emit ADD for all remaining bytes
emit_ADD(write_stream, _result_file_length - ADD_pos, &buffer_new[ADD_pos],
ADD_pos);
@ -961,3 +955,4 @@ build(Filename file_orig, Filename file_new, Filename patch_name) {
return true;
}
#endif // HAVE_SSL

View File

@ -17,15 +17,14 @@
////////////////////////////////////////////////////////////////////
#ifndef PATCHFILE_H
#define PATCHFILE_H
//
////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////
#include <pandabase.h>
#include "pandabase.h"
#ifdef HAVE_SSL
#include "typedef.h"
#include <notify.h>
#include <filename.h>
#include "notify.h"
#include "filename.h"
#include "plist.h"
#include "datagram.h"
#include "datagramIterator.h"
@ -133,4 +132,6 @@ protected:
#include "patchfile.I"
#endif // HAVE_SSL
#endif

View File

@ -1,5 +1,5 @@
// Filename: crypto_utils.h
// Created by: drose (07Nov00)
// Filename: ramfile.I
// Created by: mike (09Jan97)
//
////////////////////////////////////////////////////////////////////
//
@ -16,21 +16,12 @@
//
////////////////////////////////////////////////////////////////////
#ifndef CRYPTO_UTILS_H
#define CRYPTO_UTILS_H
#include <pandabase.h>
#include <filename.h>
#include "typedef.h"
class HashVal;
BEGIN_PUBLISH
EXPCL_PANDAEXPRESS void md5_a_file(const Filename &fname, HashVal &ret);
EXPCL_PANDAEXPRESS void md5_a_buffer(const uchar *buf, ulong len, HashVal &ret);
END_PUBLISH
#endif
////////////////////////////////////////////////////////////////////
// Function: Ramfile::constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE Ramfile::
Ramfile() {
_pos = 0;
}

View File

@ -0,0 +1,47 @@
// Filename: ramfile.cxx
// Created by: mike (09Jan97)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "ramfile.h"
////////////////////////////////////////////////////////////////////
// Function: Ramfile::readline
// Access: Published
// Description: Assumes the stream represents a text file, and
// extracts one line up to and including the trailing
// newline character. Returns empty string when the end
// of file is reached.
//
// The interface here is intentionally designed to be
// similar to that for Python's File.readline()
// function.
////////////////////////////////////////////////////////////////////
string Ramfile::
readline() {
size_t start = _pos;
while (_pos < _data.length() && _data[_pos] != '\n') {
++_pos;
}
if (_pos < _data.length() && _data[_pos] == '\n') {
// Include the newline character also.
++_pos;
}
return _data.substr(start, _pos - start);
}

View File

@ -0,0 +1,44 @@
// Filename: ramfile.h
// Created by: mike (09Jan97)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef RAMFILE_H
#define RAMFILE_H
#include "pandabase.h"
#include "typedef.h"
#include "referenceCount.h"
////////////////////////////////////////////////////////////////////
// Class : Ramfile
// Description : An in-memory buffer specifically designed for
// downloading files to memory.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS Ramfile {
PUBLISHED:
INLINE Ramfile();
string readline();
public:
size_t _pos;
string _data;
};
#include "ramfile.I"
#endif