基于openswan klips的IPsec实现分析(十)认证算法维护

基于openswan klips的IPsec实现分析(十)认证算法维护

转载请注明出处:http://blog.csdn.net/rosetta

      这里指的认证算法是ESP使用的,对通信过程中的信息做哈希,用来校验信息的完整性的;协商时的认证算法仅用来做哈希,哈希结果再用来做签名和验签。

    相对于加密算法,认证算法会比较简单些,它也不需要像加密算法一样去构造一个结构体(当然如果需要也是可以这么做的)。

    发送方处理比较简单,主要是由ipsec_xmit_encap_once()对加密后的部分数据做哈希,然后一起发给对方;接收方稍微复杂点,先把发送方已经计算好的那份哈希弄出来,再对密文用同样的哈希算法做哈希,最后比较两个结果。

   详细过程如下分析。

发送方

        发送方就一个函数ipsec_xmit_encap_once()。

ipsec_xmit_encap_once()函数

enum ipsec_xmit_value

ipsec_xmit_encap_once(structipsec_xmit_state *ixs)

{

         printk("infunc:%s\n", "ipsec_xmit_encap_once");

#ifdef CONFIG_KLIPS_ESP

         structesphdr *espp;

         unsignedchar *idat, *pad;

         intauthlen = 0, padlen = 0, i;

#endif /* !CONFIG_KLIPS_ESP */

#ifdef CONFIG_KLIPS_AH

         structiphdr ipo;

         structahhdr *ahp;

#endif /* CONFIG_KLIPS_AH */

#if defined(CONFIG_KLIPS_AUTH_HMAC_MD5) ||defined(CONFIG_KLIPS_AUTH_HMAC_SHA1)

         union{

#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5

                   MD5_CTXmd5;

#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */

#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1

                   SHA1_CTXsha1;

#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */

         }tctx;

         __u8hash[AH_AMAX];

#endif /*defined(CONFIG_KLIPS_AUTH_HMAC_MD5) || defined(CONFIG_KLIPS_AUTH_HMACn_SHA1) */

 

         intheadroom = 0, tailroom = 0, ilen = 0, len = 0;

         unsignedchar *dat;

         intblocksize = 8; /* XXX: should be inside ixs --jjo */

         structipsec_alg_enc *ixt_e = NULL;

         structipsec_alg_auth *ixt_a = NULL;

        

         ixs->iphlen= ixs->iph->ihl << 2;

         ixs->pyldsz= ntohs(ixs->iph->tot_len) - ixs->iphlen;

         ixs->sa_len= satot(&ixs->ipsp->ips_said, 0, ixs->sa_txt, SATOT_BUF);

         KLIPS_PRINT(debug_tunnel& DB_TN_OXFS,

                       "klips_debug:ipsec_xmit_encap_once:"

                       "calling output for <%s%s%s>,SA:%s\n",

                       IPS_XFORM_NAME(ixs->ipsp),

                       ixs->sa_len ? ixs->sa_txt : "(error)");

        

         KLIPS_PRINT(debug_tunnel& DB_TN_OXFS,

                            "klips_debug:plmdebug:"

                            "ixs->ipsp->ips_said.proto:%d\n",

                            ixs->ipsp->ips_said.proto);

 

         //因为此函数(ipsec_xmit_encap_once)的外面是一个while(ixs->ipsp)循环,所以会循环sp链表,

         //最常见的情况是隧道模式(IPIP)+ESP,但这两个的协议号都是放在这个proto中的。

         //所以会进这个函数两次。

         switch(ixs->ipsp->ips_said.proto){

#ifdef CONFIG_KLIPS_AH

                   caseIPPROTO_AH:

                            headroom+= sizeof(struct ahhdr);

                            break;

#endif /* CONFIG_KLIPS_AH */

 

#ifdef CONFIG_KLIPS_ESP

                   caseIPPROTO_ESP://esp协议号50.假如只esp无ah,走这里。

                            //如果还有AH的话,会进这个函数三次。

                            {

                                      //printk("in func:%s,%s\n", __func__, "IPPROTO_ESP");

                                     ixt_e=ixs->ipsp->ips_alg_enc;//包含加密算法函数指针等结构体。--esp时指定的加密算法。

                                     if(ixt_e) {

                                               blocksize= ixt_e->ixt_common.ixt_blocksize;

                                               //比如sm1算法的ixt_blocksize为16,ocs算法为8。

                                               headroom+= ESP_HEADER_LEN + ixt_e->ixt_common.ixt_support.ias_ivlen/8;

                                               //ESP_HEADER_LEN为SPI(4字节)+序列号(4字节)=8字节,最后一个是数据,一般是IV。

                                               //可看pdf版本rfc2406第二节图.

                                               KLIPS_PRINT(debug_tunnel& DB_TN_OXFS,

                                                                 "klips_debug:plmdebug:"

                                                                 "ias_ivlen:%d\n",

                                                                 ixt_e->ixt_common.ixt_support.ias_ivlen

                                                                 );

                                               KLIPS_PRINT(debug_tunnel& DB_TN_OXFS,

                                                                 "klips_debug:plmdebug:"

                                                                 "ias_id:%d,ias_name:%s\n",

                                                                 ixt_e->ixt_common.ixt_support.ias_id,

                                                                 ixt_e->ixt_common.ixt_support.ias_name

                                                                 );

                                               //以esp 3des-md5为例.

                                               //ias_ivlen为64

                                               //isa_id为3(正是3des算法的id)//whack--status 可以查看

                                               //000algorithm ESP encrypt: id=3, name=ESP_3DES, ivlen=64, keysizemin=192,keysizemax=192

                                               //ias_name为NULL,不知道为什么?可能没加到那个名字宏里。

                                     }else {

                                               ixs->stats->tx_errors++;

                                               returnIPSEC_XMIT_ESP_BADALG;

                                     }

 

                                     ixt_a=ixs->ipsp->ips_alg_auth;

                                     if(ixt_a) {

                                               tailroom+= AHHMAC_HASHLEN;

                                     }else

                                     {

                                               //printk("21111111.\n");//走这

                                               switch(ixs->ipsp->ips_authalg){

#ifdef CONFIG_KLIPS_AUTH_HMAC_MD5

                                               caseAH_MD5:

                                                        authlen= AHHMAC_HASHLEN;

                                                        break;

#endif /* CONFIG_KLIPS_AUTH_HMAC_MD5 */

#ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1

                                               caseAH_SHA:

                                                        authlen= AHHMAC_HASHLEN;

                                                        break;

#endif /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */

                                               caseAH_NONE:

                                                        break;

                                               default:

                                                        ixs->stats->tx_errors++;

                                                        returnIPSEC_XMIT_ESP_BADALG;

                                               }                

                                     }

                                     //认证长度12,为什么MD5,SHA1,甚至是SM3的认证长度都为12?

                                     //这个12的依据是?

 

                                     KLIPS_PRINT(debug_tunnel& DB_TN_OXFS,

                                                        "klips_debug:plmdebug:"

                                                        "1,authlen:%d, tailroom:%d\n",

                                                        authlen,tailroom);

 

                                     tailroom+= blocksize != 1 ?

                                               ((blocksize- ((ixs->pyldsz + 2) % blocksize)) % blocksize) + 2 :

                                               ((4- ((ixs->pyldsz + 2) % 4)) % 4) + 2;

                                     tailroom+= authlen;

                                     //这个应该根据rfc2406进行填充?

 

                                     KLIPS_PRINT(debug_tunnel& DB_TN_OXFS,

                                                        "klips_debug:plmdebug:"

                                                        "2,authlen:%d, tailroom:%d\n",

                                                        authlen,tailroom);

                            }

                            break;

#endif /* CONFIG_KLIPS_ESP */

 

#ifdef CONFIG_KLIPS_IPIP

                   caseIPPROTO_IPIP://什么时候用IPIP?隧道模式,这里只是分配了下空间。

                            headroom+= sizeof(struct iphdr);

                            ixs->iphlen= sizeof(struct iphdr);

                            break;

#endif /* !CONFIG_KLIPS_IPIP */

 

#ifdef CONFIG_KLIPS_IPCOMP

                   caseIPPROTO_COMP://压缩?

                            break;

#endif /* CONFIG_KLIPS_IPCOMP */

 

                   default:

                            ixs->stats->tx_errors++;

                            returnIPSEC_XMIT_BADPROTO;

         }

        

         KLIPS_PRINT(debug_tunnel& DB_TN_CROUT,

                       "klips_debug:ipsec_xmit_encap_once:"

                       "pushing %d bytes, putting %d, proto%d.\n",

                       headroom, tailroom,ixs->ipsp->ips_said.proto);

 

         if(skb_headroom(ixs->skb)< headroom) {

                   printk(KERN_WARNING

                          "klips_error:ipsec_xmit_encap_once:"

                          "tried to skb_push headroom=%d, %davailable.  This should never happen,please report.\n",

                          headroom, skb_headroom(ixs->skb));

                   ixs->stats->tx_errors++;

                   returnIPSEC_XMIT_ESP_PUSHPULLERR;

         }

 

         //skb头部预留headroom字节空间。

         dat= skb_push(ixs->skb, headroom);

         ilen= ixs->skb->len - tailroom;

 

         if(skb_tailroom(ixs->skb)< tailroom) {

                   printk(KERN_WARNING

                          "klips_error:ipsec_xmit_encap_once:"

                          "tried to skb_put %d, %davailable.  This should never happen,please report.\n",

                          tailroom, skb_tailroom(ixs->skb));

                   ixs->stats->tx_errors++;

                   returnIPSEC_XMIT_ESP_PUSHPULLERR;

         }

         //skb尾部预留tailroom字节空间。

         skb_put(ixs->skb,tailroom);

         KLIPS_PRINT(debug_tunnel& DB_TN_CROUT,

                       "klips_debug:ipsec_xmit_encap_once:"

                       "head,tailroom: %d,%d beforexform.\n",

                       skb_headroom(ixs->skb),skb_tailroom(ixs->skb));

         len= ixs->skb->len;

         if(len> 0xfff0) {

                   printk(KERN_WARNING"klips_error:ipsec_xmit_encap_once: "

                          "tot_len (%d) > 65520.  This should never happen, pleasereport.\n",

                          len);

                   ixs->stats->tx_errors++;

                   returnIPSEC_XMIT_BADLEN;

         }

 

         memmove((void*)dat, (void *)(dat + headroom), ixs->iphlen);

         ixs->iph= (struct iphdr *)dat;

         ixs->iph->tot_len= htons(ixs->skb->len);

         //不懂?//虽然没怎么看明白,在IPIP模式下,即隧道模式,这里的目的猜是在ESP包前面加一个原始IP头。

         //这里仅仅是加了空间,具体的赋值在下面操作。

 

         switch(ixs->ipsp->ips_said.proto){

#ifdef CONFIG_KLIPS_ESP

         caseIPPROTO_ESP:

                   espp= (struct esphdr *)(dat + ixs->iphlen);//dat是之前IPIP时加的IP原始头指针。

                   //此时再加一个IP长度,那么这个位置espp就是放ESP头的位置。

                   espp->esp_spi= ixs->ipsp->ips_said.spi;

                   espp->esp_rpl= htonl(++(ixs->ipsp->ips_replaywin_lastseq));

                  

                   if(!ixt_e) {

                            ixs->stats->tx_errors++;

                            returnIPSEC_XMIT_ESP_BADALG;

                   }

                  

                   idat= dat + ixs->iphlen + headroom;

                   ilen= len - (ixs->iphlen + headroom + authlen);

                  

                   /*Self-describing padding */

                   pad= &dat[len - tailroom];

                   padlen= tailroom - 2 - authlen;

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

                            pad[i]= i + 1;

                   }

                   dat[len- authlen - 2] = padlen;

                  

                   dat[len- authlen - 1] = ixs->iph->protocol;

                   ixs->iph->protocol= IPPROTO_ESP;

 

                   //以上这段操作没怎么看懂。对需要加密/认证的数据进行数据补齐。

#ifdef CONFIG_KLIPS_DEBUG

                   if(debug_tunnel& DB_TN_ENCAP) {

                           dmp("pre-encrypt", dat,len);//最终需要加密的数据在dat里。

                   }

#endif

 

                   /*

                    * Do all operations here:

                    * copy IV->ESP, encrypt, update ips IV

                    *

                    */

                   {

                            intret;

                            memcpy(espp->esp_iv,

                                   ixs->ipsp->ips_iv,

                                   ixs->ipsp->ips_iv_size);

 

                   
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值