// Mech_RSA_PKCS.cpp: implementation of the CMech_SHA1_RSA_PKCS class.
//
//////////////////////////////////////////////////////////////////////

#include "Mech_SHA1_RSA_PKCS.h"

///////////////// Info para el relleno PKCS#1 ////////////////
#define NOK 0
#define OK  1

// Tipos de relleno PKCS#1
#define PKCS1_PRIVADA_00 0
#define PKCS1_PRIVADA_FF 1
#define PKCS1_PUBLICA	 2

// Minima longitud de la cadena de relleno
#define MIN_PADDINGSTRING_LEN 8


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CMech_SHA1_RSA_PKCS::CMech_SHA1_RSA_PKCS()
{
	// Si no nos pasan tamaños concretos, utilizaremos los genéricos para RSA
	m_MechInfo.ulMinKeySize	= RSA_KEY_BITS_MIN_SIZE;
	m_MechInfo.ulMaxKeySize	= RSA_KEY_BITS_MAX_SIZE;
	m_MechInfo.flags		= CKF_SIGN|CKF_VERIFY|CKF_DECRYPT;

	//m_MechType				= CKM_RSA_PKCS;
	m_MechType				= CKM_SHA1_RSA_PKCS;
}

CMech_SHA1_RSA_PKCS::CMech_SHA1_RSA_PKCS( CK_ULONG ulMinKeySize, 
										  CK_ULONG ulMaxKeySize, 
										  CK_FLAGS flags )
{
	m_MechInfo.ulMinKeySize	= ulMinKeySize;
	m_MechInfo.ulMaxKeySize	= ulMaxKeySize;
	m_MechInfo.flags		= flags;

	m_MechType				= CKM_SHA1_RSA_PKCS;
}

CMech_SHA1_RSA_PKCS::~CMech_SHA1_RSA_PKCS()
{

}

void CMech_SHA1_RSA_PKCS::AddPadding( byteBuffer &data, ulong ulPaddedDataLen )
{
	// Invocamos el método de padding de CUtil
	CUtil::pkcs1_5_Pad(data, ulPaddedDataLen);
}

void CMech_SHA1_RSA_PKCS::RemovePadding( byteBuffer & message )
{
	//CUtil::pkcs1_5_Unpad(message);
}

void CMech_SHA1_RSA_PKCS::ConstructDataUpdate( byteBuffer &data )
{
	// Para el mecanismo CKM_SHA1_RSA_PKCS hay que incluir el objectIdentifier
	// y calcular el hash SHA1 de los datos que nos pasan.
	m_sha1.Update(&data[0], data.size());
}

void CMech_SHA1_RSA_PKCS::ConstructDataFinal( byteBuffer &signature )
{
	// Para el mecanismo CKM_SHA1_RSA_PKCS hay que incluir el objectIdentifier
	// y calcular el hash SHA1 de los datos que nos pasan.

	// ObjectIdentifier del algoritmo SHA1WithRSAEncryption
	byte digestInfoHeader [15] = {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14};
	byteBuffer bbPaddedData( digestInfoHeader,  15);

	// Calculamos el hash de los datos recibidos
	int hashLen = m_sha1.DigestSize();
	byte * signatureAux = (byte *)new byte[hashLen];
	m_sha1.Final(&signatureAux[0]);
	byteBuffer bbHash( signatureAux, hashLen);

	// Construímos el byteBuffer con: DigestInfoHeader + Hash(data)
	bbPaddedData.append( bbHash );
	
	// Una vez completado el tratamiento de los datos, los copiamos en el byteBuffer de salida
	signature.zeroClear();
	signature.append( bbPaddedData );
}

