关于调用深思API读写加密狗

工作中需要完成一些加密狗的简单功能,现稍作记录。具体详见深思API帮助工具及帮助文档。

1.加密狗登录与登出
1)登录

slm_login函数详细说明:
1.会自动查找跨锁查找许可句柄。
2.在runtime库里面分配管理内存与进程线程信息。
3.对与调用者需要定期监控会话进程,如果进程死锁或者崩溃,自己释放对应的内存和其它资源。
4.LM库属于客户定制自动编译,包含RSA 公钥、认证设备ID、开发商编号等一切认证手段。
5.LM后续操作必须都要login之后才能有权限操作 比如读写、加解密等操作。

bool login_dog()
{
	SS_UINT32 status = 0;
	SS_BYTE tmp_buf[1024] = { 0 };
	SS_UINT32 buf_len = 0;
	ST_INIT_PARAM init_param = { 0 };//初始化参数
	ST_LOGIN_PARAM login_param = { 0 };//登录相关参数
	// psd是必传参数,每个开发者私有,不可泄露,请从深思云开发者中心获取
	SS_BYTE psd[16] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };

	init_param.version = SLM_CALLBACK_VERSION02;
	init_param.pfn = NULL;
	init_param.flag = 0;
	memcpy(init_param.password, psd, sizeof(psd));

	/*slm_init函数是深思Runtime API的初始化函数,在使用其他深思Runtime API之前,
	必须要先调用此函数, 初始化函数主要是对Runtime环境的初始化,并且启动反调试机制。*/
	status = slm_init(&init_param);
	if (status != SS_OK)
	{
		return false;
	}

	login_param.license_id = LICENSEID;
	login_param.size = sizeof(ST_LOGIN_PARAM);
	login_param.login_mode = SLM_LOGIN_MODE_LOCAL;
	login_param.timeout = 600;

	status = slm_login(&login_param, STRUCT, &g_slm_handle, NULL);
	if (status != SS_OK)
	{
		return false;
	}
	return true;
}
2)登出

不再使用许可时,需要调用slm_logout退出登录许可,以免其占用Runtime库中的内存和资源。
例如,由于Runtime 库只支持最多256个登录句柄,若只登录许可而不登出许可,一旦超出256个登录点将占满所有Runtime库中的资源,导致后续的登录失败

bool logout_dog()
{
	if (g_slm_handle == 0)
	{
		return true;
	}
	SS_UINT32 status = 0;
	status = slm_logout(g_slm_handle);	//currenthandle当前许可句柄值,通过login的第三个参数得到
	if (status != SS_OK)
	{
		return false;
	}
	return true;
}
2.加密狗信息读取与写入
1)读取

这里一开始用了slm_mem_readslm_mem_write,但出现很诡异的状况,参照参考文档去编写后仍无法正常读写,只有在写完后马上读才可以读到。后查阅文档,上述接口读写的是SenseShield服务内存托管内存(SS的托管内存

文档详述:
SS的托管内存原理是 APP利用有效的许可作为凭证,在SS模块内数据加密且数据校验,其内存二进制数据没有明文, 并且无法非法修改。黑客极难查看与篡改使用。
用户可以把自己APP的一些敏感数据保存到SS的托管内存,比如帐号口令,SQL数据库的帐号与密码,涉及到操作权限的临时数据放到SS内存托管里面。 另外一方面APP跟SS耦合度极大的提高,防止黑客脱离SS调试与运行。

内存托管的好处:
1.敏感数据内存不泄密、无法篡改。
2.可以跨线程安全交互数据。
3.APP软件、许可、SS三者强耦合,软件防止被破解能力极高。(黑客需要手工剥离和重建才能使软件)

所以读写出错貌似是一些权限之类的问题,需要在其他区域进行读写。

后改用slm_user_data_getsizeslm_user_data_readslm_user_data_write,可正常读取写入二进制信息。
在读写前需要通过slm_user_data_getsize先获取许可的用户数据区大小。

/** 许可数据区类型枚举  */ 
typedef enum _LIC_USER_DATA_TYPE {
    /** 只读区 */
    ROM = 0,     
    /** 读写区 */
    RAW = 1,
    /** 公开区 */
    PUB = 2,
} LIC_USER_DATA_TYPE;

//存储读取信息的结构体
struct TimeLock 
{
	int version;///< 版本号,便于以后识别使用
	int64_t dogId;///< 加密狗Id,最多支持32位
	bool isUnLock;///< 是否完全解锁 =true:完全解锁  =false:时钟锁定
	int time[6];///< 年月日时分秒
	char reserve[512];///< 备用
};

bool decodePaFile(QString & outTime, QString & outShellNum)
{
	TimeLock m_TimeLock;//存储读取信息的结构体
	memset(&m_TimeLock, 0, sizeof(TimeLock));
	
	//读锁
	login_dog();

	SS_UINT32 status = 0;
	SS_UINT32 offerset = 0;
	SS_UINT32 inputsize = 0;
	SS_BYTE tmp_buf[18432] = { 0 };//1024*18
	SS_UINT32 buf_len = 18432;
	SS_UINT32 length = 0;
	status = slm_user_data_getsize(g_slm_handle, RAW, &length);	//currenthandle当前许可句柄值,通过login的第三个参数得到
		 
	status = slm_user_data_read(g_slm_handle, RAW, tmp_buf, offerset, 560);//读取
	if (status != SS_OK)
	{
		return false;
	}

	memcpy(&m_TimeLock, tmp_buf, 560);
	logout_dog();	
	return true;
}
2)写入

