Quỏ trỡnh gửi gúi tin trong IP-Crypto

Một phần của tài liệu đề tài phần mềm bảo mật mạng dùng giao thức ip quyển 4a các phần mềm bảo mật gói ip trên hệ điều hành linux (Trang 115 - 120)

Phần mềm IP-Cryplink-3.0 gửi gúi tin được bảo mật thụng qua cạc mạng ảo được dựng sẵn. Chỉ những gúi tin nào được bảo mật mới được cạc mạng ảo này xử lý.

Một cạc mạng được đại diện bởi một cấu trỳc device. Trong cấu trỳc device, cú chứa cỏc tham số liờn quan đến thiết bị như tờn giao diện, địa chỉ vào ra của thiết bị phần cứng, ngắt của phần cứng, và cỏc hàm khi khởi tạo. Với cỏc con trỏ hàm trong cấu trỳc device, sẽ trỏ đến những hàm thực hiện cỏc cụng việc cần thiết khi giao diện mạng được khởi tạo và hoạt động. Trong cỏc con trỏ hàm đú thỡ hàm

thực hiện việc gửi gúi tin đi đú chớnh là con trỏ dev->hard_start_xmit. Như vậy, ta cú thể thiết lập một hàm gửi dữ liệu mà ta cú thể thực hiện cỏc bước xử lý gúi tin trước khi gửi đi. Cỏc cụng việc khi khởi tạo một giao diện mạng thực hiện ở hàm ipsec_tunnel_init(struct device *dev) trong tệp ipsec_tunnel.c:

int

ipsec_tunnel_init(struct device *dev) {

int i;

. . .

/* Add our tunnel functions to the device */ dev->open = ipsec_tunnel_open; dev->stop = ipsec_tunnel_close;

dev->hard_start_xmit = ipsec_tunnel_start_xmit; dev->get_stats = ipsec_tunnel_get_stats;

. . . dev->set_multicast_list = NULL; dev->set_multicast_list = NULL; dev->do_ioctl = ipsec_tunnel_ioctl; dev->hard_header = NULL; dev->rebuild_header = NULL; dev->set_mac_address = NULL; dev->header_cache_update= NULL; dev->neigh_setup = ipsec_tunnel_neigh_setup_dev; dev->hard_header_len = 0; dev->mtu = 0; dev->addr_len = 0; dev->type = ARPHRD_TUNNEL;

dev->tx_queue_len = 10; /* Small queue */ memset(dev->broadcast,0xFF, ETH_ALEN);

/* New-style flags. */

dev->flags = IFF_NOARP /* 0 */ /* Petr Novak */; dev_init_buffers(dev);

return 0; }

Để đăng ký một card mạng trong nhõn Linux, chỳng ta gọi hàm

register_netdev(struct device *):

Trong hàm ipsec_tunnel_init_devices() ở tệp ipsec_tunnel.c, thực hiện việc

đăng ký card mạng trong nhõn như sau:

static struct device dev_ipsec0 = { “ipsec0\0 “,

...,

ipsec_tunnel_probe };

if (register_netdev(&dev_ipsec0) != 0) /* Gọi hàm register_netdev để đăng ký cạc mạng */

return –EIO;

Khi hàm ipsec_tunnel_init được gọi thỡ trong nhõn sẽ cú một thiết bị mạng ảo

ipsec được đại diện bởi một cấu trỳc device. Khi gúi tin được gửi qua card mạng

ảo ipsec thỡ hàm dev->hard_start_xmit() sẽ thực hiện cỏc cụng việc cần thiết để

gửi gúi tin đi. Theo đú, con trỏ hàm dev->hard_start_xmit() chỉ tới hàm ipsec_tunnel_start_xmit().

Hàm ipsec_tunnel_start_xmit( ) thực hiện cỏc cụng việc mó hoỏ gúi tin, tớnh dữ liệu xỏc thực, bọc thờm địa chỉ IP mới (nếu trong chế độ tunnel) . . . Tuy nhiờn, ở gateway bảo mật dựng IPSEC thỡ khụng phải mọi gúi tin đi qua cạc mạng ảo ipsec

đều được bảo mật mà phải những gúi tin nào thoả món điều kiện địa chỉ IP nguồn

và đớch của nú nằm trong cặp địa chỉ mạng riờng ảo được diện bảo mật. Nếu

khụng thoả món thỡ hàm ipsec_tunnel_start_xmit( ) sẽ khụng thực hiện bất cứ thao tỏc nào đối với những loại gúi tin này.

Đoạn trỡnh xỏc định cú bộ tham số an toàn cho gúi tin hiện tại hay khụng:

/*

* First things first -- look us up in the erouting tables.

*/

matcher.sen_len = sizeof (struct sockaddr_encap); matcher.sen_family = AF_ENCAP;

matcher.sen_type = SENT_IP4;

matcher.sen_ip_src.s_addr = iph->saddr; matcher.sen_ip_dst.s_addr = iph->daddr;

