// wrap_key.cpp : Defines the entry point for the console application.
//

#include <stdio.h>
//#include <tchar.h>
#include <malloc.h>
#include <memory.h>

#include "../pkcs11_v2.2/cryptoki.h"

// 加载P11库 胡丽杰 2015-1-20
bool LoadP11Dll(const char* pP11Path, void* pP11Module, CK_FUNCTION_LIST_PTR_PTR pFuncList);
// 关闭P11库 胡丽杰 2015-1-20
bool CloseP11Dll(void* pP11Module, CK_FUNCTION_LIST_PTR pFuncList);

// 创建AES类型的秘钥 胡丽杰 2015-1-19
long CreateSecretKeyAes(CK_FUNCTION_LIST_PTR pFunctionList, CK_SESSION_HANDLE hSession,
	CK_OBJECT_HANDLE_PTR phAesKey);
// 创建3DES类型的秘钥 胡丽杰 2015-1-19
long CreateSecretKey3Des(CK_FUNCTION_LIST_PTR pFunctionList, CK_SESSION_HANDLE hSession,
	CK_OBJECT_HANDLE_PTR ph3DesKey);
// 创建RSA秘钥对 胡丽杰 2015-1-19
long CreateRsaKeyPair(CK_FUNCTION_LIST_PTR pFunctionList, CK_SESSION_HANDLE hSession,
	CK_ULONG ulModulusBits, CK_OBJECT_HANDLE_PTR phPubKey, CK_OBJECT_HANDLE_PTR phPriKey);
// 测试秘钥打包秘钥、解包秘钥 胡丽杰 2015-1-19
long Test_SecretKeyWrapSecretKey(CK_FUNCTION_LIST_PTR pFunctionList, CK_SESSION_HANDLE hSession,
	CK_OBJECT_HANDLE hWrapingKey, CK_MECHANISM ckmWrap, CK_OBJECT_HANDLE hWrapedKey,
	CK_ATTRIBUTE_PTR pAttUnwrapKey, CK_ULONG ulAttCount, CK_MECHANISM ckmEncrypt);
// 测试秘钥打包私钥、解包私钥 胡丽杰 2015-1-19
long Test_SecretKeyWrapPriKey(CK_FUNCTION_LIST_PTR pFunctionList, CK_SESSION_HANDLE hSession,
	CK_OBJECT_HANDLE hWrapingKey, CK_MECHANISM ckmWrap, CK_OBJECT_HANDLE hPubKey,
	CK_OBJECT_HANDLE hPriKey, CK_ATTRIBUTE_PTR pAttUnwrapKey, CK_ULONG ulAttCount,
	CK_MECHANISM ckmEncrypt);
// 测试公钥打包秘钥、私钥解包秘钥 胡丽杰 2015-1-19
long Test_PubKeyWrapSecretKey(CK_FUNCTION_LIST_PTR pFunctionList, CK_SESSION_HANDLE hSession,
	CK_OBJECT_HANDLE hPubKey, CK_MECHANISM ckmWrap, CK_OBJECT_HANDLE hPriKey,
	CK_OBJECT_HANDLE hWrapedKey, CK_ATTRIBUTE_PTR pAttUnwrapKey, CK_ULONG ulAttCount,
	CK_MECHANISM ckmEncrypt);
long FindPublicKey(CK_FUNCTION_LIST_PTR pFunctionList, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE *phPriKey);
long FindPrivateKey(CK_FUNCTION_LIST_PTR pFunctionList, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE *phPriKey);

CK_OBJECT_HANDLE FindObject(CK_FUNCTION_LIST_PTR pFunctionList, CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pAttrTemplates, CK_ULONG ulCount );

#define ERROR_THROW(r) {if(r!=0) goto END_OF_FUN;}

