// distribution boxbackup-0.10 (svn version: 494)
//  
// Copyright (c) 2003 - 2006
//      Ben Summers and contributors.  All rights reserved.
//  
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 3. All use of this software and associated advertising materials must 
//    display the following acknowledgment:
//        This product includes software developed by Ben Summers.
// 4. The names of the Authors may not be used to endorse or promote
//    products derived from this software without specific prior written
//    permission.
// 
// [Where legally impermissible the Authors do not disclaim liability for 
// direct physical injury or death caused solely by defects in the software 
// unless it is modified by a third party.]
// 
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//  
//  
//  
// --------------------------------------------------------------------------
//
// File
//		Name:    BackupStoreFilenameClear.cpp
//		Purpose: BackupStoreFilenames in the clear
//		Created: 2003/08/26
//
// --------------------------------------------------------------------------

#include "Box.h"
#include "BackupStoreFilenameClear.h"
#include "BackupStoreException.h"
#include "CipherContext.h"
#include "CipherBlowfish.h"
#include "Guards.h"

#include "MemLeakFindOn.h"

// Hide private variables from the rest of the world
namespace
{
	int sEncodeMethod = BackupStoreFilename::Encoding_Clear;
	CipherContext sBlowfishEncrypt;
	CipherContext sBlowfishDecrypt;
}

// --------------------------------------------------------------------------
//
// Function
//		Name:    BackupStoreFilenameClear::BackupStoreFilenameClear()
//		Purpose: Default constructor, creates an invalid filename
//		Created: 2003/08/26
//
// --------------------------------------------------------------------------
BackupStoreFilenameClear::BackupStoreFilenameClear()
{
}

// --------------------------------------------------------------------------
//
// Function
//		Name:    BackupStoreFilenameClear::BackupStoreFilenameClear(const std::string &)
//		Purpose: Creates a filename, encoding from the given string
//		Created: 2003/08/26
//
// --------------------------------------------------------------------------
BackupStoreFilenameClear::BackupStoreFilenameClear(const std::string &rToEncode)
{
	SetClearFilename(rToEncode);
}

// --------------------------------------------------------------------------
//
// Function
//		Name:    BackupStoreFilenameClear::BackupStoreFilenameClear(const BackupStoreFilenameClear &)
//		Purpose: Copy constructor
//		Created: 2003/08/26
//
// --------------------------------------------------------------------------
BackupStoreFilenameClear::BackupStoreFilenameClear(const BackupStoreFilenameClear &rToCopy)
	: BackupStoreFilename(rToCopy),
	  mClearFilename(rToCopy.mClearFilename)
{
}

// --------------------------------------------------------------------------
//
// Function
//		Name:    BackupStoreFilenameClear::BackupStoreFilenameClear(const BackupStoreFilename &rToCopy)
//		Purpose: Copy from base class
//		Created: 2003/08/26
//
// --------------------------------------------------------------------------
BackupStoreFilenameClear::BackupStoreFilenameClear(const BackupStoreFilename &rToCopy)
	: BackupStoreFilename(rToCopy)
{
	// Will get a clear filename when it's required
}

// --------------------------------------------------------------------------
//
// Function
//		Name:    BackupStoreFilenameClear::~BackupStoreFilenameClear()
//		Purpose: Destructor
//		Created: 2003/08/26
//
// --------------------------------------------------------------------------
BackupStoreFilenameClear::~BackupStoreFilenameClear()
{
}

// --------------------------------------------------------------------------
//
// Function
//		Name:    BackupStoreFilenameClear::GetClearFilename()
//		Purpose: Get the unencoded filename
//		Created: 2003/08/26
//
// --------------------------------------------------------------------------
#ifdef BACKUPSTOREFILEAME_MALLOC_ALLOC_BASE_TYPE
const std::string BackupStoreFilenameClear::GetClearFilename() const
{
	MakeClearAvailable();
	// When modifying, remember to change back to reference return if at all possible
	// -- returns an object rather than a reference to allow easy use with other code.
	return std::string(mClearFilename.c_str(), mClearFilename.size());
}
#else
const std::string &BackupStoreFilenameClear::GetClearFilename() const
{
	MakeClearAvailable();
	return mClearFilename;
}
#endif