写入的流程和读取类似,下面例子是读取加密狗授权文件(.bin),并将其写入加密狗中。

	bool LoadBinFile(QString strPath)
	{
		if (strPath == "")
		{
			return false;
		}
		//写入锁
		QFile file(strPath);

		if (!file.open(QIODevice::ReadOnly))
		{
			return false;
		}

		QByteArray text = file.readAll();

		if (text.size() != sizeof(TimeLock))
		{
			return false;
		}
		else
		{
			login_dog();
			SS_UINT32 status = 0;
			SS_UINT32 offerset = 0;
			SS_UINT32 inputsize = 0;
			SS_UINT32 length = 0;
			status = slm_user_data_getsize(g_slm_handle, RAW, &length);	//currenthandle当前许可句柄值,通过login的第三个参数得到
			if (status == SS_OK && length != 0)
			{
				std::unique_ptr<SS_BYTE[]> temp_buf(new SS_BYTE[560]);
				memcpy(temp_buf.get(), text.data(), 560);
				status = slm_user_data_write(g_slm_handle, temp_buf.get(), offerset, 560);
				if (status != SS_OK)
				{
					return false;
				}
			}
			logout_dog();
		}
		return true;
	}
3.获取设备信息

slm_enum_device,此接口可以枚举到本地锁的设备信息,包括锁的锁号,锁的时间等。
下面例子为获取设备锁锁号和锁内时间,这里的锁内时间是指锁内时钟的时间,要与锁设定的到期时间区分开来。

bool getDeviceInfo(QString &outRetTime, QString &outRetShellNum)
{
	SS_UINT32 status = 0;
	char* result = nullptr;

	status = slm_enum_device(&result);
	if (status == SS_OK && result != 0)
	{
		//这里拆解信息
		QString strInfo(result);
		slm_free(result);

		//获取时间,时间存储的形式为秒(s)数
		int nTimeIndex = strInfo.indexOf("clock");
		if (-1 != nTimeIndex)
		{
		//这里简单进行字符串处理,获取时间
			int nEndIndex = strInfo.indexOf(",", nTimeIndex);
			outRetTime = strInfo.mid(nTimeIndex + 7, nEndIndex - nTimeIndex - 7);
			outRetTime = outRetTime.trimmed();
		}

		//获取锁号
		int nShellIndex = strInfo.indexOf("shell_num");
		if (-1 != nShellIndex)
		{
			int nEndIndex = strInfo.indexOf(",", nShellIndex);

			//shell_num":
			outRetShellNum = strInfo.mid(nShellIndex + 11, nEndIndex - nShellIndex - 11);
			outRetShellNum = outRetShellNum.replace("\"", "");
			outRetShellNum = outRetShellNum.trimmed();
		}

		return true;
	}

	return false;
}

全部设备信息,根据这个可以截获需要的信息。
关于调用深思API读写加密狗

上一篇:[BUUCTF]Reverse——findKey


下一篇:1.3寸IIC OLED SSD1106控制的oled显示问题解决方案