int main(int argc, char* argv[])
{
	if(argc < 2)
		return 1;

	char * p11_dll = argv[1]; 

	//pkcs11_wrapper p11_wrapper;

	//if(0 != p11_wrapper.pkcs11_initialize(p11_dll))
	//{
	//	return 1;
	//}

	//CK_FUNCTION_LIST_PTR pToken = p11_wrapper.GetFunctionsPtr();

	CK_RV rv = CKR_OK;
	CK_ULONG ulCount;
	CK_SESSION_HANDLE hSession;

	CK_UTF8CHAR uPin[] = "11111111";

	CK_OBJECT_HANDLE hAesKey;
	CK_OBJECT_HANDLE h3DesKey;
	CK_OBJECT_HANDLE hPubKey, hPriKey;
	CK_MECHANISM ckmWrap;
	CK_MECHANISM ckmEncrypt;
	CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; 
	CK_KEY_TYPE keyType = CKK_AES;
	CK_ULONG ulLen = 16;
	CK_BBOOL bTrue = CK_TRUE;
	CK_ULONG ulKeyID = 9;
	CK_ATTRIBUTE tmpAes[] = { 
		{CKA_CLASS, &keyClass, sizeof(keyClass)}, 
		{CKA_KEY_TYPE, &keyType, sizeof(keyType)},
		{CKA_VALUE_LEN, &ulLen, sizeof(ulLen)},
		{CKA_ENCRYPT, &bTrue, sizeof(true)}, 
		{CKA_DECRYPT, &bTrue, sizeof(true)},
		{CKA_ID, &ulKeyID, sizeof(ulKeyID)}
	}; 

	CK_ATTRIBUTE tmp3Des[] = { 
		{CKA_CLASS, &keyClass, sizeof(keyClass)}, 
		{CKA_KEY_TYPE, &keyType, sizeof(keyType)},
		{CKA_ENCRYPT, &bTrue, sizeof(true)}, 
		{CKA_DECRYPT, &bTrue, sizeof(true)},
		{CKA_ID, &ulKeyID, sizeof(ulKeyID)}
	}; 

	CK_ATTRIBUTE tmpRsa[] = {
		{CKA_CLASS, &keyClass, sizeof(keyClass)},
		{CKA_KEY_TYPE, &keyType, sizeof(keyType)},
		{CKA_ID, &ulKeyID, sizeof(ulKeyID)},
		{CKA_TOKEN, &bTrue, sizeof(bTrue)},
		{CKA_PRIVATE, &bTrue, sizeof(bTrue)},
		{CKA_SENSITIVE, &bTrue, sizeof(bTrue)},
		{CKA_DECRYPT, &bTrue, sizeof(bTrue)},
		{CKA_SIGN, &bTrue, sizeof(bTrue)},
		{CKA_UNWRAP, &bTrue, sizeof(bTrue)}
	};

	CK_BYTE szValue[256] = {0};
	CK_ULONG ulSize = 256;
	CK_ATTRIBUTE attValue[] = {CKA_VALUE, szValue, ulSize};

	void* pP11Module = NULL;
	CK_FUNCTION_LIST_PTR pFuncList = NULL;
	if (!LoadP11Dll(p11_dll, pP11Module, &pFuncList))
	{
		printf("Load p11 failed!\n");
		goto END_OF_FUN;
	}

	rv = pFuncList->C_GetSlotList(CK_TRUE, NULL_PTR, &ulCount);
	ERROR_THROW(rv);

	CK_SLOT_ID pSlotList[8];
	//pSlotList = (CK_SLOT_ID_PTR)new CK_SLOT_ID[ulCount];;
	rv = pFuncList->C_GetSlotList(CK_TRUE, pSlotList, &ulCount);
	ERROR_THROW(rv);

	if (ulCount <= 0)
	{
		rv = CKR_TOKEN_NOT_PRESENT;
		ERROR_THROW(rv);
	}

	//Create a read only session
	rv = pFuncList->C_OpenSession(pSlotList[0], CKF_SERIAL_SESSION|CKF_RW_SESSION,
		NULL_PTR, NULL_PTR, &hSession);
	if (rv != CKR_OK)
	{
		//delete[] pSlotList;
		return 2;
	}
	
	rv = pFuncList->C_Login(hSession, CKU_USER, uPin, 8);
	ERROR_THROW(rv);

	printf("CreateSecretKeyAes...\n");
	rv = CreateSecretKeyAes(pFuncList, hSession, &hAesKey);
	ERROR_THROW(rv);

	rv = pFuncList->C_GetAttributeValue(hSession, hAesKey, attValue, 1);
	ERROR_THROW(rv);
	printf("CKA_VALUE:");
	for (int i=0; i<attValue[0].ulValueLen; i++)
	{
		printf(" %2x", szValue[i]);
	}
	printf("\n");
	
	printf("CreateSecretKey3Des...\n");
	rv = CreateSecretKey3Des(pFuncList, hSession, &h3DesKey);
	ERROR_THROW(rv);

	printf("CreateRsaKeyPair...\n");
	rv = CreateRsaKeyPair(pFuncList, hSession, 2048, &hPubKey, &hPriKey);
	ERROR_THROW(rv);

	printf("Test_PubKeyWrapSecretKey...\n");
	ckmWrap.mechanism = CKM_RSA_PKCS;
	ckmWrap.pParameter = NULL_PTR;
	ckmWrap.ulParameterLen = 0;

	ckmEncrypt.mechanism = CKM_AES_CBC_PAD;
	ckmEncrypt.pParameter = NULL_PTR;
	ckmEncrypt.ulParameterLen = 0;

	rv = Test_PubKeyWrapSecretKey(pFuncList, hSession, hPubKey, ckmWrap, hPriKey, hAesKey,
		tmpAes, sizeof(tmpAes)/sizeof(CK_ATTRIBUTE), ckmEncrypt);
	ERROR_THROW(rv);

	printf("Test_SecretKeyWrapSecretKey...\n");
	ckmWrap.mechanism = CKM_AES_CBC_PAD;
	ckmWrap.pParameter = NULL_PTR;
	ckmWrap.ulParameterLen = 0;

	ckmEncrypt.mechanism = CKM_DES3_CBC_PAD;
	ckmEncrypt.pParameter = NULL_PTR;
	ckmEncrypt.ulParameterLen = 0;
	keyClass = CKO_SECRET_KEY; 
	keyType = CKK_DES3;
	ulKeyID = 9;
	rv = Test_SecretKeyWrapSecretKey(pFuncList, hSession, hAesKey, ckmWrap, h3DesKey,
		tmp3Des, sizeof(tmp3Des)/sizeof(CK_ATTRIBUTE), ckmEncrypt);
	ERROR_THROW(rv);

	printf("Test_SecretKeyWrapPriKey...\n");
	ckmWrap.mechanism = CKM_AES_CBC_PAD;
	ckmWrap.pParameter = NULL_PTR;
	ckmWrap.ulParameterLen = 0;

	ckmEncrypt.mechanism = CKM_RSA_PKCS;
	ckmEncrypt.pParameter = NULL_PTR;
	ckmEncrypt.ulParameterLen = 0;

	keyClass = CKO_PRIVATE_KEY;
	keyType = CKK_RSA;
	ulKeyID = 9;
	rv = Test_SecretKeyWrapPriKey(pFuncList, hSession, hAesKey, ckmWrap, hPubKey,
		hPriKey, tmpRsa, sizeof(tmpRsa)/sizeof(CK_ATTRIBUTE), ckmEncrypt);
	ERROR_THROW(rv);

	printf("Destroy hAesKey...\n");
	rv = pFuncList->C_DestroyObject(hSession, hAesKey);
	ERROR_THROW(rv);

	printf("Destroy h3DesKey...\n");
	rv = pFuncList->C_DestroyObject(hSession, h3DesKey);
	ERROR_THROW(rv);

	printf("Destroy hPubKey...\n");
	rv = pFuncList->C_DestroyObject(hSession, hPubKey);
	ERROR_THROW(rv);

	printf("Destroy hPriKey...\n");
	rv = pFuncList->C_DestroyObject(hSession, hPriKey);
	ERROR_THROW(rv);

END_OF_FUN:
	if(rv != CKR_OK)
	{
		printf("Error = %0x \n", (unsigned int)rv);
	}
	else
	{
		printf("Successfully!\n");
	}

	CloseP11Dll(pP11Module, pFuncList);
	getchar();
	return 0;
}