/* Tỡm kiếm bộ tham số an toàn cho gúi tin */

er = ipsec_findroute(&matcher);

if(er) {

outgoing_cnid = er->er_cnid; }

/* Lấy bộ tham số an toàn tương ứng */

spin_lock_irqsave(&tdb_lock, tdb_flags); tdbp = gettdb(&outgoing_cnid);

Một gúi tin IP được mó hoỏ bằng hàm mó khối MK1 trong mode CBC, thỡ phần

đầu của nú cần phải khai bỏo vộc tơ khởi điểm ban đầu. Cựng với nú là cỏc thụng

tin CII (Connection Information Index) khai bỏo gúi tin thuộc connection nào, chỉ số số thứ tự gúi tin gửi đi để chống lại kiểu tấn cụng lặp lại. Chỳng ta cần phải biết

độ dài của cỏc trường này để thực hiện việc cung cấp khoảng trống cho buffer skb. Đoạn trỡnh xỏc định độ dài của cỏc trường:

switch(tdbp->tdb_cnid.proto) { case IPPROTO_ESP:

switch(tdbp->tdb_encalg) { case ESP_BLOCKCIPHER:

headroom += sizeof(struct esp); break;

. . . } }

. . .

}

Nếu trong trường hợp thiết lập tunnel thỡ ở phần đầu của cấu trỳc buffer skb chỳng ta cũn phải dành phần trống cho phần IP header mới thờm vào:

case IPPROTO_IPIP:

headroom += sizeof(struct iphdr); break;

Ở phần cuối của buffer skb, vỡ độ dài gúi tin là bất kỳ, muốn ỏp dụng được hàm

mó khối MK1 ở mode CBC thỡ chỳng ta cần phải thực hiện thờm phần dữ liệu chẵn khối (padding data). Đoạn trỡnh tớnh phần dữ liệu thờm vào cho chẵn khối là:

tailroom += ((BLOCKCIPHER_DATA_SIZE - ((pyldsz + 2 * sizeof(unsigned char)) % BLOCKCIPHER_DATA_SIZE)) % BLOCKCIPHER_DATA_SIZE) + 2;

Mặt khỏc, vỡ dữ liệu xỏc thực gồm 12 byte đặt ở cuối gúi tin nờn chỳng ta cũng cần cung cấp vựng nhớ cho nú:

case AH_MD5:

authlen = AHHMAC_HASHLEN; break;

Tổng độ dài cần cung cấp ở cuối gúi tin bao gồm phần dữ liệu thờm vào chẵn khối và phần dữ liệu xỏc thực:

tailroom += authlen;

Để đảm bảo cho mỗi gúi tin được mó hoỏ và giải mó đỳng. Trỏnh trường hợp

luồng gúi tin đến đớch khụng đỳng thứ tự, hoặc cú sự mất mỏt gúi tin trờn đường truyền sẽ ảnh hưởng đến cỏc gúi tin sau đú. Thỡ ở mỗi gúi tin phải chứa vộc tơ

khởi điểm của gúi tin đú. Đoạn trỡnh thực hiện việc lấy và gỏn vộc tơ khởi điểm

trong hàm ipsec_tunnel_start_xmit() trong tệp ipsec_tunnel.c:

case ESP_BLOCKCIPHER: iv[0] = *((__u32*)&(espp->esp_iv) ) = ((__u32*)(tdbp->tdb_iv))[0]; iv[1] = *((__u32*)&(espp->esp_iv) + 1) = ((__u32*)(tdbp->tdb_iv))[1]; iv[2] = *((__u32*)&(espp->esp_iv) + 2) = ((__u32*)(tdbp->tdb_iv))[2]; iv[3] = *((__u32*)&(espp->esp_iv) + 3) = ((__u32*)(tdbp->tdb_iv))[3];

Trong chương trỡnh chỳng tụi cú sử dụng một trường chứa số thứ tự của gúi tin. Số thứ tự này đỳng chớnh bằng số gúi tin được gửi đi. Việc sử dụng trường số thứ tự này sẽ chống lại được kiểu tấn cụng lặp lại:

espp->esp_rpl = htonl(++(tdbp->tdb_replaywin_lastseq));

Bởi vỡ ở trờn hai gateway cú thể tồn tại nhiều connection khỏc nhau, điều đú cú

nghĩa là cú nhiều gúi tin được bảo mật giữa cỏc cặp mạng ảo khỏc nhau. Ở bờn

nhận, để phõn biệt được connection nào được sử dụng cho gúi tin đến thỡ bờn nhận phải dựa vào chỉ số phõn biệt connection CII. Trờn mỗi gúi tin nú chứa thụng tin về CII để bờn nhận dựa vào CII để nhận bộ tham số an toàn tương ứng cho gúi tin:

espp = (struct esp *)(dat + iphlen); espp->esp_cii = tdbp->tdb_cii;

. . .

Để thờm chẵn khối mó hoỏ đối với gúi tin thỡ chỳng ta đó xỏc định được độ dài cần