// --------------------------------------------------------------------------
//
// Function
//		Name:    BackupStoreFilenameClear::SetClearFilename(const std::string &)
//		Purpose: Encode and make available the clear filename
//		Created: 2003/08/26
//
// --------------------------------------------------------------------------
void BackupStoreFilenameClear::SetClearFilename(const std::string &rToEncode)
{
	// Only allow Blowfish encodings
	if(sEncodeMethod != Encoding_Blowfish)
	{
		THROW_EXCEPTION(BackupStoreException, FilenameEncryptionNotSetup)
	}

	// Make an encoded string with blowfish encryption
	EncryptClear(rToEncode, sBlowfishEncrypt, Encoding_Blowfish);
		
	// Store the clear filename
	mClearFilename.assign(rToEncode.c_str(), rToEncode.size());

	// Make sure we did the right thing
	if(!CheckValid(false))
	{
		THROW_EXCEPTION(BackupStoreException, Internal)
	}
}

// --------------------------------------------------------------------------
//
// Function
//		Name:    BackupStoreFilenameClear::MakeClearAvailable()
//		Purpose: Private. Make sure the clear filename is available
//		Created: 2003/08/26
//
// --------------------------------------------------------------------------
void BackupStoreFilenameClear::MakeClearAvailable() const
{
	if(!mClearFilename.empty())
		return;		// nothing to do

	// Check valid
	CheckValid();
		
	// Decode the header
	int size = BACKUPSTOREFILENAME_GET_SIZE(*this);
	int encoding = BACKUPSTOREFILENAME_GET_ENCODING(*this);
	
	// Decode based on encoding given in the header
	switch(encoding)
	{
	case Encoding_Clear:
		TRACE0("**** BackupStoreFilename encoded with Clear encoding ****\n");
		mClearFilename.assign(c_str() + 2, size - 2);
		break;
		
	case Encoding_Blowfish:
		DecryptEncoded(sBlowfishDecrypt);
		break;
	
	default:
		THROW_EXCEPTION(BackupStoreException, UnknownFilenameEncoding)
		break;	
	}
}


// Buffer for encoding and decoding -- do this all in one single buffer to
// avoid lots of string allocation, which stuffs up memory usage.
// These static memory vars are, of course, not thread safe, but we don't use threads.
static int sEncDecBufferSize = 0;
static MemoryBlockGuard<uint8_t *> *spEncDecBuffer = 0;

static void EnsureEncDecBufferSize(int BufSize)
{
	if(spEncDecBuffer == 0)
	{
#ifndef WIN32
		TRACE1("Allocating filename encoding/decoding buffer with size %d\n", BufSize);
#endif
		spEncDecBuffer = new MemoryBlockGuard<uint8_t *>(BufSize);
		MEMLEAKFINDER_NOT_A_LEAK(spEncDecBuffer);
		MEMLEAKFINDER_NOT_A_LEAK(*spEncDecBuffer);
		sEncDecBufferSize = BufSize;
	}
	else
	{
		if(sEncDecBufferSize < BufSize)
		{
#ifndef WIN32
			TRACE2("Reallocating filename encoding/decoding buffer from %d to %d\n", sEncDecBufferSize, BufSize);
#endif
			spEncDecBuffer->Resize(BufSize);
			sEncDecBufferSize = BufSize;
			MEMLEAKFINDER_NOT_A_LEAK(*spEncDecBuffer);
		}
	}
}