#ifdef WIN32
	#include <windows.h>
#else
	#include <dlfcn.h>
#endif

// 加载P11库 胡丽杰 2015-1-20
bool LoadP11Dll(const char* pP11Path, void* pP11Module, CK_FUNCTION_LIST_PTR_PTR pFuncList)
{
	pP11Module = NULL;
	CK_RV (*c_get_function_list)(CK_FUNCTION_LIST_PTR_PTR) = NULL;
#ifdef WIN32
	pP11Module = (void*)LoadLibrary(pP11Path);
	if (pP11Module == NULL)
		return false;
	c_get_function_list = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR))GetProcAddress(
		(HMODULE)pP11Module, "C_GetFunctionList");
#else
	pP11Module = dlopen(pP11Path, RTLD_LAZY);
	if (pP11Module == NULL)
		return false;
	c_get_function_list = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR))dlsym(pP11Module,
		"C_GetFunctionList");
#endif

	if (c_get_function_list == NULL)
		return false;
	CK_RV rv = c_get_function_list(pFuncList);
	if (rv != CKR_OK)
		return false;

	rv = (*pFuncList)->C_Initialize(NULL_PTR);
	if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)
	{
		return false;
	}

	return true;
}

// 关闭P11库 胡丽杰 2015-1-20
bool CloseP11Dll(void* pP11Module, CK_FUNCTION_LIST_PTR pFuncList)
{
	if (pFuncList != NULL)
	{
		pFuncList->C_Finalize(NULL);
	}
	pFuncList = NULL;

	if (pP11Module != NULL)
	{
#ifdef WIN32
		if (FreeLibrary((HMODULE)pP11Module))
			pP11Module = NULL;
		else
			return false;
#else
		dlclose(pP11Module);
#endif
	}

	return true;
}

