#include "TassCtlAPI4PCIeSM.h"
#include "TassType4PCIeSM.h"

#include <cstdio>
#include <cstring>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <iomanip>

#if defined(_WIN32) || defined(_WIN64)
#include <io.h >
#include <sys\timeb.h>
#include <windows.h>
#else
#include <unistd.h>
#include <arpa/inet.h>
#include <curses.h>
#include <sys/time.h>
#include <dlfcn.h>
#endif


#define TTY_PATH		"/dev/tty"
#define STTY_CLOSE      "stty raw -echo -F "
#define STTY_OPEN       "stty -raw echo -F "

#define INPUT_ADMIN_PIN()	system(STTY_CLOSE TTY_PATH);\
printf("\n请输入管理员口令:");\
cin >> pwd;\
system(STTY_OPEN TTY_PATH);\

#define STR(msg)	#msg

static int isLogin = 0;
unsigned char g_pwdHashCipher[128] = { 0 };
unsigned char g_encKey[128] = { 0 };

#define CheckRt(func, rt)\
do{\
	if (rt != 0) {\
		printf("Function [%s] run failed, rt = [%d | %#010X]\n", #func, rt, rt);\
		return rt;\
	}\
	else {\
		printf("Function [%s] run success\n", #func);\
	}\
} while (0)

#define PRINT_BUF(func, buf, len)\
do{\
	printf("Function [%s] -> %s [%s = %d|%#010X]:\n\t%s\n", #func, #buf, #len, len, len, Bin2String(buf, len, true).c_str());\
} while (0)

#define PRINT_STR(func, str)\
do{\
	/*printf("Function [%s] -> %s [strlen(%s) = %d|%#010X]:\n\t%s\n", #func, #str, #str, strlen(str), strlen(str), str);*/\
} while (0)

#define PRINT_NUM(func, len)\
do{\
	/*printf("Function [%s] -> %s = %d|%#010X\n", #func, #len, len, len);*/\
} while (0)

#define PRINT_STRUCT_ITEM(st, item)\
do{\
	/*printf("[%s] -> [%s %d|%#010X]:\n\t%s\n", #st, #item, sizeof(st.item), sizeof(st.item), Utility::Bin2String(st.item, sizeof(st.item), true).c_str()); */\
}while(0);

using namespace std;

char g_pwdKeyManager[32] = { 0 };

static void printHex(const char* title, unsigned char* buf, int len)
{
	int i;
	printf("%s[length = %d]:\n\t", title == NULL ? "" : title, len);
	for (i = 0; i < len; ++i)
		printf("%02X", buf[i]);
	printf("\n");
}

string String2Bin(const string& str)
{
	string bRt = "";
	for (int i = 0; i < (int)str.length() / 2 * 2; i += 2) {
		std::stringstream ss(str.substr(i, 2));
		int tmp = -1;
		ss >> std::hex >> tmp;
		bRt.append(1, (char)(tmp & 0xFF));
	}
	return bRt;
}

int String2Bin(const string& str, unsigned char* bin, unsigned int* size) {
	if (bin == NULL)
		return -1;
	if (size == NULL)
		return str.length() / 2;
	if (*size < str.length() / 2)
		return str.length() / 2;
	string bBin = String2Bin(str);
	*size = bBin.length();
	memcpy(bin, bBin.data(), *size);
	return *size;
}

string Bin2String(const unsigned char* bin, const unsigned int len, bool upper) {
	if (bin == NULL || len == 0)
		return "";
	std::stringstream ss;
	for (int i = 0; i < (int)len; ++i) {
		if (upper)
			ss.setf(std::ios::uppercase);
		ss << std::hex << std::setw(2) << std::setfill('0') << (bin[i] & 0xff);
	}
	return ss.str();
}

string Bin2String(const string & bBin, bool upper)
{
	return Bin2String((unsigned char*)bBin.data(), bBin.length(), upper);
}


int WriteFileData(const char* pPath, const char* pBuf, int dataLen)
{
	if (pPath == NULL)
	{
		return -1;
	}
	FILE* fp = fopen(pPath, "ab");
	if (fp != NULL)
	{
		fwrite(pBuf, 1, dataLen, fp);
		fclose(fp);
	}
	else
	{
		return -1;
	}
	return 0;
}

int ReadFileData(const char* pPath, char* pBuf, int* dataLen)
{
	if (access(pPath, 0) != 0)
		return -1;

	FILE* fp = fopen(pPath, "r");
	if (fp == NULL)
		return -1;

	fseek(fp, 0, SEEK_END);
	int size = ftell(fp);
	rewind(fp);

	*dataLen = size;
	int len = fread(pBuf, 1, size, fp);;

	fclose(fp);

	return 0;
}

int DeviceFormat_InitRestoreFactory(void* hDev, unsigned char* encPk)
{
	char pwd[32] = { 0 };
	system(STTY_CLOSE TTY_PATH); 
	printf("\n请输入管理员口令:"); 
	cin >> pwd;		//默认固定为admin，可在初始化为生产状态时出入新的口令
	system(STTY_OPEN TTY_PATH);

	printf("\n正在准备设备格式化、初始化为出厂状态，请稍等...\n");

	unsigned char pwdHashCipher[128] = { 0 };

	auto rt = TassCtlEncryptPwdHash(hDev, encPk, pwd, pwdHashCipher);
	CheckRt(TassCtlEncryptPwdHash, rt);

	rt = TassCtlLogin(hDev, "admin", pwdHashCipher);
	CheckRt(TassCtlLogin, rt);
	
	rt = TassCtlDeviceFormat(hDev, pwdHashCipher);
	CheckRt(TassCtlDeviceFormat, rt);

	//格式化会清除登录状态，需要重新使用默认口令登录设备管理员
	char adminPwd[32] = { 0 };
	system(STTY_CLOSE TTY_PATH);
	printf("\n格式化成功，出厂设置需要重新输入管理员默认口令登录:");
	cin >> adminPwd;		//默认固定为admin
	system(STTY_OPEN TTY_PATH);

	unsigned char adminPwdHash[128] = { 0 };
	rt = TassCtlEncryptPwdHash(hDev, encPk, adminPwd, adminPwdHash);
	CheckRt(TassCtlEncryptPwdHash, rt);

	rt = TassCtlLogin(hDev, "admin", adminPwdHash);
	CheckRt(TassCtlLogin, rt);

	rt = TassCtlDeviceInitRestoreFactory(hDev, (const unsigned char*)"\x00\x02\x04\x41", 1800);
	CheckRt(TassCtlDeviceInitRestoreFactory, rt);

	rt = TassCtlLogout(hDev);
	CheckRt(TassCtlLogout, rt);

	printf("\n出厂状态设置完成!\n\n");
	return 0;
}

int DeviceFormat_Init(void* hDev, unsigned char* encPk)
{
	char pwd[32] = { 0 };

	printf("\n正在准备设备格式化、初始化为生产状态，请稍等...\n");

	INPUT_ADMIN_PIN();

	unsigned char pwdHashCipher[128] = { 0 };
	auto rt = TassCtlEncryptPwdHash(hDev, encPk, pwd, pwdHashCipher);
	CheckRt(TassCtlEncryptPwdHash, rt);

	rt = TassCtlLogin(hDev, "admin", pwdHashCipher);
	CheckRt(TassCtlLogin, rt);

	rt = TassCtlDeviceFormat(hDev, pwdHashCipher);
	CheckRt(TassCtlDeviceFormat, rt);

	//格式化会清除登录状态，需要重新使用默认口令登录设备管理员
	rt = TassCtlLogin(hDev, "admin", pwdHashCipher);
	CheckRt(TassCtlLogin, rt);

	char newPwd[32] = { 0 };

	//system(STTY_CLOSE TTY_PATH);
	printf("格式化成功，生产状态设置请输入新的管理员口令，之后登录均使用该口令: ");
	cin >> newPwd;
	//system(STTY_OPEN TTY_PATH);

	unsigned char newPwdHash[128] = { 0 };
	rt = TassCtlEncryptPwdHash(hDev, encPk, newPwd, newPwdHash);
	CheckRt(TassCtlEncryptPwdHash, rt);

	unsigned char kekCv[16] = { 0 };
	rt = TassCtlDeviceInit(hDev, newPwdHash, TA_BOOL_FALSE, (const unsigned char*)"\x00\x02\x04\x41", 1800, kekCv);
	CheckRt(TassCtlDeviceInit, rt);

	PRINT_BUF(TassCtlDeviceInit, kekCv, sizeof(kekCv));

	//格式化会清除登录状态，需要用新口令登录设备管理员
	rt = TassCtlLogin(hDev, "admin", newPwdHash);
	CheckRt(TassCtlLogin, rt);

	rt = TassCtlLogout(hDev);
	CheckRt(TassCtlLogout, rt);

	printf("\n生产状态设置完成!\n\n");

	return 0;
}

int DeviceBackup(void* hDev, unsigned char* encPk)
{
	char pwd[32] = { 0 };
	unsigned char pwdHashCipher[128] = { 0 };

	INPUT_ADMIN_PIN();

	printf("\n正在准备备份数据，请稍等...\n");

	auto rt = TassCtlEncryptPwdHash(hDev, encPk, pwd, pwdHashCipher);
	CheckRt(TassCtlEncryptPwdHash, rt);

	rt = TassCtlLogin(hDev, "admin", pwdHashCipher);	//暂用设备管理员登录
	CheckRt(TassCtlLogin, rt);
	
	unsigned char devInfo[1024 * 1024] = { 0 };
	unsigned int devInfoLen = sizeof(devInfo);

	rt = TassCtlBackup(hDev, NULL, pwdHashCipher, devInfo, &devInfoLen);
	CheckRt(TassCtlBackup, rt);

	rt = WriteFileData("devInfoList", (char*)devInfo, devInfoLen);
	CheckRt(WriteFileData, rt);

	rt = TassCtlLogout(hDev);
	CheckRt(TassCtlLogout, rt);

	printf("\n备份数据完成!\n\n");

	return 0;
}

int DeviceRecover(void* hDev, unsigned char* encPk)
{
	char pwd[32] = { 0 };
	unsigned char pwdHashCipher[128] = { 0 };

	INPUT_ADMIN_PIN();

	printf("\n正在复制恢复数据，请稍等...\n");

	auto rt = TassCtlEncryptPwdHash(hDev, encPk, pwd, pwdHashCipher);
	CheckRt(TassCtlEncryptPwdHash, rt);

	rt = TassCtlLogin(hDev, "admin", pwdHashCipher);	//暂用设备管理员登录
	CheckRt(TassCtlLogin, rt);
	
	unsigned char devInfo[1024 * 1024] = { 0 };
	int devInfoLen = sizeof(devInfo);

	rt = ReadFileData("devInfoList", (char*)devInfo, &devInfoLen);
	CheckRt(ReadFileData, rt);

	rt = TassCtlCheckBackupInfoValid(hDev, pwdHashCipher, devInfo, devInfoLen);
	CheckRt(TassCtlCheckBackupInfoValid, rt);

	rt = TassCtlDeviceFormat(hDev, pwdHashCipher);
	CheckRt(TassCtlDeviceFormat, rt);
	
	//格式化会清除登录状态，需要重新使用默认口令登录设备管理员
	char adminPwd[32] = { 0 };
	system(STTY_CLOSE TTY_PATH);
	printf("\n格式化成功，出厂设置需要重新输入管理员默认口令登录:");
	cin >> adminPwd;		//默认固定为admin
	system(STTY_OPEN TTY_PATH);

	unsigned char adminPwdHash[128] = { 0 };
	rt = TassCtlEncryptPwdHash(hDev, encPk, adminPwd, adminPwdHash);
	CheckRt(TassCtlEncryptPwdHash, rt);

	rt = TassCtlLogin(hDev, "admin", adminPwdHash);
	CheckRt(TassCtlLogin, rt);

	rt = TassCtlRecover(hDev, adminPwdHash, devInfo, devInfoLen);
	CheckRt(TassCtlRecover, rt);

	rt = TassCtlLogin(hDev, "admin", adminPwdHash);
	CheckRt(TassCtlLogin, rt);

	rt = TassCtlLogout(hDev);
	CheckRt(TassCtlLogout, rt);

	printf("\n恢复数据完成!\n\n");

	return 0;
}

int ScanfKey(void* hDev)
{
	int alg = 0;
	unsigned char info[256] = { 0 };
	unsigned int infoLen = sizeof(info);

	TassKeyInfo infos[64];
	int len = sizeof(TassKeyInfo);

	while (1)
	{
		printf("请输入要查询的密钥类型，0-SM4, 1-SM1，2-SM2，3-ECC_SECP_256R1, 4-RSA, 5-AES, 6-DES，7-SM7, 8-ECC_SECP_256K1, 9-HMAC: ");
		cin >> alg;
		if (alg == 0 || alg == 1 || alg == 2 || alg == 3 || alg == 4 || alg == 5 || alg == 6 || alg == 7 || alg == 8 || alg == 9)
			break;
		else
			printf("该类型不支持!\n");
	}

	int rt = TassCtlListKey(hDev, (TassAlg)alg, infos, &len);
	CheckRt(TassCtlListKey, rt);
	printf("密钥个数 = %d\n", len / sizeof(TassKeyInfo));
	for(int i = 0; i < len / sizeof(TassKeyInfo); i++)
		printf("index = %d, pk_kcv: %s\nsk_key: %s\n", infos[i].index, Bin2String(infos[i].pk_kcv, infos[i].pk_kcvLen, true).data(), Bin2String(infos[i].sk_key, infos[i].sk_keyLen, true).data());
	printf("\n");
	return 0;
}

int DeleteKey(void* hDev)
{
	unsigned int index = 0, alg = 0;

	while (1)
	{
		printf("请输入要删除的密钥类型，0-SM4, 1-SM1，2-SM2，3-ECC_SECP_256R1, 4-RSA, 5-AES, 6-DES，7-SM7, 8-ECC_SECP_256K1, 9-HMAC: ");
		cin >> alg;
		if (alg == 0 || alg == 1 || alg == 2 || alg == 3 || alg == 4 || alg == 5 || alg == 6 || alg == 7 || alg == 8 || alg == 9)
			break;
		else
			printf("该类型不支持!\n");
	}

	printf("请输入要删除的密钥索引号：");
	cin >> index;

	int rt = TassCtlDestroyKey(hDev, (TassAlg)alg, index);
	CheckRt(TassCtlDestroyKey, rt);

	printf("\n删除密钥成功!\n\n");

	return 0;
}

int GenerateKey(void* hDev)
{
	int alg, index = 0, keyBits;

	while (1)
	{
		printf("请输入要生成的密钥类型，0-SM4, 1-SM1，2-SM2，3-ECC_SECP_256R1, 4-RSA, 5-AES, 6-DES，7-SM7, 8-ECC_SECP_256K1, 9-HMAC: ");
		cin >> alg;
		if (alg == 0 || alg == 1 || alg == 2 || alg == 3 || alg == 4 || alg == 5 || alg == 6 || alg == 7 || alg == 8 || alg == 9)
			break;
		else
			printf("该类型不支持!\n");
	}

	if ((TassAlg)alg == TA_ALG_RSA)
		keyBits = 2048;
	if ((TassAlg)alg == TA_ALG_SM2 || (TassAlg)alg == TA_ALG_ECC_SECP_256R1 || (TassAlg)alg == TA_ALG_ECC_SECP_256K1)
		keyBits = 256;
	if ((TassAlg)alg == TA_ALG_SM1 || (TassAlg)alg == TA_ALG_AES || (TassAlg)alg == TA_ALG_DES || (TassAlg)alg == TA_ALG_SM4 || (TassAlg)alg == TA_ALG_SM7)
		keyBits = 128;
	if ((TassAlg)alg == TA_ALG_HMAC)
	{
		while (1)
		{
			printf("请输入要生成的HMAC密钥的模长 128、256、384、512：");
			cin >> keyBits;
			if (keyBits == 128 || keyBits == 256 || keyBits == 384 || keyBits == 512)
				break;
			else
				printf("该模长不支持!\n");
		}
	}
		
	printf("请输入要存储的密钥索引号：");
	cin >> index;

	unsigned char sk_key[1024] = { 0 };
	unsigned int sk_keyLen = sizeof(sk_key);
	unsigned char pk_kcv[1024] = { 0 };
	unsigned int pk_kcvLen = sizeof(pk_kcv);
	int rt = TassCtlGenerateKey(hDev,
		(TassAlg)alg, 
		keyBits,
		index,
		NULL, NULL,
		sk_key, &sk_keyLen,
		pk_kcv, &pk_kcvLen);
	CheckRt(TassCtlGenerateKey, rt);

	printf("sk_keyLen = %d, sk_key = %s\n", sk_keyLen, Bin2String(sk_key, sk_keyLen, true).data());
	printf("pk_kcvLen = %d, pk_kcv = %s\n", pk_kcvLen, Bin2String(pk_kcv, pk_kcvLen, true).data());

	printf("\n生成密钥成功!\n\n");
}

int Device_KeyManager(void* hDev)
{
	while (true) {
		int idx = 0;
		printf("[%d] 查询密钥\n", ++idx);
		printf("[%d] 删除密钥\n", ++idx);
		printf("[%d] 生成密钥\n", ++idx);
		printf("[0] 退出\n");

		cin >> idx;
		switch (idx) {
		case 1: ScanfKey(hDev); break;
		case 2: DeleteKey(hDev); break;
		case 3: GenerateKey(hDev); break;
		case 0: {
			return 0;
		};
		default: {
			printf("输入错误！");
			continue;
		};
		}
	}

	return 0;
}

int Device_ImporPlaintKey(void* hDev)
{
	int rt = 0;

	//string sm2Pk = "AECF38A316B43733881971C685CA33B3A1E69A27FCEB13A01D593373DC5D032ECFCC4601C815D653ABC2012EF30E1E6D8BC9D00E0B90634E0630C0D5923557D9";
	//string sm2Sk = "FC0249EF1FBDB1B31CAE486AE1E54F7BF21B23A9CA87DED96EDEBA67BB1DC75D";
	string sm2Pk;
	string sm2Sk;
	printf("请输入SM2的公钥：");
	cin >> sm2Pk;
	printf("请输入SM2的私钥：");
	cin >> sm2Sk;

	string sm2Pub = String2Bin(sm2Pk);
	string sm2Pri = String2Bin(sm2Sk);

	int indexSm2 = 0;
	printf("SM2\n");
	printf("请输入导入SM2的密钥索引号：");
	cin >> indexSm2;
	rt = TassCtlImportPlainKey(hDev,
		TA_ALG_SM2,
		indexSm2,
		NULL,
		NULL,
		(unsigned char*)sm2Pri.data(), sm2Pri.size(),
		(unsigned char*)sm2Pub.data(), sm2Pub.size());
	CheckRt(TassCtlImportPlainKey, rt);

	printf("SM4\n");
	/*string sm4 = "RBF9B62F18E83907304870A3433493C81";
	string sm4Kcv = "01F0E5EA25028A88";*/

	/*unsigned char sk_key[128] = { 0 };
	unsigned int sk_keyLen = sizeof(sk_key);
	unsigned char pk_kcv[128] = { 0 };
	unsigned int pk_kcvLen = sizeof(pk_kcv);

	rt = TassCtlGenerateKey(hDev,
		TA_ALG_SM4,
		128,
		1, 
		NULL, NULL,
		sk_key, &sk_keyLen,
		pk_kcv, &pk_kcvLen);
	CheckRt(TassCtlGenerateKey, rt);*/

	string sm4;
	printf("请输入SM4的密钥：");
	cin >> sm4;
	string sm4Key = String2Bin(sm4);
	/*string kcv = String2Bin(sm4Kcv);*/

	int indexSm4 = 0;
	printf("请输入导入SM4的密钥索引号：");
	cin >> indexSm4;

	rt = TassCtlImportPlainKey(hDev,
		TA_ALG_SM4,
		indexSm4,
		NULL,
		NULL,
		(unsigned char*)sm4Key.data(), sm4Key.size(),
		(unsigned char*)"", 0);
	CheckRt(TassCtlImportPlainKey, rt);

	return 0;
}


int Device_FormatOperation(void *hDev, unsigned char* encPk)
{
	int rt = 0;
	while (true) {
		int idx = 0;
		printf("[%d] 设备格式化、初始化为出厂状态\n", ++idx);
		printf("[%d] 设备格式化、初始化为生产状态\n", ++idx);
		printf("[0] 退出\n");

		cin >> idx;
		switch (idx) {
		case 1: DeviceFormat_InitRestoreFactory(hDev, encPk); break;
		case 2: DeviceFormat_Init(hDev, encPk); break;
		case 0: {
			return 0;
		};
		default: {
			printf("输入错误！");
			continue;
		};
		}
	}
}

int Device_BackupRecover(void* hDev, unsigned char* encPk)
{
	int rt = 0;
	while (true) {
		int idx = 0;
		printf("[%d] 备份设备信息\n", ++idx);
		printf("[%d] 恢复设备信息\n", ++idx);
		printf("[0] 退出\n");

		cin >> idx;
		switch (idx) {
		case 1: DeviceBackup(hDev, encPk); break;
		case 2: DeviceRecover(hDev, encPk); break;
		case 0: {
			return 0;
		};
		default: {
			printf("输入错误！");
			continue;
		};
		}
	}
}

int Device_ChangePrikeyPwd(void* hDev)
{
	int rt = 0;
	unsigned int alg = 0;
	while (1)
	{
		printf("请输入修改私钥权限的密钥类型：2-SM2，3-ECC_SECP_256R1, 4-RSA, 8-ECC_SECP_256K1: ");
		cin >> alg;
		if (alg == 2 || alg == 3 || alg == 4 || alg == 8)
			break;
		else
			printf("该类型不支持！\n");
	}

	unsigned int index = 0;
	printf("请输入要修改私钥权限口令的索引：");
	cin >> index;

	string privateKeyPwd;
	printf("请输入新的私钥权限口令：");
	cin >> privateKeyPwd;

	rt = TassCtlChangePrivateKeyAccessRight(hDev,
		(TassAlg)alg, index,
		(unsigned char*)privateKeyPwd.data(), privateKeyPwd.size());
	CheckRt(TassCtlChangePrivateKeyAccessRight, rt);

	printf("\n修改私钥权限口令成功!\n\n");
}

int Device_LoginAndGetEncKey(void** hDev)
{
	int rt = 0;
	unsigned int idLen = 0;

	rt = TassCtlScanDevice(nullptr, &idLen);
	CheckRt(TassCtlScanDevice, rt);

	char ids[256] = { 0 };
	TassCtlScanDevice(ids, &idLen);

	int i = 0;
	auto* p = ids;
	while (strlen(p) != 0) {
		//printf("Device ID[%d]: %s\n", ++i, p);
		p += strlen(p) + 1;
	}

	void* hDevTmp = nullptr;
	rt = TassCtlOpenDevice(ids, &hDevTmp);
	CheckRt(TassCtlOpenDevice, rt);
	*hDev = hDevTmp;

	unsigned int infoLen = 0;
	rt = TassCtlListAdmin(hDevTmp, NULL, &infoLen);
	CheckRt(TassCtlListAdmin, rt);

	TassAdminInfo info[5];
	TassCtlListAdmin(hDevTmp, info, &infoLen);
	for (int i = 0; i < infoLen / sizeof(TassAdminInfo); ++i) {
		//PRINT_STRUCT_ITEM(info[i], name);
		//PRINT_STR(TassCtlListAdmin, info[i].name);
	}

	rt = TassCtlRequestPwdHashEncPublicKey(hDevTmp, g_encKey);
	CheckRt(TassCtlRequestPwdHashEncPublicKey, rt);
#if defined(_WIN32) || defined(_WIN64)
	Sleep(1000);
#else
	sleep(1);
#endif
	//PRINT_BUF(TassCtlRequestPwdHashEncPublicKey, g_encKey, 64);

	char pwd[32] = { 0 };

	//INPUT_ADMIN_PIN();
	system(STTY_CLOSE TTY_PATH);
	printf("\n请输入管理员口令:");
	cin >> pwd;		//默认固定为admin，可在初始化为生产状态时出入新的口令
	system(STTY_OPEN TTY_PATH);

	rt = TassCtlEncryptPwdHash(hDevTmp, g_encKey, pwd, g_pwdHashCipher);
	CheckRt(TassCtlEncryptPwdHash, rt);

	rt = TassCtlLogin(hDevTmp, "admin", g_pwdHashCipher);
	if (rt == 0)
	{
		printf("TassCtlLogin run success!\n");
		isLogin = 1;
		return rt;
	}
	else
	{
		printf("TassCtlLogin run failed, rt = [%d | %#010X]\n", rt, rt);
		isLogin = 0;
		return rt;
	}
}

int OpenDeviceAndGetEncKey(void** hDev, unsigned char* encKey)
{
	int rt = 0;
	unsigned int idLen = 0;
	rt = TassCtlScanDevice(nullptr, &idLen);
	CheckRt(TassCtlScanDevice, rt);

	char ids[256] = { 0 };
	TassCtlScanDevice(ids, &idLen);

	int i = 0;
	auto* p = ids;
	while (strlen(p) != 0) {
		//printf("Device ID[%d]: %s\n", ++i, p);
		p += strlen(p) + 1;
	}

	void* hDevTmp = nullptr;
	rt = TassCtlOpenDevice(ids, &hDevTmp);
	CheckRt(TassCtlOpenDevice, rt);
	*hDev = hDevTmp;

	unsigned int infoLen = 0;
	rt = TassCtlListAdmin(hDevTmp, NULL, &infoLen);
	CheckRt(TassCtlListAdmin, rt);

	TassAdminInfo info[5];
	TassCtlListAdmin(hDevTmp, info, &infoLen);
	for (int i = 0; i < infoLen / sizeof(TassAdminInfo); ++i) {
		//PRINT_STRUCT_ITEM(info[i], name);
		//PRINT_STR(TassCtlListAdmin, info[i].name);
	}

	rt = TassCtlRequestPwdHashEncPublicKey(hDevTmp, encKey);
	CheckRt(TassCtlRequestPwdHashEncPublicKey, rt);
#if defined(_WIN32) || defined(_WIN64)
	Sleep(1000);
#else
	sleep(1);
#endif
	//PRINT_BUF(TassCtlRequestPwdHashEncPublicKey, encKey, sizeof(encKey));
}

int ImportAsymKey(void* hDev)
{
	int rt = 0;

	string sm2PriKey;
	printf("请输入SM2的保护私钥: ");
	cin >> sm2PriKey;
	string sm2Sk = String2Bin(sm2PriKey);

	string symmKeyCipher;
	printf("请输入随机对称密钥: ");
	cin >> symmKeyCipher;
	string symmKey = String2Bin(symmKeyCipher);

	string pubKey;
	printf("请输入要导入的公钥: ");
	cin >> pubKey;
	string pk = String2Bin(pubKey);

	string priKey;
	printf("请输入要导入的私钥: ");
	cin >> priKey;
	string sk = String2Bin(priKey);

	int importedKeyAlg = 0;
	while (1)
	{
		printf("请输入要导入密钥的类型：2-SM2，3-ECC_SECP_256R1, 4-RSA, 8-ECC_SECP_256K1: ");
		cin >> importedKeyAlg;
		if (importedKeyAlg == 2 || importedKeyAlg == 3 || importedKeyAlg == 4 || importedKeyAlg == 8)
			break;
		else
			printf("该类型不支持！\n");
	}

	unsigned int importedKeyIndex = 0;
	printf("请输入要导入密钥的索引：");
	cin >> importedKeyIndex;

	rt = TassCtlImportKey(hDev,
		(unsigned char*)sm2Sk.data(),
		(TassAlg)importedKeyAlg,
		importedKeyIndex,
		(unsigned char*)"",
		0,
		(unsigned char*)symmKey.data(),
		symmKey.size(),
		(unsigned char*)pk.data(),
		pk.size(),
		(unsigned char*)sk.data(),
		sk.size());
	CheckRt(TassCtlImportKey, rt);

	printf("导入非对称密钥成功！\n");
}

int ExportAsymKey(void* hDev)
{
	int rt = 0;
	unsigned char symmKeyCipher[1024] = { 0 };
	unsigned int symmKeyCipherLen = sizeof(symmKeyCipher);
	unsigned char exportedPk[1024] = { 0 };
	unsigned int exportedPkLen = sizeof(exportedPk);
	unsigned char exportedKeyCipherByPk[1024] = { 0 };
	unsigned int exportedKeyCipherByPkLen = sizeof(exportedKeyCipherByPk);

	string sm2PubKey;
	printf("请输入SM2的保护公钥: ");
	cin >> sm2PubKey;
	string sm2Pk = String2Bin(sm2PubKey);

	int exportedKeyAlg = 0;
	while (1)
	{
		printf("请输入导出密钥的类型：2-SM2，3-ECC_SECP_256R1, 4-RSA, 8-ECC_SECP_256K1: ");
		cin >> exportedKeyAlg;
		if (exportedKeyAlg == 2 || exportedKeyAlg == 3 || exportedKeyAlg == 4 || exportedKeyAlg == 8)
			break;
		else
			printf("该类型不支持！\n");
	}

	unsigned int exportedKeyIndex = 0;
	printf("请输入要导出密钥的索引：");
	cin >> exportedKeyIndex;

	rt = TassCtlExportKey(hDev,
		(unsigned char*)sm2Pk.data(),
		(TassAlg)exportedKeyAlg,
		exportedKeyIndex,
		g_pwdHashCipher,
		symmKeyCipher,
		&symmKeyCipherLen,
		exportedPk,
		&exportedPkLen,
		exportedKeyCipherByPk,
		&exportedKeyCipherByPkLen);
	CheckRt(TassCtlExportKey, rt);

	printf("导出非对称密钥成功！\n");
	printf("随机对称密钥：symmKeyCipherLen = %d, symmKeyCipher: %s\n\n", symmKeyCipherLen, Bin2String(symmKeyCipher, symmKeyCipherLen, true).data());
	printf("导出的公钥：exportedPkLen = %d, exportedPk: %s\n", exportedPkLen, Bin2String(exportedPk, exportedPkLen, true).data());
	printf("导出的私钥：exportedKeyCipherByPk = %d, exportedKeyCipherByPkLen: %s\n", exportedKeyCipherByPkLen, Bin2String(exportedKeyCipherByPk, exportedKeyCipherByPkLen, true).data());
}

int Device_ImportAndExportAsymKey(void* hDev)
{
	while (true) {
		int idx = 0;
		printf("[%d] 导出非对称密钥\n", ++idx);
		printf("[%d] 导入非对称密钥\n", ++idx);
		printf("[0] 退出\n");

		cin >> idx;
		switch (idx) {
		case 1: ExportAsymKey(hDev); break;
		case 2: ImportAsymKey(hDev); break;
		case 0: {
			return 0;
		};
		default: {
			printf("输入错误！");
			continue;
		};
		}
	}
}

int DevManager()
{
	void* hDev = nullptr;
	unsigned char encPk[128] = { 0 };

	auto rt = OpenDeviceAndGetEncKey(&hDev, encPk);
	CheckRt(OpenDeviceAndGetEncKey, rt);

	while (true) {
		int idx = 0;
		printf("[%d] 设备格式化操作\n", ++idx);
		printf("[%d] 备份和恢复设备信息\n", ++idx);
		printf("[0] 退出\n");

		cin >> idx;
		switch (idx) {
		case 1: Device_FormatOperation(hDev, encPk); break;
		case 2: Device_BackupRecover(hDev, encPk); break;
		case 0: {
			TassCtlLogout(hDev);
			TassCtlCloseDevice(hDev);
			return 0;
		};
		default: {
			printf("输入错误！");
			continue;
		};
		}
	}
	return 0;
}

int KeyManager()
{
	void* hDev = nullptr;
	auto rt = Device_LoginAndGetEncKey(&hDev);
	CheckRt(Device_LoginAndGetEncKey, rt);

	while (true) {
		int idx = 0;
		printf("[%d] 应用密钥管理（增加、查询、删除）\n", ++idx);
		printf("[%d] 导入外部明文密钥到设备\n", ++idx);
		printf("[%d] 修改私钥使用权限口令\n", ++idx);
		printf("[%d] 导入导出非对称密钥\n", ++idx);
		printf("[0] 退出\n");

		cin >> idx;
		switch (idx) {
		case 1: Device_KeyManager(hDev); break;
		case 2: Device_ImporPlaintKey(hDev); break;
		case 3: Device_ChangePrikeyPwd(hDev); break;
		case 4: Device_ImportAndExportAsymKey(hDev); break;
		case 0: {
			TassCtlLogout(hDev);
			TassCtlCloseDevice(hDev);
			return 0;
		};
		default: {
			printf("输入错误！");
			continue;
		};
		}
	}
	return 0;
}

int main()
{
	while (true) {
		int idx = 0;
		printf("[%d] 密钥管理\n", ++idx);
		printf("[%d] 设备管理\n", ++idx);
		printf("[0] 退出\n");

		cin >> idx;
		switch (idx) {
		case 1: KeyManager(); break;
		case 2: DevManager(); break;
		case 0: {
			return 0;
		};
		default: {
			printf("输入错误！");
			continue;
		};
		}
	}

	return 0;
}