《电子技术应用》
您所在的位置:首页 > 嵌入式技术 > 业界动态 > USB安全钥功能扩展与优化设计

USB安全钥功能扩展与优化设计

2009-01-19
作者:马 伟

    摘  要:介绍USB安全钥的完整功能,加密算法的动态链接库DLL设计,在线修改存储在安全钥内的用户产品信息功能的方法。为设计完整的USB设备提供借鉴。 

    关键词:通用串行总线USB  单片机  动态链接库DLL  标准加密算法DES  USB固件  USB驱动程序  人机接口设备HID 

 

1  USB安全钥的完整功能 

    USB安全钥最早基于USB的热插拔、速度以及硬件等优势,结合加密算法,用于办公文件、软件等的存储和加密。但USB安全钥的用武之地远不止这些,与网络技术结合,用于时下最时尚的电子商务中,才使其大显神通。USB安全钥结合传统的电子商务核心技术和新兴的USB技术,用于实现电子商务中的关键技术——身份识别,在未来电子商务领域具有广阔的应用前景。USB安全钥集数据加密和数据存储两大功能于一体,推动了电子商务的发展。 

    传统的电子商务或是网络email等的身份认证基本上是通过两种方式来实现的。一种是密码机制,双方约定好规则。这是目前最为普遍的方式,但是这种方式的严重缺点显而易见。密码作为最重要的信息,在网络上传输,很容易被黑客攻击截获,经常发生密码被盗。第二种方式是通过第三方的认证,双方共同信任第三方公司提供的信息,从而进行交易。微软在.NET计划中推出的认证服务器就提供这种服务。但是,信誉度建立在第三方上,便会受到第三方的制约,掏钱不说,还要担心第三方是否会倒闭。USB安全钥解决了这两种方式无法解决的问题。 

    完整的USB安全钥系统由三部分组成:安全钥端,采用Motorola公司带USB接口的8位单片机MC68HC908JB8构成;PC端,由任何一台可接入网络的PC构成,并安装PC端的用户身份认证软件;Server端,任何一台网络服务器安装用于身份认证的Server端软件。 

    USB安全钥系统结构体系及功能流程如图1所示,列出了九个步骤,描述了USB安全钥从插入PC到完成一次身份识别的完整流程。 

 

 

    需要强调的是,在上述步骤中,PC仅仅起一个Media(媒介)的作用。任何重要的数据都没有经过PC,在网络上传输的仅仅是8个字节的随机数(它只在Server服务器和安全钥端有意义,只对特定的加密算法和密钥有意义),被黑客截取也不会有问题。这8个字节的随机数由网络Server产生,经由PC传递给USB安全钥加密;加密后的随机数再由PC不加任何改变地传递给Server;Server去调用解密算法解开加密的随机数,与原来未加密的随机数比较,如果相同则说明USB安全钥的持有者身份合理。整个身份认证也告结束。这里,USB安全钥体现出两大优点:(1)没有任何重要的个人信息在网上传递,保证了安全性;(2)Server由网络商自己维护,安全钥由用户携有,双方的认证没有依靠第三方,快捷、安全、信誉度高。当然,USB安全钥还有其他很多优点,例如可以在PC上热插拔,可以在任何一台支持USB的PC上工作(现在几乎所有的PC都应该支持USB)等。 

2 USB安全钥的技术细节 

    USB安全钥技术,从设计上可以分为三个模块:Server端的网络通讯和加密算法设计、PC端的USB驱动程序和网络通讯设计、安全钥端的USB固件和加密算法设计。涉及到的计算机技术包括Socket网络编程技术、USB驱动程序设计技术和加密算法技术。可以说整个设计内容庞杂,技术难度高。因此,设计时就需细化,一步步完成单个功能,再进行联调,将单个模块融合成完整的USB安全钥。 

    后期的功能扩展和优化设计也是针对三个模块,应用三大技术完成。主要是:服务器(Server)端DES加密算法的研究,设计加密算法的动态链接库DLL,提供给客户最简单的API;PC和安全钥端驱动程序的研究,实现PC端友好的程序界面,动态在线修改存储在安全钥内的用户产品信息。本文将详细介绍扩展和优化的设计方法,从而揭示USB安全钥的技术细节。 