long CreateSecretKeyAes(CK_FUNCTION_LIST_PTR pFunctionList, CK_SESSION_HANDLE hSession,
	CK_OBJECT_HANDLE_PTR phAesKey)
{
	CK_BYTE cka_value[128] = {1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8};
	CK_OBJECT_CLASS oClass = CKO_SECRET_KEY;
	CK_KEY_TYPE keyType = CKK_AES; 
	CK_BBOOL bTrue = true;
	CK_BBOOL bFalse = false;
	CK_ULONG ulLen = 16;
	CK_ULONG key_ID = 6;
	CK_ATTRIBUTE AESItem[] = {
		{CKA_CLASS, &oClass, sizeof(CK_OBJECT_CLASS)},
		{CKA_KEY_TYPE, &keyType, sizeof(CK_KEY_TYPE)},
		//		{CKA_TOKEN, &bTrue, sizeof(CK_BBOOL)},
		{CKA_ENCRYPT, &bTrue, sizeof(CK_BBOOL)},
		{CKA_DECRYPT, &bTrue, sizeof(CK_BBOOL)},
		{CKA_EXTRACTABLE, &bTrue, sizeof(CK_BBOOL)},
		{CKA_VALUE, cka_value, ulLen},
		{CKA_VALUE_LEN, &ulLen, sizeof(ulLen)},
		{CKA_ID, &key_ID, sizeof(key_ID)},
		{CKA_EXTRACTABLE, &bTrue, sizeof(CK_BBOOL)}
	};

	CK_ULONG ulCount = sizeof(AESItem) / sizeof(CK_ATTRIBUTE);
	CK_RV rv = pFunctionList->C_CreateObject(hSession, AESItem, ulCount, phAesKey);
	return rv;
}

long CreateSecretKey3Des(CK_FUNCTION_LIST_PTR pFunctionList, CK_SESSION_HANDLE hSession,
	CK_OBJECT_HANDLE_PTR ph3DesKey)
{
	CK_BYTE cka_value[128] = {1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8};
	CK_OBJECT_CLASS oClass = CKO_SECRET_KEY;
	CK_KEY_TYPE keyType = CKK_DES3; 
	CK_BBOOL bTrue = true;
	CK_BBOOL bFalse = false;
	CK_ULONG ulLen = 24;
	CK_ULONG key_ID = 7;
	CK_ATTRIBUTE DES3Item[] = {
		{CKA_CLASS, &oClass, sizeof(CK_OBJECT_CLASS)},
		{CKA_KEY_TYPE, &keyType, sizeof(CK_KEY_TYPE)},
		//		{CKA_TOKEN, &bTrue, sizeof(CK_BBOOL)},
		{CKA_ENCRYPT, &bTrue, sizeof(CK_BBOOL)},
		{CKA_DECRYPT, &bTrue, sizeof(CK_BBOOL)},
		{CKA_EXTRACTABLE, &bTrue, sizeof(CK_BBOOL)},
		{CKA_VALUE, cka_value, ulLen},
		{CKA_ID, &key_ID, sizeof(key_ID)}
	};

	CK_ULONG ulCount = sizeof(DES3Item) / sizeof(CK_ATTRIBUTE);
	CK_RV rv = pFunctionList->C_CreateObject(hSession, DES3Item, ulCount, ph3DesKey);
	return rv;
}

