文章内容主要是对网上找到的一篇 文章进行整理,并对照mystar的源代码进行修改和补充得到的,但是因为那篇文章时很久之前找到并保存下来的,已经记不清作者和出处了,所以在这里没办法列出来,但还是要对他表示感谢。
一、802.1x认证过程
认证过程中客户端和认证服务器之间运行EAPOL协议,二者之间传送的信息均为以太网帧格式。每一帧均包含如下头信息。
01 80 C2 00 00 03 AA BB CC DD EE FF 88 8E 01 01
00 00 ……
前6个字节为目标地址,之后6个字节是源地址,这里假定为AA BB CC DD EE FF;第13,14个字节是协议类型(proctol type),802.1x对应的值为88 8E;第15个字节是协议版本号(proctol version);16字节是帧类型(packet type);第17、18字节为帧的长度(Packet Body Length),是指头信息之后(从第19字节开始)的有效数据的长度。
另外每一帧的有效数据之后还必须包含实达专用的附加数据包。
FF FF 37 77 FF 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 08 15 00 00 13 11 38 30 32 31 78
2E 65 78 65 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 02 1F 00 00 00
00 00 13 11 00 28 1A 28 00 00 13 11 17 22 92 68
64 66 92 94 62 66 91 93 95 62 93 93 91 94 64 61
64 64 65 66 68 94 98 A7 61 67 65 67 9C 6B
这110字节为实达专用附加数据包,在每一帧的后面都要附加这个数据包。其中从第6字节开始的18个字节要填充本机相应的信息:IP、掩码、网关、 DNS,还有一个不知道是什么意思的两字节的circleCheck,这些信息都要经过加密,加密算法在mystar里叫做Alog。
1.客户端发起认证(EAPOL-Start)
01 80 C2 00 00 03 AA BB CC DD EE FF 88 8E 01 01
00 00
发起认证时客户端并不知道服务器的MAC地址,可以用标准组播地址(01 80 C2 00 00 03),也可以用实达的私有组播地址(01 D0 F8 00 00 03)。EAPOL-Start帧的帧类型为01。
2.服务器端请求用户名(EAP-Request/Identity)
AA BB CC DD EE FF 00 D0 F8 FC 78 4E 88 8E 01 00
00 05 01 01 00 05 01
从这里可以得到服务器的地址00 D0 F8 FC 78 4E,并填充到以后的帧中;第19字节是帧类型,01表示请求;第20字节是客户端发送用户名时要用的Identity。
3.客户端发送用户名(EAP-Response/Identity)
00 D0 F8 FC 78 4E AA BB CC DD EE FF 88 8E 01 00
00 0D 02 01 00 0D 01 ......
Packet Type为00,Packet Body Length是从第19字节到用户名最后一个字符的长度,则此处为000D,这里用的是网络字节顺序(network byte order);19字节02表示Response;20字节的01是上面包里的Identity,以后每一步都相同,故不再重复;21、22字节含义与第 17、18字节相同;23字节表示发送的是用户名;第24字节开始是用户名的ASCII码。
4.服务器端请求密码(EAP-Request)
AA BB CC DD EE FF 00 D0 F8 FC 78 4E 88 8E 01 00
00 16 01 02 00 16 04 10 01 02 03 04 05 06 07 08
09 00 01 02 03 04 05 06
这里需要用到的除了Identity,还有从第24字节开始的密钥信息,第24字节是密钥的长度,之后是密钥。这个密钥用来加密将要发送的用户密码。
5.客户端发送密码(EAP-Response)
00 D0 F8 FC 78 4E AA BB CC DD EE FF 88 8E 01 00
00 1E 02 02 00 1E 04 10 XX XX XX XX XX XX XX XX
XX XX XX XX XX XX XX XX ?? ?? ?? ?? ?? ?? ?? ??
16个字节的XX是加密后的密码,是用MD5算法算出来的,生成方法是把Identity、密码和加密密钥按顺序保存在一个数组中,再计算其MD5。之后的??是用户名。
6.服务器表明认证结果
AA BB CC DD EE FF 00 D0 F8 FC 78 4E 88 8E 01 00
00 EA 03 02 00 04 00 00 13 11 00 56 0D 0A 20 C9
......(省略12行)
00 00 00 13 11 01 01 00 00 13 11 01 01 FF FF 37
77 AF 7F FF FF A7 FC FF FF FF A7 FF
第19个字节帧类型为03表示表示成功,04表示认证失败。我们要记下最后一行的FF FF A7 FC,它在帧中的偏移为packet body length + 9;
7.保持激活状态
00 D0 F8 FC 78 4E AA BB CC DD EE FF 88 8E 01 BF
00 1E FF FF 37 77 7F 9F F7 FF 00 00 FF FF 37 77
7F 9F F7 FF 00 00 FF FF 37 77 7F 3F FF
上面是mystar中的原始数据,其中第35至38字节由一个初值为0x1000002A的序列号经Alog算法加密生成的mystar里叫做Alog,该序列号每次使用前加一。第19至第22字节由上面包中的FF FF A7 FC加上序列号再经Alog算法生成。每过一段时间就需要发送该帧一次以维持激活状态。而hustauth的做法则是每隔45秒就重新认证一次。
二、实现构想
进行认证的关键是数据链路层(OSI模型中的第二层)的通信。mystar用了libpcap来实现。而我的想法是直接使用Unix/Linux的 socket来实现。socket中有一种PF_PACKET,就是在数据链路层进行通信的(libpcap就是用PF_PACKET写出来的),所以完全可以用PF_PACKET来完成认证程序,只是会麻烦一点。
PF_PACKET可以用如下方法创建:
socket(PF_PACKET, int socket_type, int protocol);
其中socket_type可以是SOCK_RAW或SOCK_DGRAM。SOCK_RAW 直接从数据链路层取得数据包,而SOCK_DRRAM 则要对数据包进行加工(cooked),去掉数据链路层头信息。创建之后可以用recvfrom()和sendto()进行读写,读写时要用一个 sockaddr_ll 来保存链路信息。详细的信息可以在相应的manpage里找到。
阅读(1335) | 评论(0) | 转发(0) |