092_基于Linux的网络层加密解密
1.无需注册登录,支付后按照提示操作即可获取该资料.
2.资料以网页介绍的为准,下载后不会有水印.资料仅供学习参考之用.
密 惠 保
系统的设计与实现
4.1 系统的总体设计
内核嵌入部分主要实现对套接字缓存的数据即skbuff->data进行加密、解密。在内核中定义的函数均在linux/include/net/ip.h中声明。
对于IP包的加密状况,这里采用设置加密位来标志该IP包是否被加密,而由于IP头中的TOS字段作为优先权的高3位已经废弃,为了减少内核的大小,采取把TOS最高位置1作为加密标志。以次判断包是否应该解密。
对于如何判断一个包是否应该加密,设计为判断目的IP地址。设计思路为把需要加密发送的目的IP地址存放到一个定义为全局变量的链表中。该链表在内核运行期间始终有效,并声明为模块可读写。链表结构体定义在ip.h中:
extern struct iplist{
unsigned int ip;
struct iplist *next;
}iplist;
定义一个全局变量:struct iplist *list;
并声明为模块可读写:EXPORT_SYMBOL(list);
通过模块对用户文件/home/ip.list和/home/rm_ip.list读取实现对list的插入和删除。通过对list的查询来判断发送包是否应该加密。
4.2 模块部分的设计与实现 【买计算机毕业论文就到计算机毕业论文网】
由于模块主要是针对链表和文件的操作,为了能够使多个模块都能使用到这些函数,采取把一些主要函数定义在内核中。具体位置为net/ipv4/myfile.c,里面的函数主要是涉及到对全局变量list的操作。 think58好,好think58
首先定义直接对链表操作的函数:
void init_iplist(struct iplist **list),初始化链表,EXPORT_SYMBOL(init_iplist)声明为模块可用;
void insert_iplist(struct iplist *list, unsigned int ipaddr),链表插入操作函数,插入位置为紧接头部之后。由于网络通信的特点是短时间内发往同一目的地址的数据包一般情况下最频繁。这样可以减少查询链表的时间;
int query_iplist(struct iplist *list, unsigned int ipaddr)。链报查询操作函数,在链表未初始化时返回2,链表中存在ipaddr时返回1,不存在则返回0,EXPORT_SYMBOL(query_iplist)声明为模块可用。
定义对文件的操作,文件部分的函数均声明为模块可用:
struct file *list_fopen(const char *filename, int flags, int mode),定义在内核中打开文件的操作;
void list_fclose(struct file *filp),定义对文件的关闭操作;
int list_fread(char *buf, int len, struct file *filp),定义对文件的读操作。由于内核中对文件的读写操作要求缓存buf为用户空间变量,所以操作的时候要避免内核对变量地址的检查;
int list_fgetc(struct file *filp),通过调用list_fread()函数实现按1个字节读取; think58.com [资料来源:http://think58.com]
其他函数的定义,以下函数也均声明为模块可用:
void my_atoi(char *buf, unsigned int *ipaddr),把点分十进制的IP地址转换为32位无符号整形数。但是按点分段从右到左转换,以保证于套接字缓存中的目的IP地址方式一致;
void init_iplist_byfile(struct file *fp, struct iplist *list),根据文件对list进行插入操作。
功能模块主要包含对list的插入操作、删除操作和读操作,对DES密匙的修改。模块是Linux系统为防止内核不断扩大而设计的一种体系,它能运行于内核态,可以自由加载和删除,增加了系统的灵活性。
针对2.6版本内核,模块的编写方法大致如下,egmodule.c:
#include <linux/kernel.h>
#include <linux/module.h> think58.com [资料来源:THINK58.com]
int function1()
{
...
函数体
...
}
think58好,好think58
[资料来源:www.THINK58.com]
[版权所有:http://think58.com]
...
[资料来源:http://think58.com]
void functionx()
{
...
函数体
...
}
本文来自think58 [资料来源:http://THINK58.com]
[资料来源:http://think58.com]
void functiony()
{
...
函数体
...
} 本文来自think58
module_init(functionx);
module_exit(functiony); think58.com [资料来源:http://THINK58.com]
MODULE_LICENSE("GPL"); think58好,好think58
[来源:http://think58.com]
然后利用make,gcc编译成可执行的模块,makefile内容为:
ifneq ($(KERNELRELEASE),)
obj-m := egmodule.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
[来源:http://www.think58.com]
分别编写模块insertlist、deletelist、showlist、和repdeskey:
insertlist主要实现读取文件/home/ip.list中的点分十进制IP地址插入 list中,如果list中已经存在的IP地址则不需再插入;
deletelist主要实现读取文件/home/rm_ip.list中的点分十进制IP地址,并删除list中与之相同的IP地址;
showlist主要实现查看list中的IP地址;
repdeskey主要实现修改DES加密算法的密匙。
4.3 DES算法实现
与DES相关函数全部定义在文件net/ipv4/des.c中。
由于套接字缓存中skbuff->data为数据开始,但是其并不是标准字符串(即不是以‘\0’结尾)的头指针。所以在次先多DES加密算法做一些修改,即添加一个参数,表示需加密的长度。而由于IP包的一个特点是,数据的长度为8的整数倍,所以这里的DES算法可以不考虑对字符串的填充。
DES算法的主要实现思想为定义一个长度为64的unsigned char类型的字符数组把字符串的每8字节按位存储在该字符数组中。密匙也用基本相同的方法处理。加密算法的所有操作都以数组元素为单位操作,减少了位操作的烦琐。
Des.c中定义的所有函数如下:
extern void bytetobit(unsigned char *, unsigned char *),16轮迭代过后,把字符数组,每字节用位表示; think58.com
extern void initper(unsigned char *, unsigned char *),对传入数据的初始置换,同时按每位没字节存放到字符数组中;
extern void expper(unsigned char *, unsigned char *),数据右半部分的扩展置换;
extern void keyper(unsigned char *, unsigned char *),密匙替换;
extern void pper(unsigned char *),P盒置换;
extern void tailper(unsigned char *),末置换;
extern void cvrtdata(int, unsigned char *, unsigned char *),把数据分成8字节每块;
extern void packper(int, int, unsigned char *, unsigned char *),生成每轮密匙;
extern void sproc(unsigned char *, unsigned char *),S盒处理;
extern void des(int, unsigned char *, int, unsigned char *),DES主函数;
extern void decskb(struct sk_buff *skb)和extern void encskb(struct sk_buff *skb)实现对套接字缓存的操作。
在这里给出几个重要函数的实体:
DES算法主程序:
void des(int mode, unsigned char *data, int datalen, unsigned char *key)
{
unsigned char *s, keyw[48], keybyte[56], databyte[64], bufdata[64], expdata[48], tempdata[32]; 本文来自think58
int i, iternm, len = 0;
s = data;
keyper(key,keybyte);/*密匙置换,每位以1字节表示*/
while (len < datalen) {
for (i = 0; i< 8; ++i, ++len) {
cvrtdata(i, s ,databyte);/*数据分块,并扩展为每位用1字节表示*/
}
initper(bufdata, databyte);/*初始置换*/
for(iternm = 0; iternm < 16; ++iternm) {/*16轮迭代*/
packper(mode, iternm, keybyte, keyw);/*得到压缩的48位密匙*/
for (i = 0; i < 32; ++i)
tempdata[i] = bufdata[32 + i];
expper(tempdata, expdata);/*得到扩展的48位数据*/
for (i = 0; i < 48; ++i)
expdata[i] ^= keyw[i];/*数据密匙异或*/
sproc(expdata, tempdata);/*s盒子处理*/
pper(tempdata);/*p盒置换*/
for (i = 0; i < 32; ++i)
tempdata[i] ^= bufdata[i];/*与左半部异或*/
if (iternm < 15) {/*前15轮左右交换*/
for (i = 0; i < 32; ++i) {
bufdata[i] = bufdata[32 + i];
bufdata[32 + i] = tempdata[i];
}
}
else {/*最后1轮不交换*/
for (i = 0; i < 32; ++i) think58 [资料来源:THINK58.com]
bufdata[i] = tempdata[i];
}
}/*迭代结束*/
tailper(bufdata);/*末置换*/
bytetobit(s, bufdata);/*把以字节表示的位转换为位表示*/
s += 8;
}
};
Encskb函数实体:
void encskb(struct sk_buff *skb)
{
int i = skb->tail - skb->data;
unsigned char *data;
data = skb->data + (skb->nh.iph->ihl * 4);
des(1,data, i, DES_KEY);
};
Decskb函数实体:
void decskb(struct sk_buff *skb)
{
int i = skb->tail - skb->data;
unsigned char *data;
data = skb->data +(skb->nh.iph->ihl * 4);
des(0, data, i, DES_KEY);
};
4.4 对内核函数的修改
修改的内核函数主要在net/ipv4/ip_output.c和net/ipv4/ip_input.c中。主要通过对list的查询和加密位的检查调用加密算法实现对数据的加密解密。
在ip_input.c中的ip_local_deliver()函数中decskb()需被调用,对套接字缓存中IP头以后的数据进行解密。并检查list,如果list中没有该源IP地址,则插入:
/*
* Decrypt the skb whose destination is in the list.
*/
if ((skb->nh.iph->tos) & 128) {
skb->nh.iph->tos &= 127;
printk(KERN_ALERT "ip_local_deliver(),decrypt!\n");/*测试语句*/
decskb(skb);
if (list == NULL)
init_iplist(&list);
if (!query_iplist(list, skb->nh.iph->saddr))
insert_iplist(list, skb->nh.iph->saddr);
}
而由于数据包传出过程中有多处进入IP层的接口,所以在ip_output.c中也分别在ip_build_and_send_pkt()、ip_queue_xmit()和ip_push_pending_frames()中encskb()需被调用。由于在加密过程中需要对TOS字段进行设置,所以应该在计算IP头检验和之前调用,以避免多次计算检验和。
/*
* Set the bit that is for encryption and encrypt.
*/
if (!(iph->tos & 128) && (query_iplist(list, iph->daddr) == 1)) {
iph->tos |= 128;
printk(KERN_ALERT "encrypt");
encskb(skb);
}
5 网络层加密系统的测试
该系统已经成功通过测试。为直观显示测试过程,在加密系统中的加密解密程序块中插入了测试语句。测试环境为两个虚拟机A、B、C的内网地址分别为192.168.1.102、192.168.1.107、192.168.1.100,网管地址为192.168.1.9。A、B两机操作系统为加密系统,C和网管系统为普通系统。系统B为系统A的克隆,所以图中A、B主机名和用户名字相同。由于加密系统环境为终端环境, 所以测试程序采用系统本身的ping命令。下面介绍测试细节。 [版权所有:http://think58.com]
首先测试加密系统的普通工作情况,即A、B两机的list为空时,作为普通主机的网络工作情况。A、B主机互相能够ping通,并且无测试语句出现。
接着我们分别向A、B两主机的list中插入对方IP地址,A、B主机能互相ping通,并出现测试语句:显示结果为如图5和图6:
think58好,好think58
[资料来源:http://THINK58.com]