2.1 如何设计Server端加密算法及其DLL 

    密码算法(Algorithm)就是指加密函数(Encryption)和解密函数(Decryption)。有加密函数,那么必然有一套与它对应的解密函数。现代密码学用密钥技术解决了保密性不够的问题。密钥用K表示。K的取值范围叫做密钥空间。可以用如下式子来表示加密和解密函数之间的关系: 

    DK(EK(M))=M 

    其中,E为加密函数,D为解密函数,M为被加密的原文。有一个重要的结论:所有算法的安全性都基于密钥的安全性,而不是算法细节的安全性。这就是说,算法可以公开,只要密钥是保密的,则这个算法就是安全的。简单地说,密钥就是与密文叠加在一起的一组数。 

    标准加密算法DES作为ANSI的数据加密算法和ISO的DEA-1,成为世界范围内的标准已经20多年。就目前密码学的发展情况来说,DES的安全性还是能够满足用户需求的。由于完整的DES算法相当复杂,这里仅简单介绍算法的结构。 

    DES是分组加密算法,以64位为一组对明文进行分组,然后进行加密和解密。加密和解密的算法相同,只是密钥的编排不同。密钥长度为56位,通常是64位,但是每字节第8位都用来作为奇偶校验位,因此实际上只有56位。DES共有16轮,即对同一组明文结合密钥进行16轮相同的加密过程,最终达到加密要求。 

    具体到每一轮的加密过程是这样的:每一轮中,密钥位移位,然后从密钥中选出48位。数据的32位右半部分数据扩展成48位,与密钥结合。然后再将这48位数据变换为32位,并与数据的32位左半部分相与后作为新的32位右半部分。而32位左半部分基本不变。最后,左右各32位数组合在一起便构成了一轮加密后的64位密文。重复同样运算16次,便完成了加密/解密功能[4]。 

    Server端的加密算法采用DES。加密和解密是整个USB安全钥身份认证的核心。在安全钥的初期产品中,已经实现了DES算法下的加密功能。但是,作为产品,其安全性是第一位的。而且,对于要将加密算法嵌入自己系统的用户来说,提供给他们大量的加密算法的源代码是不合适的。要对DES算法进行修改,将其从Server端的源程序中提出,改掉原来复杂的调用机制,改为提供给用户三个简单的接口函数:产生随机数、加密和解密函数、实现DES加密算法的DLL。 

    动态链接库(DLL)是一个包含了若干个函数的可执行模块,Windows应用程序可以调用这些函数来完成实际任务。对于调用DLL的用户来说,利用的资源仅仅是应用函数接口和一个后缀为.dll的文件,实现加密算法的模块化。 

    在建立了一个VC工程之后,需要建立主程序头文件KeyDll.h,加入如下代码。这些代码中定义了导出的四个函数。 

class _declspec(dllexport) CKeyDllApp 

{public: 

    BOOL GetChallenge(); 

    int* Challenge();//导出函数 

    int* DecryptData(BYTE []);//导出函数,需要解密的随机数,可存储在数组InputNum[8]中。此函数输出值即为加密后的数据,输出格式为数组DESDeData[8] 

    int* EncryptData(BYTE []);//导出函数,需要加密的随机数,可存储在数组InputNum[8]中。此函数输出值即为加密后的数据,输出格式为数组DESEnData[8] 

    BOOL cha_gen; 

    void DESDecrypt ();//BYTE *Data, BYTE *Key); //解密函数定义 

    void DESEncrypt ();//BYTE *Data, BYTE *Key); //加密函数定义 

    BOOL Init(); 

protected: 

    BYTE DESKey[8];     //密钥 

    BYTE IniDeData[8]; //外部输入的需要解密的数据 

    BYTE IniEnData[8]; //外部输入的加密前的随机数 

    BYTE DESDeData[8]; //解密后的数据 

    BYTE DESEnData[8]; //加密后的数据 

    WORD subkey[16][48]; //子密钥 

    BYTE challenge[8]; 

......} 

    然后,在主文件KeyDll.cpp中实现各功能函数的具体功能,主要是算法的实现。 

BOOL CKeyDllApp::GetChallenge()//这是产生随机数的函数,它调用API的函数srand(),最终产生的8位随机数存在数组challenge[8]中 

    int i; 

    srand((unsigned)time(NULL)); 

    if(!cha_gen){ 

        for(i = 0; i < 8; i++){ 

        do{challenge[i] = (rand()/256);} 

        while((challenge[i]=='t') || (challenge[i] == 0) || (challenge[i]==255) || (challenge[i]== 256- 't'));} 

        challenge[8] = 0; 

        cha_gen = TRUE; 

        return TRUE;} 

    return FALSE;} 

 

void CKeyDllApp::DESDecrypt ()//解密函数,完成对已加密的8位随机数的解密功能  

    WORD TempInput[64],TempOutput[64],TempKey[64]; 

    stringtobit (IniDeData, TempInput); 

    stringtobit (DESKey, TempKey); 

    decry (TempInput, TempKey, TempOutput); 

    bittostring (TempOutput, DESDeData);} 

 