long CreateRsaKeyPair(CK_FUNCTION_LIST_PTR pFunctionList, CK_SESSION_HANDLE hSession,
	CK_ULONG ulModulusBits, CK_OBJECT_HANDLE_PTR phPubKey, CK_OBJECT_HANDLE_PTR phPriKey)
{
	if (ulModulusBits!=1024 && ulModulusBits!=2048)
	{
		return CKR_ATTRIBUTE_VALUE_INVALID;
	}

	CK_MECHANISM mechanism = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0};
	CK_BYTE publicExponent[] = { 0x01, 0x00, 0x01 }; /* 65537 in bytes */
	CK_BBOOL _true = TRUE;
	CK_OBJECT_CLASS pubkey_class = CKO_PUBLIC_KEY;
	CK_OBJECT_CLASS privkey_class = CKO_PRIVATE_KEY;
	CK_BYTE szLabel[] = "08_key";
	CK_ULONG ulID = 8;
	CK_ATTRIBUTE publicKeyTemplate[20] = {
		{CKA_CLASS, &pubkey_class, sizeof(pubkey_class)},
		{CKA_TOKEN, &_true, sizeof(_true)},
		{CKA_ENCRYPT, &_true, sizeof(_true)},
		{CKA_VERIFY, &_true, sizeof(_true)},
		{CKA_WRAP, &_true, sizeof(_true)},
		{CKA_MODULUS_BITS, &ulModulusBits, sizeof(ulModulusBits)},
		{CKA_PUBLIC_EXPONENT, publicExponent, sizeof(publicExponent)},
		{CKA_LABEL, szLabel, sizeof(szLabel)},
		{CKA_ID, &ulID, sizeof(ulID)}
	};

	CK_ATTRIBUTE privateKeyTemplate[20] = {
		{CKA_CLASS, &privkey_class, sizeof(privkey_class)},
		{CKA_TOKEN, &_true, sizeof(_true)},
		{CKA_PRIVATE, &_true, sizeof(_true)},
		{CKA_SENSITIVE, &_true, sizeof(_true)},
		{CKA_DECRYPT, &_true, sizeof(_true)},
		{CKA_SIGN, &_true, sizeof(_true)},
		{CKA_UNWRAP, &_true, sizeof(_true)},
		{CKA_LABEL, szLabel, sizeof(szLabel)},
		{CKA_ID, &ulID, sizeof(ulID)}
	};

	CK_RV rv = pFunctionList->C_GenerateKeyPair(hSession, &mechanism,
		publicKeyTemplate, 9, privateKeyTemplate, 9, phPubKey, phPriKey);
	return rv;
}

