// // The developer of the original code and/or files is Tripwire, Inc. // Portions created by Tripwire, Inc. are copyright (C) 2000 Tripwire, // Inc. Tripwire is a registered trademark of Tripwire, Inc. All rights // reserved. // // This program is free software. The contents of this file are subject // to the terms of the GNU General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. You may redistribute it and/or modify it // only in compliance with the GNU General Public License. // // This program is distributed in the hope that it will be useful. // However, this program is distributed AS-IS WITHOUT ANY // WARRANTY; INCLUDING THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS // FOR A PARTICULAR PURPOSE. Please see the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, // USA. // // Nothing in the GNU General Public License or any other license to use // the code or files shall permit you to use Tripwire's trademarks, // service marks, or other intellectual property without Tripwire's // prior written consent. // // If you have any questions, please contact Tripwire, Inc. at either // info@tripwire.org or www.tripwire.org. // /////////////////////////////////////////////////////////////////////////////// // signature.cpp -- interface for calculating file signatures /////////////////////////////////////////////////////////////////////////////// #include "stdfco.h" #include "signature.h" #include "core/errorgeneral.h" #include "core/serializer.h" #include #include #include "fcoundefprop.h" #include "core/archive.h" #ifndef HAVE_OPENSSL_MD5_H # ifdef HAVE_STRINGS_H # include /* for bcopy(), this is only needed for Solaris */ # endif #endif using namespace std; // Vector for base64 conversion // // The standard "digits" for base64 are "[A-Z][a-z][0-9]+/" // (see RFC 2045 at http://sunsite.doc.ic.ac.uk/rfc/rfc2045.txt). // However, Tripwire 1.3 used a different set of characters. // // In order to more closely follow the standard I changed our // encoding to the standard. dmb 09-30-1998 // static char base64vec[] = //"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz:."; "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /////////////////////////////////////////////////////////////////////////////// // class iSignature -- Interface all signatures will implement. /////////////////////////////////////////////////////////////////////////////// iFCOProp::CmpResult iSignature::Compare(const iFCOProp* rhs, Op op) const { // make sure we support this operation if(op != iFCOProp::OP_EQ && op != iFCOProp::OP_NE) { ASSERT(false); return iFCOProp::CMP_UNSUPPORTED; } // compares with undefined props are not equal if (rhs->GetType() == cFCOUndefinedProp::GetInstance()->GetType()) { return (op == iFCOProp::OP_EQ) ? iFCOProp::CMP_FALSE : iFCOProp::CMP_TRUE; } // make sure we are the right type... if(this->GetType() != rhs->GetType()) { ASSERT(false); return iFCOProp::CMP_WRONG_PROP_TYPE; } ASSERT((op == iFCOProp::OP_EQ) || (op == iFCOProp::OP_NE)); if (IsEqual(*static_cast(rhs))) return (op == iFCOProp::OP_EQ) ? iFCOProp::CMP_TRUE : iFCOProp::CMP_FALSE; else return (op == iFCOProp::OP_NE) ? iFCOProp::CMP_TRUE : iFCOProp::CMP_FALSE; } void cArchiveSigGen::AddSig( iSignature* pSig ) { mSigList.push_back( pSig ); } void cArchiveSigGen::CalculateSignatures( cArchive& a ) { byte abBuf[iSignature::SUGGESTED_BLOCK_SIZE]; const int cbToRead = iSignature::SUGGESTED_BLOCK_SIZE; int cbRead; container_type::size_type i; // init hash for( i = 0; i < mSigList.size(); i++ ) mSigList[i]->Init(); // hash data do { cbRead = a.ReadBlob( abBuf, cbToRead ); for( i = 0; i < mSigList.size(); i++ ) mSigList[i]->Update( abBuf, cbRead ); } while( cbRead == cbToRead ); // finalize hash for( i = 0; i < mSigList.size(); i++ ) mSigList[i]->Finit(); } /////////////////////////////////////////////////////////////////////////////// // btob64 -- convert arbitrary bits to base 64 string // // Input: bit array (represented as u_char array) // number of bits in the array // ptr-to-str for return string val /////////////////////////////////////////////////////////////////////////////// char* btob64(const register byte* pcbitvec, register char* pcout, int numbits) { register unsigned int val; register int offset; uint8 *pcorig = (uint8 *) pcout; ASSERT( sizeof( uint8 ) == sizeof( byte ) ); /* everything breaks otherwise */ assert(numbits > 0); val = *pcbitvec; offset = numbits % 6; /* how many bits initially? */ if (offset) { val >>= (8 - offset); *pcout++ = base64vec[val & 0x1f]; } for ( numbits -= offset; numbits > 0; offset += 6, numbits -= 6) { val = *pcbitvec; if (offset > 2) { offset -= 8; val <<= 8; val |= *++pcbitvec; } val >>= (2-offset); *pcout++ = base64vec[val & 0x3f]; } *pcout = '\0'; return (char *) pcorig; } /////////////////////////////////////////////////////////////////////////////// // pltob64 -- walk through a vector of int32s, convert them to // network byte ordering, and then convert to base 64 // this is the preferred interface to btob64. /////////////////////////////////////////////////////////////////////////////// #define NUMTMPLONGS 1000 char* pltob64(uint32* pl, char* pcout, int numlongs) { register int i; register uint32 *plto; uint32 larray[NUMTMPLONGS]; assert(numlongs < NUMTMPLONGS); /* we use our own ntohl() routines, but we have to do it in-place */ memcpy((char *) larray, (char *) pl, numlongs*sizeof(uint32)); for (i = 0, plto = larray; i < numlongs; i++) { *plto = tw_htonl(*plto); ++plto; } return btob64((byte*) larray, (char *) pcout, numlongs*sizeof(uint32)*8); } /////////////////////////////////////////////////////////////////////////////// // class cNullSignature -- The signature that is always 0 /////////////////////////////////////////////////////////////////////////////// IMPLEMENT_TYPEDSERIALIZABLE(cNullSignature, _T("cNullSignature"), 0, 1) cNullSignature::cNullSignature() { } cNullSignature::~cNullSignature() { } void cNullSignature::Init() { } void cNullSignature::Update( const byte* pbData, int cbDataLen ) { } void cNullSignature::Finit() { } TSTRING cNullSignature::AsString() const { TSTRING s = _T("0"); return s; } TSTRING cNullSignature::AsStringHex() const { TSTRING s = _T("0"); return s; } bool cNullSignature::IsEqual(const iSignature& rhs) const { return true; } void cNullSignature::Read(iSerializer* pSerializer, int32 version) { if (version > Version()) ThrowAndAssert(eSerializerVersionMismatch(_T("Null Signature Read"))); #ifdef _DEBUG int16 ret; pSerializer->ReadInt16(ret); ASSERT(ret == 123); #endif } void cNullSignature::Write(iSerializer* pSerializer) const { #ifdef _DEBUG pSerializer->WriteInt16(123); #endif } /////////////////////////////////////////////////////////////////////////////// // Copy /////////////////////////////////////////////////////////////////////////////// void cNullSignature::Copy(const iFCOProp* rhs) { // do nothing! } /////////////////////////////////////////////////////////////////////////////// // class cChecksumSignature -- A simple signature consisting of all the bytes // in an archive. Useful as an example if nothing else. /////////////////////////////////////////////////////////////////////////////// IMPLEMENT_TYPEDSERIALIZABLE(cChecksumSignature, _T("cChecksumSignature"), 0, 1) cChecksumSignature::cChecksumSignature() { mChecksum = 0; } cChecksumSignature::~cChecksumSignature() { } void cChecksumSignature::Init() { } void cChecksumSignature::Update( const byte* pbData, int cbDataLen ) { for( int i = 0; i < cbDataLen; i++, pbData++ ) mChecksum += *pbData; } void cChecksumSignature::Finit() { } TSTRING cChecksumSignature::AsString() const { TSTRING ret; char *ps_signature; char buf[100]; uint32 local[2]; local[0] = (uint32)(mChecksum >> 32); // note we put the MSB first local[1] = (uint32)(mChecksum); ps_signature = pltob64(local, buf, 2); //ps_signature holds base64 representation of mCRC #ifdef _UNICODE ret.resize(strlen(ps_signature)); mbstowcs((TCHAR*)ret.data(), ps_signature, strlen(ps_signature)); #else ret.append(ps_signature); #endif return ret; } TSTRING cChecksumSignature::AsStringHex() const { TOSTRINGSTREAM ss; ss.imbue( std::locale::classic() ); ss.setf( ios::hex, ios::basefield ); ASSERT( false ); ss << (size_t)(uint32) mChecksum; // TODO:BAM -- this is truncating a 64-bit value to 32 bits! return ss.str(); } bool cChecksumSignature::IsEqual(const iSignature& rhs) const { return mChecksum == ((cChecksumSignature&)rhs).mChecksum; } void cChecksumSignature::Read(iSerializer* pSerializer, int32 version) { if (version > Version()) ThrowAndAssert(eSerializerVersionMismatch(_T("Checksum Signature Read"))); pSerializer->ReadInt64((int64&)mChecksum); } void cChecksumSignature::Write(iSerializer* pSerializer) const { pSerializer->WriteInt64((int64)mChecksum); } /////////////////////////////////////////////////////////////////////////////// // Copy /////////////////////////////////////////////////////////////////////////////// void cChecksumSignature::Copy(const iFCOProp* rhs) { ASSERT(GetType() == rhs->GetType()); mChecksum = static_cast(rhs)->mChecksum; } /////////////////////////////////////////////////////////////////////////////// // class cCRC32Signature -- A CRC32 signature /////////////////////////////////////////////////////////////////////////////// IMPLEMENT_TYPEDSERIALIZABLE(cCRC32Signature, _T("cCRC32Signature"), 0, 1); cCRC32Signature::cCRC32Signature() { } cCRC32Signature::~cCRC32Signature() { } void cCRC32Signature::Init() { crcInit( mCRCInfo ); } void cCRC32Signature::Update( const byte* pbData, int cbDataLen ) { ASSERT( sizeof( byte ) == sizeof( uint8 ) ); crcUpdate( mCRCInfo, (uint8*)pbData, cbDataLen ); } void cCRC32Signature::Finit() { crcFinit( mCRCInfo ); } /////////////////////////////////////////////////////////////////////////////// // AsString -- Returns a TSTRING that holds the base64 representation of // mCRC TSTRING cCRC32Signature::AsString() const { TSTRING ret; char *ps_signature; char buf[100]; uint32 local = mCRCInfo.crc; ps_signature = pltob64(&local, buf, 1); //ps_signature holds base64 representation of mCRCInfo.crc #ifdef _UNICODE ret.resize(strlen(ps_signature)); mbstowcs((TCHAR*)ret.data(), ps_signature, strlen(ps_signature)); #else ret.append(ps_signature); #endif return ret; } TSTRING cCRC32Signature::AsStringHex() const { TOSTRINGSTREAM ss; ss.imbue( std::locale::classic() ); ss.setf( ios::hex, ios::basefield ); ss << (size_t)mCRCInfo.crc; return ss.str(); } bool cCRC32Signature::IsEqual(const iSignature& rhs) const { if (this == &rhs) return true; else return (mCRCInfo.crc == ((cCRC32Signature&)rhs).mCRCInfo.crc); } void cCRC32Signature::Read(iSerializer* pSerializer, int32 version) { if (version > Version()) ThrowAndAssert(eSerializerVersionMismatch(_T("CRC32 Read"))); pSerializer->ReadInt32((int32&)mCRCInfo.crc); } void cCRC32Signature::Write(iSerializer* pSerializer) const { pSerializer->WriteInt32((int32)mCRCInfo.crc); } /////////////////////////////////////////////////////////////////////////////// // Copy /////////////////////////////////////////////////////////////////////////////// void cCRC32Signature::Copy(const iFCOProp* rhs) { ASSERT(GetType() == rhs->GetType()); mCRCInfo.crc = static_cast(rhs)->mCRCInfo.crc; } /////////////////////////////////////////////////////////////////////////////// // class cMD5Signature -- A MD5 signature /////////////////////////////////////////////////////////////////////////////// IMPLEMENT_TYPEDSERIALIZABLE(cMD5Signature, _T("cMD5Signature"), 0, 1) cMD5Signature::cMD5Signature() { memset( mMD5Info.digest, 0, sizeof( mMD5Info.digest ) ); memset( md5_digest, 0, MD5_DIGEST_LENGTH ); } cMD5Signature::~cMD5Signature() { } void cMD5Signature::Init() { #ifdef HAVE_OPENSSL_MD5_H MD5_Init( &mMD5Info ); #else MD5Init( &mMD5Info ); #endif } void cMD5Signature::Update( const byte* pbData, int cbDataLen ) { #ifdef HAVE_OPENSSL_MD5_H MD5_Update( &mMD5Info, (uint8*)pbData, cbDataLen ); #else MD5Update( &mMD5Info, (uint8*)pbData, cbDataLen ); #endif } void cMD5Signature::Finit() { #ifdef HAVE_OPENSSL_MD5_H MD5_Final( md5_digest, &mMD5Info ); #else MD5Final( &mMD5Info ); bcopy(mMD5Info.digest, md5_digest, MD5_DIGEST_LENGTH); #endif } //////////////////////////////////////////////////////////////////////////////// // AsString -- Converts to Base64 representation and returns a TSTRING TSTRING cMD5Signature::AsString() const { TSTRING ret; char buf[24]; int length; ASSERT( sizeof( uint8 ) == sizeof( byte ) ); /* everything breaks otherwise */ btob64((byte*)md5_digest, buf, SIG_BYTE_SIZE*8); //converting to base64 representation. length = strlen(buf); #ifdef _UNICODE //making it TSTRING sensitive ret.resize(length); mbstowcs((TCHAR*) ret.data(), buf, length); #else ret.append(buf); #endif return ret; //return ret; //ret holds base64 representation of digest. } TSTRING cMD5Signature::AsStringHex() const { TSTRING ret; TCHAR stringBuffer[128]; TCHAR sigStringOut[128]; sigStringOut[0] = '\0'; uint8 *dbuf = (uint8 *)md5_digest; for(int i = 0; i < SIG_BYTE_SIZE; ++i) { _stprintf(stringBuffer, _T("%02lx"), dbuf[i]); _tcscat(sigStringOut, stringBuffer); } ret.append(sigStringOut); return ret; } bool cMD5Signature::IsEqual(const iSignature& rhs) const { if (this == &rhs) return true; else { return (memcmp(md5_digest, ((cMD5Signature&)rhs).md5_digest, SIG_BYTE_SIZE) == 0); } } void cMD5Signature::Read(iSerializer* pSerializer, int32 version) { if (version > Version()) ThrowAndAssert(eSerializerVersionMismatch(_T("MD5 Read"))); pSerializer->ReadBlob(md5_digest, SIG_BYTE_SIZE); } void cMD5Signature::Write(iSerializer* pSerializer) const { pSerializer->WriteBlob(md5_digest, SIG_BYTE_SIZE); } /////////////////////////////////////////////////////////////////////////////// // Copy /////////////////////////////////////////////////////////////////////////////// void cMD5Signature::Copy(const iFCOProp* rhs) { ASSERT(GetType() == rhs->GetType()); memcpy(md5_digest, &(static_cast(rhs)->md5_digest), SIG_BYTE_SIZE); } /////////////////////////////////////////////////////////////////////////////// // class cSHASignature -- Implementation for cSHASignature: /////////////////////////////////////////////////////////////////////////////// IMPLEMENT_TYPEDSERIALIZABLE(cSHASignature, _T("cSHASignature"), 0, 1) cSHASignature::cSHASignature() { memset( &mSHAInfo, 0, sizeof( mSHAInfo ) ); memset( sha_digest, 0, SHA_DIGEST_LENGTH ); } cSHASignature::~cSHASignature() {} void cSHASignature::Init() { #ifdef HAVE_OPENSSL_SHA_H SHA1_Init( &mSHAInfo ); #else shsInit( &mSHAInfo ); #endif } void cSHASignature::Update( const byte* pbData, int cbDataLen ) { ASSERT( sizeof( byte ) == sizeof( uint8 ) ); #ifdef HAVE_OPENSSL_SHA_H SHA1_Update( &mSHAInfo, (uint8*)pbData, cbDataLen ); #else shsUpdate( &mSHAInfo, (uint8*)pbData, cbDataLen ); #endif } void cSHASignature::Finit() { #ifdef HAVE_OPENSSL_SHA_H SHA1_Final( (unsigned char *)sha_digest, &mSHAInfo ); #else shsFinal( &mSHAInfo ); bcopy(&mSHAInfo.digest, sha_digest, SHA_DIGEST_LENGTH); { /* sha_digest is a byte array, so can't be in * host order. */ int i; uint32 *j = (uint32 *)sha_digest; uint32 *k = (uint32 *)&mSHAInfo.digest; for(int i=0; i> 8) & 0xff00 ) | ( (k[i] >> 24) & 0x00ff ); # endif //WORDS_BIGENDIAN } #endif } //////////////////////////////////////////////////////////////////////////////// // AsString -- Converts to Base64 representation and returns a TSTRING TSTRING cSHASignature::AsString(void) const { TSTRING ret; char* ps_signature; char buf[100]; int length; ps_signature = btob64((uint8*)sha_digest, buf, SIG_UINT32_SIZE*sizeof(uint32)*8); //converting to base64 representation. length = strlen(ps_signature); #ifdef _UNICODE //making it TSTRING sensitive ret.resize(length); mbstowcs((TCHAR*) ret.data(), ps_signature, length); #else ret.append(ps_signature); #endif return ret; //return ret; } TSTRING cSHASignature::AsStringHex() const { TSTRING ret; TCHAR stringBuffer[128]; TCHAR sigStringOut[128]; sigStringOut[0] = '\0'; uint8 *dbuf = (uint8 *)sha_digest; for (int i=0; i < SIG_UINT32_SIZE*(int)sizeof(uint32); ++i) { _stprintf(stringBuffer, _T("%02x"), dbuf[i]); _tcscat(sigStringOut, stringBuffer); } ret.append(sigStringOut); return ret; } /////////////////////////////////////////////////////////////////////////////// // Copy -- Copies a new sig value from a base pointer void cSHASignature::Copy(const iFCOProp* rhs) { ASSERT(GetType() == rhs->GetType()); for (int i = 0; i(rhs))->mSHAInfo.digest)[i]; } /////////////////////////////////////////////////////////////////////////////// // Serializer Implementation: Read and Write void cSHASignature::Read (iSerializer* pSerializer, int32 version) { if (version > Version()) ThrowAndAssert(eSerializerVersionMismatch(_T("SHA Read"))); for (int i = 0; i < SIG_UINT32_SIZE; ++i) pSerializer->ReadInt32((int32&)mSHAInfo.digest[i]); } void cSHASignature::Write(iSerializer* pSerializer) const { for (int i = 0; i < SIG_UINT32_SIZE; ++i) pSerializer->WriteInt32(mSHAInfo.digest[i]); } /////////////////////////////////////////////////////////////////////////////// // IsEqual -- Tests for equality, given a base pointer (iSignature) bool cSHASignature::IsEqual(const iSignature& rhs) const { if (this == &rhs) return true; else { return (memcmp(mSHAInfo.digest, ((cSHASignature&)rhs).mSHAInfo.digest, SIG_UINT32_SIZE * sizeof(uint32)) == 0); } } /////////////////////////////////////////////////////////////////////////////// // class cHAVALSignature -- /////////////////////////////////////////////////////////////////////////////// IMPLEMENT_TYPEDSERIALIZABLE(cHAVALSignature, _T("cHAVALSignature"), 0, 1) cHAVALSignature::cHAVALSignature() { memset( mSignature, 0, sizeof( mSignature ) ); } cHAVALSignature::~cHAVALSignature() {} void cHAVALSignature::Init() { haval_start( &mHavalState ); } void cHAVALSignature::Update( const byte* pbData, int cbDataLen ) { haval_hash( &mHavalState, (uint8*)pbData, cbDataLen ); } void cHAVALSignature::Finit() { haval_end( &mHavalState, mSignature ); } /////////////////////////////////////////////////////////////////////////////// // AsString -- Returns Base64 representation of mSignature in a TSTRING TSTRING cHAVALSignature::AsString() const { TSTRING ret; char buf[24]; int length; btob64((byte*)mSignature, buf, 128); //converting to base64 representation. length = strlen(buf); #ifdef _UNICODE //making it TSTRING sensitive ret.resize(length); mbstowcs((TCHAR*) ret.data(), buf, length); #else ret.append(buf); #endif return ret; //return ret; //ret holds base64 representation of digest. } TSTRING cHAVALSignature::AsStringHex() const { TSTRING ret; TCHAR stringBuffer[128]; TCHAR sigStringOut[128]; sigStringOut[0] = _T('\0'); for (int i=0; i < SIG_BYTE_SIZE; ++i) { _stprintf(stringBuffer, _T("%02x"), mSignature[i]); _tcscat(sigStringOut, stringBuffer); } ret.append(sigStringOut); return ret; } /////////////////////////////////////////////////////////////////////////////// // Copy -- Copies the sig value using a base class pointer. void cHAVALSignature::Copy(const iFCOProp* rhs) { ASSERT(GetType() == rhs->GetType()); memcpy(&mSignature, &(static_cast(rhs)->mSignature), SIG_BYTE_SIZE); } /////////////////////////////////////////////////////////////////////////////// // Serializer Implementation: Read and Write void cHAVALSignature::Read(iSerializer* pSerializer, int32 version) { if (version > Version()) ThrowAndAssert(eSerializerVersionMismatch(_T("HAVAL Read"))); pSerializer->ReadBlob(mSignature, SIG_BYTE_SIZE); } void cHAVALSignature::Write(iSerializer* pSerializer) const { pSerializer->WriteBlob(mSignature, SIG_BYTE_SIZE); } /////////////////////////////////////////////////////////////////////////////// // Equal -- Tests for equality given a base pointer. bool cHAVALSignature::IsEqual(const iSignature & rhs) const { if (this == &rhs) return true; else { return (memcmp(mSignature, ((cHAVALSignature&)rhs).mSignature, SIG_BYTE_SIZE) == 0); } }