void CKeyDllApp::DESEncrypt()   //加密函数,可完成 

对8位随机数的加密功能,然后可与原随机数比较,看是否相等 

    WORD TempInput[64], TempOutput[64],TempKey[64]; 

    stringtobit (IniEnData, TempInput); 

    stringtobit (DESKey, TempKey); 

    encry (TempInput, TempKey, TempOutput); 

    bittostring (TempOutput, DESEnData);} 

 

int* CKeyDllApp::DecryptData(BYTE InputDeNum[8])//导出的获取解密数据的函数。此函数需要赋值——已加密了的8位随机数,并进行解密,最终函数值为解密后的 

8位随机数 

    int i; 

    for (i = 0; i < 8; i++) 

    IniDeData[i]=InputDeNum[8]; 

    return (int *)DESDeData;} 

 

int* CKeyDllApp::EncryptData(BYTE InputEnNum[8])//导出的获取加密数据的函数。此函数需要赋值——8位随机数,直接调用并赋8位随机数后,此函数将调用加密函数并进行加密,最终函数值为加密后的8位随机数 

    int i; 

        for (i = 0; i < 8; i++) 

        IniEnData[i]=InputEnNum[i]; 

        return (int *)DESEnData;}  

 

    编译、连接后将产生一系列文件,在加上源工程文件,将会有数量比较庞大的文件系统。最终,只需提供给用户三个文件即可,它们是: 

    · KeyDllDebugKeyDll.dll,这是DLL文件; 

    · KeyDllDebugKeyDll.lib,这个文件将在应用DLL的程序编译和连接时,提供连接向导; 

    · KeyDllKeyDll.h,这个头文件告诉用户此DLL中导出了哪些量可以用。 

    DES的DLL导出了一个类:CkeyDllApp。在这个类中共有4个导出函数可以导入应用程序中,用户在导入了加密DLL后,可以在自己的程序中直接调用以下函数: 

    · BOOL GetChallenge(),用于在应用程序支持循环结构; 

    · int*Challenge(),产生随机数,并存储在Challenge[8]中; 

    · int*DecryptData(BYTE []),用于解密随机数; 

    · int*EncryptData(BYTE []),用于加密随机数。 

2.2 USB安全钥新增功能描述 

    USB安全钥和PC传输的数据量不大,而且没有很高的速度要求。因此,在编写固件时就将其归类为HID(USB的人机接口设备类)。在编写PC端的驱动程序时可以直接调用Windows提供的HID的API函数,大大降低了编程的难度。更重要的是,Windows对HID设备的支持非常完备,不需要用户再编写底层的驱动。 

    安全钥端的设计内容主要是:实现在线修改存储在安全钥内的KeyID和读取KeyID两个功能,分别由函数Set_KeyID和Get_KeyID实现。KeyID是安全钥的标识符,在安全钥插到PC上后,被读出并送往Server进行检查。在初期产品中,KeyID只能是安全钥首次接到PC上读取,且不能更改,这为厂家和开发者造成了不便。因此要更改初期产品中的KeyID,就必须修改安全钥端的汇编程序,然后再“烧”写到安全钥中,非常麻烦。新增功能可实现KeyID的在线修改。 

    PC端的设计包括两步。首先要实现在PC上读取安全钥内的KeyID。通过安全钥的端点1,8个字节的KeyID被周期地送出。PC要获取这些数据,调用HID类库Get_Report(Feature)。从安全钥发来的包含KeyID的包的特性及技术指标如表1。 

 

 

    第2步,在PC上实现修改KeyID功能。调用HID类库Set_Report(Feature),将新的KeyID发送到安全钥中,具体指标如表2所示。

 

 

2.3 如何设计安全钥端新增功能的USB固件 

    USB固件(Firmware),就是USB安全钥硬件上采用的单片机和其他处理器中有关USB通信的程序。这里采用Motorola公司的8位单片机MC68HC908JB8作为USB安全钥的控制器芯片。MC68HC908JB8带有USB接口,8K的Flash,支持USB 1.1版本中的低速(Low Speed)设备,资源有限,主要用于实现USB通信,价格比较低廉。因此,很适合于USB安全钥。MC68HC908JB8中USB通信的程序模块,包含在实现MC68HC908JB8所有功能的汇编程序中。 

    图2是经典的USB固件的流程图。考虑到USB安全钥中USB数据通信量很小,不需要考虑通信时间,采用中断传输方式。整个程序就是在等待数据传输要求的中断到来,从而进入数据传输模块。读/写数据缓冲区,往USB端点(Endpoint)中读/写数据,交给USB模块收发数据。当USB安全钥不需要传输数据时,就进入挂起状态(Suspend)。在得到PC主机远程唤醒后启动,继续工作。 

 

 

    新增功能中,主要完成的两个功能就是KeyID的读取和修改,即实现Get_KeyID和Set_KeyID功能。程序构思大致是:对于Get_KeyID,在接收到PC端发来的读取KeyID的中断后,立即从端点1发送8字节的KeyID,这一段没有什么特别之处;对于Set_KeyID,在接收到信号后,立即转入Set_KeyID子程序。首先将存储KeyID的Flash去保护,然后寄存器置位,即在硬件上给Flash一个高电平,接着进行擦除,再将保存于缓冲区的PC发来的新KeyID存储到Flash中。最后,置Flash状态寄存器位,给Flash加保护。 