// 测试秘钥打包秘钥、解包秘钥
// 参数：hWrapingKey [in] 用来打包、解包的秘钥
// 参数：ckmWrap [in] 打包、解包的机制
// 参数：hWrapedKey [in] 被打包的秘钥
// 参数：pAttUnwrapKey [in] 解包时要生成的秘钥属性模板
// 参数：ulAttCount [in] 模板属性个数
// 参数：ckmEncrypt [in] 使用被打包秘钥进行加解密测试的机制
long Test_SecretKeyWrapSecretKey(CK_FUNCTION_LIST_PTR pFunctionList, CK_SESSION_HANDLE hSession,
	CK_OBJECT_HANDLE hWrapingKey, CK_MECHANISM ckmWrap, CK_OBJECT_HANDLE hWrapedKey,
	CK_ATTRIBUTE_PTR pAttUnwrapKey, CK_ULONG ulAttCount, CK_MECHANISM ckmEncrypt)
{
	CK_RV rv = pFunctionList->C_EncryptInit(hSession, &ckmEncrypt, hWrapedKey);
	if (rv != CKR_OK)
	{
		return rv;
	}

	CK_BYTE szData[] = "hello word";
	CK_BYTE szEncryptData[1024];
	CK_ULONG ulEncryptLen = 1024;
	rv = pFunctionList->C_Encrypt(hSession, szData, sizeof(szData), szEncryptData,
		&ulEncryptLen);
	if (rv != CKR_OK)
	{
		return rv;
	}

	CK_ULONG wrapLen = 0;
	rv = pFunctionList->C_WrapKey(hSession, &ckmWrap, hWrapingKey, hWrapedKey, NULL_PTR,
		&wrapLen);
	if (rv != CKR_OK)
	{
		return rv;
	}

	CK_BYTE_PTR pWrappedData = (CK_BYTE_PTR) malloc(wrapLen);
	rv = pFunctionList->C_WrapKey(hSession, &ckmWrap, hWrapingKey, hWrapedKey,
		pWrappedData, &wrapLen);
	if (rv != CKR_OK)
	{
		return rv;
	}

	CK_OBJECT_HANDLE hNewKey = 0;
	rv = pFunctionList->C_UnwrapKey(hSession, &ckmWrap, hWrapingKey, pWrappedData, wrapLen,
		pAttUnwrapKey, ulAttCount, &hNewKey);
	if (rv != CKR_OK)
	{
		return rv;
	}

	CK_BYTE szValue[256] = {0};
	CK_ULONG ulSize = 256;
	CK_ATTRIBUTE attValue[] = {CKA_VALUE, szValue, ulSize};
	rv = pFunctionList->C_GetAttributeValue(hSession, hNewKey, attValue, 1);
	printf("CKA_VALUE:");
	for (int i=0; i<attValue[0].ulValueLen; i++)
	{
		printf(" %2x", szValue[i]);
	}
	printf("\n");

	rv = pFunctionList->C_DecryptInit(hSession, &ckmEncrypt, hNewKey);
	if (rv != CKR_OK)
	{
		return rv;
	}
	CK_BYTE szDecryptData[1024];
	CK_ULONG ulDecryptLen = 1024;
	rv = pFunctionList->C_Decrypt(hSession, szEncryptData, ulEncryptLen, szDecryptData,
		&ulDecryptLen);
	if (rv != CKR_OK)
	{
		return rv;
	}

	rv = pFunctionList->C_DestroyObject(hSession, hNewKey);
	if (rv != CKR_OK)
	{
		return rv;
	}

	if (memcmp(szData, szDecryptData, ulDecryptLen) != 0)
	{
		return CKR_FUNCTION_FAILED;
	}

	return CKR_OK;
}

