#pragma once

#include "byteBuffer.h"

#include "CryptoPP/integer.h"
#include "CryptoPP/osrng.h"		// Para el generador de números aleatorios (de CryptoPP)

#include "BIT_STRING.h"
#include "INTEGER.h"
#include "cryptoki.h"

using namespace CryptoPP;

#ifdef _DEBUG
	#define DBG_TRACE(PARAMS)			CUtil::DBG_trace PARAMS
	#define DBG_DUMP(PARAMS)			CUtil::DBG_dumpData PARAMS
	#define DBG_DUMP_TEMPLATE(PARAMS)	CUtil::DBG_dumpTemplate PARAMS
	#define DBG_DUMP_DIRECT(PARAMS)		CUtil::DBG_dumpDirect PARAMS
#else
	#define DBG_TRACE(PARAMS)
	#define DBG_DUMP(PARAMS)
	#define DBG_DUMP_TEMPLATE(PARAMS)
	#define DBG_DUMP_DIRECT(PARAMS)
#endif


//
// Estructuras para manejar claves RSA (no CRT)
//
typedef struct
{
	CryptoPP::Integer	m_n;
	CryptoPP::Integer	m_d;
	CryptoPP::Integer	m_e;
} RSA_PrivateKey;

typedef struct
{
	CryptoPP::Integer	m_n;
	CryptoPP::Integer	m_e;
} RSA_PublicKey;


class CUtil
{
public:
	//
	// Métodos para manejo de pading, TLV, ...
	//
	static void	pkcs1_5_Pad( byteBuffer &data, ulong ulPaddedDataLen );
	static void	pkcs1_5_Unpad( SecByteBlock & message );
	static void	addPadding_7816( byteBuffer &data );
	static void	unPad_7816( byteBuffer &data );
	static long	getTLV( byte * tlv, long * pTag, long * pTL_dataLen );
	static void	buildTLV( byte tag, byteBuffer & value );

	static void pkcs1Unpadding( byteBuffer  paddedData, byteBuffer & unpaddedData);

	//
	// Verificación de certificado X509, y obtención de clave pública
	//
	static void	verify_X509_cert( byteBuffer & X509_certificate, RSA_PublicKey & caKey, RSA_PublicKey & outKey );


	// Operaciones básicas de RSA
	//
	static void	RSA_public( RSA_PublicKey & key, byteBuffer & in, byteBuffer & out );
	static void	RSA_public( RSA_PublicKey & key, SecByteBlock & in, SecByteBlock & out );
	static void	RSA_private( RSA_PrivateKey & key, byteBuffer & in, byteBuffer & out );

	//
	// Método auxiliar utilizado en la autenticación externa
	//     sigmin(a,b) = min(a,b-a);
	//
	static byteBuffer sigmin( byteBuffer a, Integer ib );

	//
	// Funciones de cifrado/descifrado DES
	//
	static void	DES_EDE2_cipher( byteBuffer & data, byteBuffer desKey );
	static void	DES_EDE2_decipher( byteBuffer & data, byteBuffer desKey );

	//
	// Cálculo de hash SHA1
	//
	static byteBuffer sha1( byteBuffer & hashIn );
	static byteBuffer sha1( byte * hashIn, ulong len );

	//
	// Actualización del hash para firma por bloques
	//
	static void sha1Update	( SHA1 & sha1, byteBuffer & data );
	static void sha1Final	( SHA1 & sha1, byteBuffer & signature );

	//
	// Método para generar stream de datos p-aleatorios
	//
	static void GenerateRandomBlock(byte *output, size_t size);

	//
	// Método para acceso a datos ASN1
	//
	static bool GetBit( BIT_STRING_t * bitString, ulong bit );
	static int GetInt32( INTEGER_t * pInteger );
	static bool SetBit( BIT_STRING_t * bitString, ulong bit, bool bValue );

	//
	// Método para convertir codificación del campo Path en tarjetas CERES.
	//
	static void PathASCII2bin( byte * pbASCII, ulong ulASCIILen, byteBuffer & bbBIN );
	static byteBuffer PathBin2ASCII( byteBuffer & bbAscii );
	static void Bin2ASCII( byte * pBin, ulong ulBinLen, char * pASCII );

#ifdef _DEBUG
	//
	// Funciones de trazas
	//
	static void DBG_trace( const char * format, ... );
	static void DBG_dumpData( byte * pData, long lenData );
	static void DBG_dumpData( byteBuffer & data )
	{
		if( data.size() )
			DBG_dumpData( &data[0], (long)data.size() );
	}
	static void DBG_dumpTemplate( CK_ATTRIBUTE_PTR pTemplate, CK_ULONG count );
	static void DBG_dumpDirect(char* texto, byte * pData, long lenData );

#endif

};
