// DWBS ------------------------------------------------------------------ DWBS
//
// PLATFORM		: ALL
// PRODUCT		: BIT_DEMON
// VISIBILITY	: PUBLIC
//
// DWBS ------------------------------------------------------------------ DWBS

#include <bdCore/bdCrypto/bdCypher3Des.h>
#include <bdCore/bdCrypto/bdCryptoConfig.h>

#define BD_LOG_LEVEL "cypher3DES"

#if (!defined BD_PLATFORM_XBOX) && (!defined BD_PLATFORM_XENON)


bdCypher3Des::bdCypher3Des()
{

	if (register_cipher(&des3_desc) == -1)
	{
		BD_ERR(BD_LOG_LEVEL, "Error registering cipher.");
	}
}

bdCypher3Des::~bdCypher3Des()
{
}

bdBool bdCypher3Des::encrypt(const bdUByte8 *key, 
							 const bdUInt keySize,
							 const bdUByte8 *iv, 
							 const bdUByte8 *pt, 
							 bdUByte8 *ct, 
							 bdUInt &size)
{
	symmetric_CBC cbc;

	bdInt error = cbc_start(
								find_cipher("3des"), // index of desired cipher
								iv, // the initial vector
								key, // the secret key
								keySize, // length of secret key
								0, // 0 == default # of rounds
								&cbc // where to store initialized CTR state
								);

	if (error != CRYPT_OK) 
	{
		BD_ERR(BD_LOG_LEVEL, "Error starting cipher.");
		BD_ERR(BD_LOG_LEVEL, "> %s", error_to_string(error));
		return false;
	}

	error = cbc_encrypt( 
						pt, /* plaintext */
						ct, /* ciphertext */
						static_cast<bdULong32>(size), /* length of data to encrypt */
						&cbc /* previously initialized CBC state */
						);
	
	if (error != CRYPT_OK) 
	{
		BD_ERR(BD_LOG_LEVEL, "Error encrypting ");
		BD_ERR(BD_LOG_LEVEL, "> %s", error_to_string(error));
		return false;
	}

	return true;
}


bdBool bdCypher3Des::decrypt(const bdUByte8 *key, 
							 const bdUInt keySize,
							 const bdUByte8 *iv, 
							 const bdUByte8 *ct, 
							 bdUByte8 *pt, 
							 bdUInt &size)
{
	symmetric_CBC cbc;

	bdInt error = cbc_start(
								find_cipher("3des"), // index of desired cipher
								iv, // the initial vector
								key, // the secret key
								keySize, // length of secret key
								0, // 0 == default # of rounds
								&cbc // where to store initialized CBC state
								);

	if (error != CRYPT_OK) 
	{
		BD_ERR(BD_LOG_LEVEL, "Error starting cipher.");
		return false;
	}


	error = cbc_decrypt( 
						ct, /* ciphertext */
						pt, /* plaintext */
						static_cast<bdULong32>(size), /* length of data to decrypt */
						&cbc
						);

	if (error != CRYPT_OK) 
	{
		BD_ERR(BD_LOG_LEVEL, "Error decrypting.");
		return false;
	}
	
	return true;
}

#else // !XBOXes

bdCypher3Des::bdCypher3Des()
{
}

bdCypher3Des::~bdCypher3Des()
{
}

bdBool bdCypher3Des::encrypt(const bdUByte8 *, 
							 const bdUInt ,
							 const bdUByte8 *, 
							 const bdUByte8 *, 
							 bdUByte8 *, 
							 bdUInt &)
{
	return false;
}


bdBool bdCypher3Des::decrypt(const bdUByte8 *, 
							 const bdUInt ,
							 const bdUByte8 *, 
							 const bdUByte8 *, 
							 bdUByte8 *, 
							 bdUInt &)
{
	return false;
}

#endif