// 测试秘钥打包私钥、解包私钥
// 参数：hWrapingKey [in] 用来打包、解包的秘钥
// 参数：ckmWrap [in] 打包、解包的机制
// 参数：hPubKey [in] 被打包的私钥所对应的公钥，用于加解密测试
// 参数：hPriKey [in] 被打包的私钥
// 参数：pAttUnwrapKey [in] 解包时要生成的私钥的属性模板
// 参数：ulAttCount [in] 模板属性个数
// 参数：ckmEncrypt [in] 使用被打包私钥进行加解密测试的机制
long Test_SecretKeyWrapPriKey(CK_FUNCTION_LIST_PTR pFunctionList, CK_SESSION_HANDLE hSession,
	CK_OBJECT_HANDLE hWrapingKey, CK_MECHANISM ckmWrap, CK_OBJECT_HANDLE hPubKey,
	CK_OBJECT_HANDLE hPriKey, CK_ATTRIBUTE_PTR pAttUnwrapKey, CK_ULONG ulAttCount,
	CK_MECHANISM ckmEncrypt)
{
	CK_RV rv = pFunctionList->C_EncryptInit(hSession, &ckmEncrypt, hPubKey);
	if (rv != CKR_OK)
	{
		return rv;
	}

	CK_BYTE szData[] = "hello word";
	CK_BYTE szEncryptData[1024];
	CK_ULONG ulEncryptLen = 1024;
	rv = pFunctionList->C_Encrypt(hSession, szData, sizeof(szData), szEncryptData,
		&ulEncryptLen);
	if (rv != CKR_OK)
	{
		return rv;
	}


	CK_ULONG wrapLen = 0;
	rv = pFunctionList->C_WrapKey(hSession, &ckmWrap, hWrapingKey, hPriKey, NULL_PTR,
		&wrapLen);
	if (rv != CKR_OK)
	{
		return rv;
	}

	CK_BYTE_PTR pWrappedData = (CK_BYTE_PTR) malloc(wrapLen);
	rv = pFunctionList->C_WrapKey(hSession, &ckmWrap, hWrapingKey, hPriKey,
		pWrappedData, &wrapLen);
	if (rv != CKR_OK)
	{
		return rv;
	}

	//FILE* pf = fopen("e:\\1.txt", "wt");
	//for (int i=0; i<wrapLen; i++)
	//{
	//	fprintf(pf, "%02x", pWrappedData[i]);
	//}
	//fclose(pf);

	CK_OBJECT_HANDLE hNewKey = 0;
	rv = pFunctionList->C_UnwrapKey(hSession, &ckmWrap, hWrapingKey, pWrappedData, wrapLen,
		pAttUnwrapKey, ulAttCount, &hNewKey);
	if (rv != CKR_OK)
	{
		return rv;
	}

	rv = pFunctionList->C_DecryptInit(hSession, &ckmEncrypt, hNewKey);
	if (rv != CKR_OK)
	{
		return rv;
	}
	CK_BYTE szDecryptData[1024];
	CK_ULONG ulDecryptLen = 1024;
	rv = pFunctionList->C_Decrypt(hSession, szEncryptData, ulEncryptLen, szDecryptData,
		&ulDecryptLen);
	if (rv != CKR_OK)
	{
		return rv;
	}

	rv = pFunctionList->C_DestroyObject(hSession, hNewKey);
	if (rv != CKR_OK)
	{
		return rv;
	}

	if (memcmp(szData, szDecryptData, ulDecryptLen) != 0)
	{
		return CKR_FUNCTION_FAILED;
	}

	return CKR_OK;
}

// 测试公钥打包秘钥、私钥解包秘钥
// 参数：hPubKey [in] 用来打包的公钥
// 参数：ckmWrap [in] 打包、解包的机制
// 参数：hPriKey [in] 用来解包的私钥
// 参数：hWrapedKey [in] 被打包的秘钥
// 参数：pAttUnwrapKey [in] 解包时要生成的秘钥属性模板
// 参数：ulAttCount [in] 模板属性个数
// 参数：ckmEncrypt [in] 使用被打包秘钥进行加解密测试的机制
long Test_PubKeyWrapSecretKey(CK_FUNCTION_LIST_PTR pFunctionList, CK_SESSION_HANDLE hSession,
	CK_OBJECT_HANDLE hPubKey, CK_MECHANISM ckmWrap, CK_OBJECT_HANDLE hPriKey,
	CK_OBJECT_HANDLE hWrapedKey, CK_ATTRIBUTE_PTR pAttUnwrapKey, CK_ULONG ulAttCount,
	CK_MECHANISM ckmEncrypt)
{
	CK_RV rv = pFunctionList->C_EncryptInit(hSession, &ckmEncrypt, hWrapedKey);
	if (rv != CKR_OK)
	{
		return rv;
	}

	CK_BYTE szData[] = "123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789123456789abc";
	CK_BYTE szEncryptData[1024];
	CK_ULONG ulEncryptLen = 1024;
	rv = pFunctionList->C_Encrypt(hSession, szData, sizeof(szData), szEncryptData,
		&ulEncryptLen);
	if (rv != CKR_OK)
	{
		return rv;
	}

	CK_ULONG wrapLen = 0;
	rv = pFunctionList->C_WrapKey(hSession, &ckmWrap, hPubKey, hWrapedKey, NULL_PTR,
		&wrapLen);
	if (rv != CKR_OK)
	{
		return rv;
	}

	CK_BYTE_PTR pWrappedData = (CK_BYTE_PTR) malloc(wrapLen);
	rv = pFunctionList->C_WrapKey(hSession, &ckmWrap, hPubKey, hWrapedKey,
		pWrappedData, &wrapLen);
	if (rv != CKR_OK)
	{
		return rv;
	}

	CK_OBJECT_HANDLE hNewKey = 0;
	rv = pFunctionList->C_UnwrapKey(hSession, &ckmWrap, hPriKey, pWrappedData, wrapLen,
		pAttUnwrapKey, ulAttCount, &hNewKey);
	if (rv != CKR_OK)
	{
		return rv;
	}

	CK_BYTE szValue[256] = {0};
	CK_ULONG ulSize = 256;
	CK_ATTRIBUTE attValue[] = {CKA_VALUE, szValue, ulSize};
	rv = pFunctionList->C_GetAttributeValue(hSession, hNewKey, attValue, 1);
	printf("CKA_VALUE:");
	for (int i=0; i<attValue[0].ulValueLen; i++)
	{
		printf(" %2x", szValue[i]);
	}
	printf("\n");

	rv = pFunctionList->C_DecryptInit(hSession, &ckmEncrypt, hNewKey);
	if (rv != CKR_OK)
	{
		return rv;
	}
	CK_BYTE szDecryptData[1024];
	CK_ULONG ulDecryptLen = 1024;
	rv = pFunctionList->C_Decrypt(hSession, szEncryptData, ulEncryptLen, szDecryptData,
		&ulDecryptLen);
	if (rv != CKR_OK)
	{
		return rv;
	}

	rv = pFunctionList->C_DestroyObject(hSession, hNewKey);
	if (rv != CKR_OK)
	{
		return rv;
	}

	if (memcmp(szData, szDecryptData, ulDecryptLen) != 0)
	{
		return CKR_FUNCTION_FAILED;
	}

	return CKR_OK;
}