thờm vào. Dữ liệu được thờm vào sẽ là 1, 2, 3 . . . Để sang bờn nhận khụi phục lại

độ dài nguyờn bản ban đầu của gúi tin thỡ bờn gửi sẽ phải bỏo độ dài phần dữ liệu

thờm vào:

Đoạn trỡnh thực hiện việc thờm dữ liệu chẵn khối:

padlen = tailroom - 2 - authlen; for (i = 0; i < padlen; i++) {

pad[i] = i + 1; }

Lệnh thực hiện việc bỏo độ dài phần dữ liệu thờm vào:

dat[len - authlen - 2] = padlen;

Sau khi đó hồn tất cỏc cụng việc cần thiết thỡ trỡnh sẽ thực hiện việc gọi hàm để mó hoỏ gúi tin được gửi đi bằng việc gọi hàm blockcipher_cbc_encrypt():

case ESP_BLOCKCIPHER:

blockcipher_cbc_encrypt(idat, idat, ilen,

(caddr_t)(tdbp->tdb_key_e),(caddr_t)iv, 1); break;

Vộc tơ khởi điểm của gúi tin sau sẽ được lấy bằng cỏch cập nhật 16 byte cuối cựng của gúi tin được mó hoỏ trước đú:

switch(tdbp->tdb_encalg) {

case ESP_BLOCKCIPHER:

/* XXX update IV with the last 16 octets of the encryption */ ((__u32*)(tdbp->tdb_iv))[0] = ((__u32 *)(idat))[(ilen >> 2) - 4]; ((__u32*)(tdbp->tdb_iv))[1] = ((__u32 *)(idat))[(ilen >> 2) - 3]; ((__u32*)(tdbp->tdb_iv))[2] =((__u32 *)(idat))[(ilen >> 2) - 2]; ((__u32*)(tdbp->tdb_iv))[3] = ((__u32 *)(idat))[(ilen >> 2) - 1]; break;

Sau khi mó hoỏ gúi tin xong, chương trỡnh sẽ thực hiện việc băm trờn nội dung gúi tin đó được mó để tớnh ra dữ liệu xỏc thực. Hàm băm mật mó được dựng ở đõy là hàm MD5 với mode HMAC, lấy đầu ra 96 bớt (12 byte):

switch(tdbp->tdb_authalg) { case AH_MD5:

tctx.md5 = ((struct md5_ctx*)(tdbp->tdb_key_a))->ictx;

MD5Update(&tctx.md5, (caddr_t)espp, len - iphlen - authlen); MD5Final(hash, &tctx.md5);

tctx.md5 = ((struct md5_ctx*)(tdbp->tdb_key_a))->octx; MD5Update(&tctx.md5, hash, AHMD596_ALEN);

MD5Final(hash, &tctx.md5);

Dữ liệu xỏc thực được đặt vào ở cuối gúi tin sử dụng hàm memcpy():

memcpy(&(dat[len - authlen]), hash, authlen);

Trong chế độ tunnel, gúi tin sau khi đó được mó hoỏ sẽ được bọc thờm một phần IP header mới với địa chỉ nguồn là địa chỉ IP của card mạng ipsec của nú và địa

chỉ đớch là địa chỉ IP của card mạng ipsec của mỏy gateway bảo mật bờn nhận. Đoạn trỡnh thực hiện việc gắn thờm địa chỉ IP:

case IPPROTO_IPIP:

iph->version = 4; /* const should be used here */

iph->tos = skb->nh.iph->tos; /* XXX is this right? */ iph->ttl = 64; /* ip_statistics.IpDefaultTTL; */ iph->frag_off = 0;

iph->saddr = ((struct sockaddr_in*)(tdbp->tdb_addr_s))- >sin_addr.s_addr;

iph->daddr = ((struct sockaddr_in*)(tdbp->tdb_addr_d))- >sin_addr.s_addr;

iph->protocol = IPPROTO_IPIP;

iph->ihl = sizeof(struct iphdr) >> 2 /* 5 */;

iph->id = htons(ip_id_count++); /* Race condition here?*/ newdst = (__u32)iph->daddr;

newsrc = (__u32)iph->saddr; skb->h.ipiph = skb->nh.iph; break;

Sau đú trỡnh sẽ thực hiện việc xỏc định đường đi cho gúi tin bằng cỏch gọi hàm

ip_route_output():

if(ip_route_output(&rt, skb->nh.iph->daddr, skb->nh.iph->saddr, RT_TOS(skb->nh.iph->tos),physdev->iflink)) { stats->tx_errors++;

goto cleanup; }

Gúi tin thực sự được gửi đi bằng hàm ip_send():

ip_send(skb);

stats->tx_packets++;

Một phần của tài liệu đề tài phần mềm bảo mật mạng dùng giao thức ip quyển 4a các phần mềm bảo mật gói ip trên hệ điều hành linux (Trang 115 - 120)