// --------------------------------------------------------------------------
//
// Function
//		Name:    BackupStoreFilenameClear::EncryptClear(const std::string &, CipherContext &, int)
//		Purpose: Private. Assigns the encoded filename string, encrypting.
//		Created: 1/12/03
//
// --------------------------------------------------------------------------
void BackupStoreFilenameClear::EncryptClear(const std::string &rToEncode, CipherContext &rCipherContext, int StoreAsEncoding)
{
	// Work out max size
	int maxOutSize = rCipherContext.MaxOutSizeForInBufferSize(rToEncode.size()) + 4;
	
	// Make sure encode/decode buffer has enough space
	EnsureEncDecBufferSize(maxOutSize);
	
	// Pointer to buffer
	uint8_t *buffer = *spEncDecBuffer;
	
	// Encode -- do entire block in one go
	int encSize = rCipherContext.TransformBlock(buffer + 2, sEncDecBufferSize - 2, rToEncode.c_str(), rToEncode.size());
	// and add in header size
	encSize += 2;
	
	// Adjust header
	BACKUPSTOREFILENAME_MAKE_HDR(buffer, encSize, StoreAsEncoding);
	
	// Store the encoded string
	assign((char*)buffer, encSize);
}


// --------------------------------------------------------------------------
//
// Function
//		Name:    BackupStoreFilenameClear::DecryptEncoded(CipherContext &)
//		Purpose: Decrypt the encoded filename using the cipher context
//		Created: 1/12/03
//
// --------------------------------------------------------------------------
void BackupStoreFilenameClear::DecryptEncoded(CipherContext &rCipherContext) const
{
	// Work out max size
	int maxOutSize = rCipherContext.MaxOutSizeForInBufferSize(size()) + 4;
	
	// Make sure encode/decode buffer has enough space
	EnsureEncDecBufferSize(maxOutSize);
	
	// Pointer to buffer
	uint8_t *buffer = *spEncDecBuffer;
	
	// Decrypt
	const char *str = c_str() + 2;
	int sizeOut = rCipherContext.TransformBlock(buffer, sEncDecBufferSize, str, size() - 2);
	
	// Assign to this
	mClearFilename.assign((char*)buffer, sizeOut);
}


// --------------------------------------------------------------------------
//
// Function
//		Name:    BackupStoreFilenameClear::EncodedFilenameChanged()
//		Purpose: The encoded filename stored has changed
//		Created: 2003/08/26
//
// --------------------------------------------------------------------------
void BackupStoreFilenameClear::EncodedFilenameChanged()
{
	BackupStoreFilename::EncodedFilenameChanged();

	// Delete stored filename in clear
	mClearFilename.erase();
}


// --------------------------------------------------------------------------
//
// Function
//		Name:    BackupStoreFilenameClear::SetBlowfishKey(const void *, int)
//		Purpose: Set the key used for Blowfish encryption of filenames
//		Created: 1/12/03
//
// --------------------------------------------------------------------------
void BackupStoreFilenameClear::SetBlowfishKey(const void *pKey, int KeyLength, const void *pIV, int IVLength)
{
	// Initialisation vector not used. Can't use a different vector for each filename as
	// that would stop comparisions on the server working.
	sBlowfishEncrypt.Reset();
	sBlowfishEncrypt.Init(CipherContext::Encrypt, CipherBlowfish(CipherDescription::Mode_CBC, pKey, KeyLength));
	ASSERT(sBlowfishEncrypt.GetIVLength() == IVLength);
	sBlowfishEncrypt.SetIV(pIV);
	sBlowfishDecrypt.Reset();
	sBlowfishDecrypt.Init(CipherContext::Decrypt, CipherBlowfish(CipherDescription::Mode_CBC, pKey, KeyLength));
	ASSERT(sBlowfishDecrypt.GetIVLength() == IVLength);
	sBlowfishDecrypt.SetIV(pIV);
}

// --------------------------------------------------------------------------
//
// Function
//		Name:    BackupStoreFilenameClear::SetEncodingMethod(int)
//		Purpose: Set the encoding method used for filenames
//		Created: 1/12/03
//
// --------------------------------------------------------------------------
void BackupStoreFilenameClear::SetEncodingMethod(int Method)
{
	sEncodeMethod = Method;
}





syntax highlighted by Code2HTML, v. 0.9.1