void CMech_SHA1_RSA_PKCS::ConstructData( byteBuffer &data )
{
	// Para el mecanismo CKM_SHA1_RSA_PKCS hay que incluir el objectIdentifier
	// y calcular el hash SHA1 de los datos que nos pasan.

	// ObjectIdentifier del algoritmo SHA1WithRSAEncryption
	byte digestInfoHeader [15] = {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14};
	byteBuffer bbPaddedData( digestInfoHeader,  15);

	// Calculamos el hash de los datos recibidos
	byteBuffer bbHash (CUtil::sha1( data ));

	// Construímos el byteBuffer con: DigestInfoHeader + Hash(data)
	bbPaddedData.append( bbHash );
	
	// Una vez completado el tratamiento de los datos, los copiamos en el byteBuffer de salida
	data.zeroClear();
	data.append( bbPaddedData );
}

CK_RV CMech_SHA1_RSA_PKCS::SignInit(CPKCS11Object *pObj11, CK_VOID_PTR pParameter, CK_ULONG ulParameterLen)
{
	CK_RV rv_Result		 = CKR_OK;
	CK_ULONG ulObjAttrib = 0;

	// Comprobamos que el objeto sea una clave privada
	ulObjAttrib = pObj11->GetAttributeUlong( CKA_CLASS );
	if ( ulObjAttrib != CKO_PRIVATE_KEY)
		throw Pkcs11Exception( CKR_KEY_HANDLE_INVALID );

	// Comprobamos que la clave sea de tipo RSA
	ulObjAttrib = pObj11->GetAttributeUlong( CKA_KEY_TYPE );
	if ( ulObjAttrib != CKK_RSA)
		throw Pkcs11Exception( CKR_KEY_TYPE_INCONSISTENT );

	// Comprobamos que la clave privada RSA sea de firma
	if(!pObj11->GetAttributeBool(CKA_SIGN))
		throw Pkcs11Exception( CKR_KEY_FUNCTION_NOT_PERMITTED );

	// Los parámetros de este mecanismo deben estar a NULL
	if ((pParameter != NULL) ||
		(ulParameterLen != 0))
		throw Pkcs11Exception( CKR_MECHANISM_PARAM_INVALID );

	m_pPKCS11Object = pObj11;

	return rv_Result;
}

CK_RV CMech_SHA1_RSA_PKCS::SignUpdate(CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
{
	CK_RV rv_Result	= CKR_OK;

	// Modificaremos los datos de entrada en caso de que el mecanismo lo requiera
	byteBuffer data( pPart,  ulPartLen);
	ConstructDataUpdate(data);

	return rv_Result;
}

CK_RV CMech_SHA1_RSA_PKCS::VerifyInit(CPKCS11Object *pObj11, CK_VOID_PTR pParameter, CK_ULONG ulParameterLen)
{
	CK_RV rv_Result		 = CKR_OK;
	CK_ULONG ulObjAttrib = 0;

	// Comprobamos que el objeto sea una clave privada
	ulObjAttrib = pObj11->GetAttributeUlong( CKA_CLASS );
	if ( ulObjAttrib != CKO_PUBLIC_KEY)
		throw Pkcs11Exception( CKR_KEY_HANDLE_INVALID );

	// Comprobamos que la clave sea de tipo RSA
	ulObjAttrib = pObj11->GetAttributeUlong( CKA_KEY_TYPE );
	if ( ulObjAttrib != CKK_RSA)
		throw Pkcs11Exception( CKR_KEY_TYPE_INCONSISTENT );

	// Comprobamos que la clave privada RSA sea de firma
	if(!pObj11->GetAttributeBool(CKA_VERIFY))
		throw Pkcs11Exception( CKR_KEY_FUNCTION_NOT_PERMITTED );

	// Los parámetros de este mecanismo deben estar a NULL
	if ((pParameter != NULL) ||
		(ulParameterLen != 0))
		throw Pkcs11Exception( CKR_MECHANISM_PARAM_INVALID );

	m_pPKCS11Object = pObj11;

	return rv_Result;
}

CK_RV CMech_SHA1_RSA_PKCS::VerifyUpdate(CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
{
	CK_RV rv_Result	= CKR_OK;

	// Modificaremos los datos de entrada en caso de que el mecanismo lo requiera
	byteBuffer data( pPart,  ulPartLen);
	ConstructDataUpdate(data);

	return rv_Result;
}

