1. 关于冲击/响应身份认证的原理:
认证过程分为两个认证阶段,在两个认证都通过的情况下,系统才认为是合法用户。
第一个验证是,pin码验证:pin码保存再uk内,合法用户知道,该pin码不在网络上传输
第二个验证时,随机数验证:网络上传输一个随机数,uk和服务器分别加密这个随机数,分别得到一个密文,看这两个密文是否匹配
2. 关于冲击/响应身份验证的过程
1. 打开系统页面,插入uk
2. 输入用户的pin码
3. 点击“登陆”或者“识别”等类似触发验证的事件
4. 开始验证……
5. 验证pin码(在uk里面验证,不再网络传输),若不正确,提示用户不是pin码错误,退出系统;若是继续下一步验证
6. 随机数验证,pin码正确后给服务器一个相应,服务器就会发一个随机数s1给客户端。此时,服务器和客户端同时加密这个随机数s1:服务器端用密钥(存在数据库或者文件中)加密这个随机数s1得到一个密文s2;客户端在uk中用两个密钥文件(uk初始化时已经保存uk中,关于初始化问题,下面会有详述)加密这个随机数s1得到密文s3,把s3传回到服务器
7. 检验s2和s3是否完全一样,若一样则是合法用户,不一样则为非法用户
3. 冲击/响应验证的优点
网上很多。
4. 初始化和冲击/响应验证的代码分析
Uk初始化和验证的代码分析:对于初始化可分为客户端初始化和服务器端初始化两种;这两种方式的冲击/响应验证都是一样的
服务器端初始化:引入名称为Interop.ePasModLib.dll的动态链接库
初始化的主要步骤:创建实例,打开实例,创建key文件所在的目录,创建key文件,由密钥产生两个key文件的内容,把内容分别写入两个key文件,关闭实例
- //创建实例
- ePasModLib.ePas1Class epass = new ePasModLib.ePas1Class();
- //CreateContext函数必须首先被调用(相当于加载epass实例)
- epass.CreateContext(0, 0x0200);
- //打开实例
- epass.OpenDevice(1, AppID);
- //创建目录
- di.lID = 0x200;
- di.lFlags = 0;
- epass.CreateDir(0, "", guid, ref di);
- //把当前目录从根目录换到创建的目录(把当前的目录换到id为“0x200”的目录)
- epass.ChangeDir(0, 0x200, "");
- //创建两个Key文件
- fi.lID = 3;
- fi.lFlags = 0;
- fi.lFileSize = 16;
- fi.ucFileType = (byte)0x04;
- fi.ucReadAccess = (byte)0x00;
- fi.ucWriteAccess = (byte)0x00;
- fi.ucCryptAccess = (byte)0x00;
- epass.CreateFile(0, ref fi);
- fi.lID = 4;
- fi.lFlags = 0;
- fi.lFileSize = 16;
- fi.ucFileType = (byte)0x04;
- fi.ucReadAccess = (byte)0x00;
- fi.ucWriteAccess = (byte)0x00;
- fi.ucCryptAccess = (byte)0x00;
- epass.CreateFile(0, ref fi);
- object strKey1 = "";
- object strKey2 = "";
- object strDist = "";
- //密钥,用密钥产生两个key文件
- string strPassword = "esint";
- ePasModLib.HashClass ClaHashClass = new ePasModLib.HashClass();
- ClaHashClass.MD5HMAC("", strPassword, ref strKey1, ref strKey2, ref strDist);
- byte[] Key = hexstr2array((string)strKey1);
- //打开2个Key文件,写入内容
- epass.OpenFile(0x20, 1, ref fi);
- epass.Write(0, 0, Key, 16, out tSize);
- epass.CloseFile();
- Key = hexstr2array((string)strKey2);
- epass.OpenFile(0x20, 2, ref fi);
- epass.Write(0, 0, Key, 16, out tSize);
- epass.CloseFile();
- epass.CloseDevice();
客户端初始化:引入classid=clsid:0aa5300d-42fc-42a0-9487-357ccc060a7a的activex控件
初始化的主要步骤:加载实例,打开实例,创建key文件所在的目录,创建key文件,产生第一个key文件内容,写入可以文件,产生第二个可以文件内容,写入key文件,关闭实例
- '加载打开实例
- ePass.GetLibVersion
- ePass.OpenDevice 1, ""
- '创建目录和文件
- epass.CreateDir 0,pName,pGUID,
- '更改目录
- ePass.ChangeDir &H20, &H200, ""
- '创建文件
- epass.CreateFile 0,3,16,4,7,0,1,0
- epass.CreateFile 0,4,16,4,7,0,1,0
- '密钥
- dim key
- key=”esint”
- dim strDist
- dim pData
- pData=""
- '产生和写key文件
- epass.Soft_MD5HMAC 0,pData,key,strDist
- epass.OpenFile &H20,3
- epass.Write 1,0,0,strDist,16
- epass.Soft_MD5HMAC 1,pData,key,strDist
- epass.OpenFile &H20,4
- epass.Write 1,0,0,strDist,16
- '关闭设备
- ePass.CloseDevice
验证过程:服务器给客户端传输一个随机数s1; 客户端在uk里面加密得到s2,传回服务器;同时服务器端加密得到s3;对比s2和s3是否一样。
客户端加密过程:引入classid=clsid:0aa5300d-42fc-42a0-9487-357ccc060a7a的activex控件
- '打开设备,改变目录
- ePass.OpenDevice 1, ""
- ePass.ChangeDir &H20, &H200, ""
- '验证pin
- ePass.VerifyPIN 0, Pin
- ePass.OpenFile 0, 3
- 'Do HASH-MD5-HMAC compute.
- Digest = ePass.HashToken(1,4,document.Form1.random.Value)
- ePass.CloseDevice
服务器端加密验证过程:引入名称为Interop.ePasModLib.dll的动态链接库
- #region these for MD5_HMAC
- //these for MD5_HMAC
- string ipad = "";
- string opad = "";
- {
- for (int i = 0; i < 64; i++)
- {
- ipad += "6";
- opad += "//";
- }
- }
- string Password = userpwd;
- int KLen = Password.Length;
- string iResult = "";
- {
- for (int i = 0; i < 64; i++)
- {
- if (i < KLen)
- iResult += Convert.ToChar(ipad[i] ^ Password[i]);
- else
- iResult += Convert.ToChar(ipad[i]);
- }
- }
- iResult += clientrandom;
- iResult = fun_MD5(iResult);
- byte[] Test = hexstr2array(iResult);
- iResult = "";
- char[] b = System.Text.Encoding.GetEncoding(1252).GetChars(Test);
- for (int i = 0; i < b.Length; i++)
- {
- iResult += b[i];
- }
- string oResult = "";
- {
- for (int i = 0; i < 64; i++)
- {
- if (i < KLen)
- oResult += Convert.ToChar(opad[i] ^ Password[i]);
- else
- oResult += Convert.ToChar(opad[i]);
- }
- }
- oResult += iResult;
- string Result = fun_MD5(oResult).ToUpper();
- if (Object.Equals(Result, clientdigest))
- {
- Response.Write("<script language='javascript'>alert('验证通过')</script>");
- }
- else
- {
- Response.Write("<script language='javascript'>alert('验证未通过')</script>");
- }
- #endregion
- string fun_MD5(string str)
- {
- byte[] b = System.Text.Encoding.GetEncoding(1252).GetBytes(str);
- b = new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(b);
- string ret = "";
- for (int i = 0; i < b.Length; i++)
- ret += b[i].ToString("x").PadLeft(2, '0');
- return ret;
- }
- Byte[] hexstr2array(string HexStr)
- {
- string HEX = "0123456789ABCDEF";
- string str = HexStr.ToUpper();
- int len = str.Length;
- byte[] RetByte = new byte[len / 2];
- for (int i = 0; i < len / 2; i++)
- {
- int NumHigh = HEX.IndexOf(str[i * 2]);
- int NumLow = HEX.IndexOf(str[i * 2 + 1]);
- RetByte[i] = Convert.ToByte(NumHigh * 16 + NumLow);
- }
- return RetByte;
- }
注:其中hexstr2array和fun_MD5函数的代码是飞天的例子中的