2.4 PC端新增功能的USB驱动程序设计 

    Windows 98的驱动程序从结构上来说分为两层:内核层和用户层。USB的客户驱动程序属于用户层,而USB类驱动程序和底层驱动程序则属于内核层。目前,USB还属于起步阶段,Windows对USB的支持还不够完善,仅支持内核层。USB开发人员所要做的,就是开发客户驱动程序,直接与类驱动程序打交道。 

    HID属于USB设备类中的一个子类,Windows对它提供了非常强大的支持,尤其是在用户层提供了Hid.dll,其中包含了用户层驱动程序与类驱动程序通信需要的各种功能模块,将它们以API的形式提供给用户函数接口。这样,在编写客户驱动程序的时候就可以直接调用这些API函数来完成诸如IN、OUT等功能,大大降低了编写驱动程序的难度。 

    HID客户驱动程序访问HID类驱动程序,由HID类驱动程序完成大多数工作,而硬件交互由HID小驱动程序HidUsb.sys处理,HID小驱动程序调用USB底层驱动程序USBD.sys访问设备。 

    这里介绍用户模式的HID客户驱动程序设计过程。它主要包括三个方面的工作: 

    ·查找所有HID设备; 

    ·对于查找到的每一个HID设备,检查其功能,判断是否为感兴趣的设备; 

    ·根据用户需要读取HID输入Report(Feature)或者写HID输出Report(Feature)。 

    程序流程如下: 

    (1)查找USB安全钥设备; 

    (2)读取HID设备功能; 

    (3)具体实现Get_KeyID和Set_KeyID子函数; 

BOOL    CUsbKey::GetKeyID()  //Get_KeyID子程序 

{... 

    result=HidD_GetFeature(HidDevice, ReadBuffer,0x09); 

   //调用此函数,获取从端点1发来的8字节KeyID;  

    for(tmpInt=0;tmpInt

        KeyID_Get[tmpInt]=ReadBuffer[tmpInt+1]; 

    return TRUE; 

BOOL  CUsbKey::SetKeyID()    // Set_KeyID子程序 

{   int i; 

    long result; 

    int DataBuffer[16]; 

    WriteBuffer[0]=0;           //写缓冲区首字节清0,作为Set_Feature函数的要求 

    char *c;                  //获得对话框内输入8字节新KeyID字符串的指针 

    c=(char *)(LPCSTR)str_KeyIDSet; 

    for (i=0;i

        DataBuffer[i]=*c++; 

    ……   //此处省略了对输入的8个字节的KeyID的16进制检查代码 

    for(i=0;i<8;i++) 

        WriteBuffer[i+1]=DataBuffer[2*i]+DataBuffer[2*i+1]; 

    result=HidD_SetFeature(HidDevice,WriteBuffer, 0x09); 

    return  TRUE; 

    (4)程序运行结果。 

    编译连接之后,最终会生成可执行文件KEYDEMO.exe。执行它即可SK通信,实现各种功能。 

参考文献 

1 王云飞.USB系统研究.研究生论文,北京:清华大学,2001 

2 MOTOROLA. MC68HC908JB8 Technical Data. 2000 

3 Chris Cant (美)著,孙义译.Windows WDM设备驱动程序开发指南.北京:机械工业出版社,2000 

4 Bruce Schneier(美)著,吴世忠译.应用密码学——协议、算法与C源程序.北京:机械工业出版社,2000 

5 USB Implementers' Forum.Universal Serial Bus Specification, Revision 1.0. January 15, 1996

本站内容除特别声明的原创文章之外,转载内容只为传递更多信息,并不代表本网站赞同其观点。转载的所有的文章、图片、音/视频文件等资料的版权归版权所有权人所有。本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如涉及作品内容、版权和其它问题,请及时通过电子邮件或电话通知我们,以便迅速采取适当措施,避免给双方造成不必要的经济损失。联系电话:010-82306118;邮箱:aet@chinaaet.com。