一、加密狗原理简介
加密狗是为软件开发商提供的一种智能型的软件保护工具,它包含一个安装在计算机并行口或USB口上的硬件,及一套适用于各种语言的接口软件和工具软件。加密狗基于硬件保护技术,其目的是通过对软件与数据的保护防止知识产权被非法使用。
加密狗是外形酷似U盘的一种硬件设备,正名加密锁,后来发展成如今的一个软件保护的通俗行业名词,加密狗是一种插在计算机并行口上的软硬件结合的加密产品(新型加密狗也有USB口的)。一般都有几十或几百字节的非易失性存储空间可供读写,现在较新的狗内部还包含了单片机。软件开发者可以通过接口函数和软件狗进行数据交换(即对软件狗进行读写),来检查软件狗是否插在接口上;或者直接用软件狗附带的工具加密自己的EXE文件(俗称"包壳")。这样,软件开发者可以在软件中设置多处软件锁,利用软件狗做为钥匙来打开这些锁;如果没插软件狗或软件狗不对应,软件将不能正常执行。
加密狗是通过在软件执行过程中和加密狗交换数据来实现加密的。加密狗内置单片机电路(也称CPU),使得加密狗具有判断、分析的处理能力,增强了主动的反解密能力。这种加密产品称它为“智能型”加密狗。加密狗内置的单片机里包含有专用于加密的算法软件,该软件被写入单片机后,就不能再被读出。这样,就保证了加密狗硬件不能被复制。同时,加密算法是不可预知、不可逆的。加密算法可以把一个数字或字符变换成一个整数,如DogConvert(1)=12345、DogConvert(A)=43565。
(以上内容来源于网络)
二、第一次使用ROCKEY-ARM
一定要先认真阅读《ROCKEY-ARM产品介绍》和《ROCKEY-ARM用户工具使用手册》。
- 打开RyRAMNavigation.exe
![](https://i-blog.csdnimg.cn/blog_migrate/cc434c70179ece7975e0c593c301e99e.png)
界面中有三个标签页:“ROCKEY-ARM 标准锁”、“ROCKEY-ARM 时钟锁”和“ROCKEY-ARM U 盘锁”,根据使用的锁选择相应的标签页,点击“更多了解······”。
![](https://i-blog.csdnimg.cn/blog_migrate/ec04281237a01c72ea2ada933665adc9.png)
选择“用户工具”标签页,里面介绍了集中常用工具的功能,初次使用点击“集成编辑工具”打开即可。
![](https://i-blog.csdnimg.cn/blog_migrate/851cee5b2734254e4a69df0a00b774b9.png)
此时是一把空锁,所有信息都是出厂时的默认值,直接点击“登录”即可。
- 初始化锁
初始化锁的目的是把空锁变成唯一化的子锁。关于空锁、子锁、母锁之间的关系:
空锁 | 飞天出厂的锁,所有信息都是缺省值,特征是产品ID为FFFFFFFF |
子锁 | 开发商通过种子码唯一化后的锁,特征是产品ID不再是FFFFFFFF |
母锁 | 在子锁的基础上写入了母锁数据,方便开发商的安全生产,特征是硬件信息中的母锁标志位为1 |
以开发商(管理员)权限使用缺省信息登录后,在“基本功能”标签页生成随机数作为种子码,点击“导出”,保存为一个bin文件。
![](https://i-blog.csdnimg.cn/blog_migrate/3ce0949365fcc8a8079baf0a6fd6eaa1.png)
点击进入“密码安全”标签页,导入刚才保存的种子码文件(bin文件),点击“生成”完成锁的初始化。
![](https://i-blog.csdnimg.cn/blog_migrate/9f7d77a01488141f746f54c9fe8caf43.png)
务必牢记产品ID和管理员密码,妥善保管好种子码!如果嫌生成的密码不好记,重新登录后可以返回当前页修改密码,注意密码必须是16位。
三、软件加密
加密狗初始化以后就可以进行基本的软件加密操作了。ROCKEY-ARM给我们提供了三种加密文件:数据文件、密钥文件和可执行文件,用来对软件进行加密。
数据文件 | 数据文件可以和上层软件进行关联,即用API进行访问,数据文件也可以被锁内的可执行文件读写 |
密钥文件 | 理解密钥文件,可以参考这两篇文章: 公钥,私钥和数字签名这样最好理解 一妻多夫制的钥匙 |
可执行文件 | 所谓可执行文件,就是由锁内的处理器芯片进行运算的程序文件。用户可以将程序中的核心代码编写成ARM可执行程序下载到锁内,在程序运行过程中,调用提供的API接口,为可执行文件传入运行参数,通过可执行文件在加密锁内部运行后,将结果返回给外部的用用程序,是被保护的软件与锁进行交互,从而达到软件保护的目的。 |
下图是各种文件在ROCKEY-ARM中的访问权限表:
![](https://i-blog.csdnimg.cn/blog_migrate/c3d47ac09372b3488a9fe0af6e529d79.png)
接下来,我们使用数据文件+密钥文件的方式来对软件进行加密,基本的思路是:先生成一对密钥,然后产生一组随机数作为原始数据,再用公钥对随机数进行加密,最后将加密的数据文件保存到锁内;程序通过API先读取锁内加密后的数据文件,然后用锁内的私钥进行解密,如果解密后的数据与原始数据完全相同,则获得软件使用权限。以上所有文件的操作权限只归开发商所有,原始数据也可以写到锁内。基本操作步骤如下:
- 生成密钥对
首先进入“文件管理”菜单页,选择文件类型为“RSA私钥文件”(选择ECCSM2私钥文件亦可),点击创建,弹出如下窗口:
![](https://i-blog.csdnimg.cn/blog_migrate/399f3814647aacbae42b449155de83dd.png)
填入文件ID(注意:文件ID必须是0000~FFFF之间的数,且所有文件类型的文件ID不能使用0000,3F00和FFFF),点击“创建”即可。然后选中刚刚生成的私钥文件,再设置好公钥和私钥的保存路径,点击“产生”,即可保存一对密钥文件。
![](https://i-blog.csdnimg.cn/blog_migrate/1a33442ed8e2b06b6109a35823bfaa5a.png)
- 产生随机数并加密
产生随机数的方法与上面初始化锁时的操作相同,然后进入“加密解密”菜单页,导入保存的随机数,选择“RSA公钥加密”,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/1fe741987a1544e77194cb9fc2a8d1e1.png)
点击“执行”,在弹出的窗口中选择刚才保存的公钥文件打开,即可产生输出结果,最后将结果导出保存即可。
- 写入加密数据文件
回到“文件管理”页,选择“数据文件”,点击“创建”,弹出如下窗口:
![](https://i-blog.csdnimg.cn/blog_migrate/33a6eb9da95ce1a468bcbe27c2d95384.png)
首先设置文件的读写权限为“管理员”,输入文件ID,然后去掉“空文件”处的√,点击“导入”,打开刚才公钥加密后的数据文件,点击“创建”即可,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/d06ec9d78663a399b754c226ed77788c.png)
这样,文件类型为“数据文件”的文件列表中就会有一个ID为“1111”的文件,而且我们还可以对这个文件进行删除和读写操作。
现在,加密锁内已经有了我们的私钥文件和用公钥加密过的数据文件,接下来只需要在我们自己的程序中利用API进行相应的验证操作就可以了。
bool Dongle()
{
DWORD dwRet = 0;
int nCount = 0;
char AdminPin[] = "FFFFFFFFFFFFFFFF";//默认开发商PIN码,使用时请修改为你自己的PIN码
int nRemainCount = 0;
DONGLE_HANDLE hDongle = NULL;
WORD wPriID = 0x1111;
WORD wFileID = 0x1111;
BYTE buffer[128];
BYTE tmpbuf[128];
int nInDataLen = 0;
int nOutDataLen = 0;
//枚举锁
dwRet = Dongle_Enum(NULL, &nCount);
if (dwRet != DONGLE_SUCCESS)return false;
//打开锁
dwRet = Dongle_Open(&hDongle, 0);
if (dwRet != DONGLE_SUCCESS)return false;
//验证开发商PIN码
dwRet = Dongle_VerifyPIN(hDongle, FLAG_ADMINPIN, AdminPin, &nRemainCount);
if (dwRet != DONGLE_SUCCESS)return false;
//从加密锁中读取公钥加密后的数据
dwRet = Dongle_ReadFile(hDongle, wFileID, 0, tmpbuf, 128);
if (dwRet != DONGLE_SUCCESS)return false;
//RSA私钥解密
nInDataLen = 128;
nOutDataLen = (128 - 11);
dwRet = Dongle_RsaPri(hDongle, wPriID, FLAG_DECODE, tmpbuf, nInDataLen, tmpbuf, &nOutDataLen);
if (dwRet != DONGLE_SUCCESS)return false;
//关闭加密锁
dwRet = Dongle_Close(hDongle);
if (dwRet != DONGLE_SUCCESS)return false;
//比较解密后的数据与原始数据是否一致
//这里buffer里的原始数据我用的是128位标准填充
for (int i = 0; i < 128; i++) buffer[i] = i;
if (memcmp(tmpbuf, buffer, 117) == 0)
return true;
else
return false;
}
在main()函数中判断if(Dongle())
,否则终止程序,并给出相应提示。