long FindPublicKey(CK_FUNCTION_LIST_PTR pFunctionList, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE *phPubKey)
{
	CK_OBJECT_CLASS objectClass = CKO_PUBLIC_KEY;
	CK_KEY_TYPE keyType = CKK_RSA;
	CK_BBOOL p11True = TRUE; 
	CK_ULONG ulID = 5;

	CK_ATTRIBUTE kpPriAttr[]={
		{CKA_CLASS, &objectClass, sizeof(objectClass)},
		{CKA_KEY_TYPE, &keyType, sizeof(keyType)},
		{CKA_ID, &ulID, sizeof(ulID)}
	};

	CK_ULONG ulCount = sizeof(kpPriAttr) / sizeof(CK_ATTRIBUTE);

	*phPubKey = FindObject(pFunctionList, hSession, kpPriAttr,ulCount);

	if(*phPubKey == NULL) //not found
	{
		return CKR_OBJECT_HANDLE_INVALID;
	}	

	return CKR_OK;
}

long FindPrivateKey(CK_FUNCTION_LIST_PTR pFunctionList, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE *phPriKey)
{
	CK_OBJECT_CLASS objectClass = CKO_PRIVATE_KEY;
	CK_KEY_TYPE keyType = CKK_RSA;
	CK_BBOOL p11True = TRUE;                  
	CK_ULONG ulID = 5;

	CK_ATTRIBUTE kpPriAttr[]={
		{CKA_CLASS, &objectClass, sizeof(objectClass)},
		{CKA_KEY_TYPE, &keyType, sizeof(keyType)},
		{CKA_ID, &ulID, sizeof(ulID)}
	};

	CK_ULONG ulCount = sizeof(kpPriAttr) / sizeof(CK_ATTRIBUTE);

	*phPriKey = FindObject(pFunctionList, hSession, kpPriAttr,ulCount);

	if(*phPriKey == NULL) //not found
	{
		return CKR_OBJECT_HANDLE_INVALID;
	}	

	return CKR_OK;
}

CK_OBJECT_HANDLE FindObject(CK_FUNCTION_LIST_PTR pFunctionList, CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pAttrTemplates, CK_ULONG ulCount )
{
	CK_RV rv = CKR_OK;

	rv = pFunctionList->C_FindObjectsInit(hSession, pAttrTemplates, ulCount); 
	if (rv != CKR_OK)
	{
		return 0;
	}

	CK_OBJECT_HANDLE foundObj = NULL;
	CK_ULONG objNumber = 1;

	rv = pFunctionList->C_FindObjects(hSession, &foundObj, 1, &objNumber);
	if (rv != 0)
	{
		pFunctionList->C_FindObjectsFinal(hSession);
		return NULL;
	}

	pFunctionList->C_FindObjectsFinal(hSession);

	if(objNumber  ==  0) //not found
		foundObj = NULL;

	return foundObj;
}
