SNMPv3协议具体参数说明和代码

说明:对于snmpv3报文分为四个部分,版本号+全局数据+USM+ScopedPDU,其中的每个参数其实在RFC341X系列文档都是有说明的,但是有人可能不想找,我收集了一下,在下面展示。

目前使用的环境

stm32f407VET6+freertos9.0.0+lwip1.4.1+iReasoning MIB Broswer专业版+WireShark抓包软件

准备工作:使用freertos任务执行lwip的udp_socket,可进行ip地址修改

实现结果展示:可进行SNMPV3的所有PDU类型操作

MIB软件如下:

WireShark软件如下:

数据交互过程中会通过认证算法和加密算法对数据进行处理,使用的是HMAC_SHA1认证算法,底层使用的是SHA1算法实现,使用的是HMAC_DES_CBC加密算法,底层使用的DES_CBC算法实现,前后端使用的认证和加密算法必须一样,不然无法解析,选择什么算法实现,好像是RFC3414 和 RFC2103这两个文档最末尾有说明和源代码,同时iReasoning MIB Broswer专业版可进行配置,如下所示:

如下是部分重要操作的截图:

walk:

set:

具体说明GET/SET/GET-NEXT-REQUEST报文的流程:

首先对于iReasoning软件,发起这些GET/SET/GET-NEXT-REQUEST请求,都会先发起无认证加密的GET请求,向我的udp服务器获取USM的三个数据,服务器响应0xa8 Report请求

snmp.EnginedID:是前后端商量的,自己可以设置一个专属于自己的,同时它是唯一标识你的SNMPV3报文的,这个东西很重要,也是生成你的认证key和加密key的关键参数之一,就是下面这两种key,是由你的认证密码/加密密码+工程ID通过你选择的认证算法进行生成,具体代码在下面。

snmp.EnginedBOOT和snmp.EnginedTime是为了防止重攻击的,在客户端第一次发起GET请求向服务端获取USM参数时,由服务端上传给MIB软件,并且在整个snmp报文PDU类型交互中都是一样的。

snmp.msgAuthenticationParameters:认证参数,对整个snmp报文进行认证,认证算法使用HMAC_SHA1或者HMAC_MD5分别生成20字节或者16字节的认证参数,将其填入,注意哈!进行认证的时候,你的snmp报文的这个参数全部为0,认证完成后,将前12字节填入即可。

snmp.msgPrivacyParameters:加密/隐私参数,用于加密使用。数据值为8字节的随机数,与PrivKey生成IV,主要用于DES_CBC加密参数使用

以下是RFC文档中涉及的算法:

RFC 2104: HMAC: Keyed-Hashing for Message Authentication

/*
** Function: hmac_md5
*/

void
hmac_md5(text, text_len, key, key_len, digest)
unsigned char*  text;                /* pointer to data stream */
int             text_len;            /* length of data stream */
unsigned char*  key;                 /* pointer to authentication key */
int             key_len;             /* length of authentication key */
caddr_t         digest;              /* caller digest to be filled in */

{
        MD5_CTX context;
        unsigned char k_ipad[65];    /* inner padding -
                                      * key XORd with ipad
                                      */
        unsigned char k_opad[65];    /* outer padding -
                                      * key XORd with opad
                                      */
        unsigned char tk[16];
        int i;
        /* if key is longer than 64 bytes reset it to key=MD5(key) */
        if (key_len > 64) {

                MD5_CTX      tctx;

                MD5Init(&tctx);
                MD5Update(&tctx, key, key_len);
                MD5Final(tk, &tctx);

                key = tk;
                key_len = 16;
        }

        /*
         * the HMAC_MD5 transform looks like:
         *
         * MD5(K XOR opad, MD5(K XOR ipad, text))
         *
         * where K is an n byte key
         * ipad is the byte 0x36 repeated 64 times



Krawczyk, et. al.            Informational                      [Page 8]

RFC 2104                          HMAC                     February 1997


         * opad is the byte 0x5c repeated 64 times
         * and text is the data being protected
         */

        /* start out by storing key in pads */
        bzero( k_ipad, sizeof k_ipad);
        bzero( k_opad, sizeof k_opad);
        bcopy( key, k_ipad, key_len);
        bcopy( key, k_opad, key_len);

        /* XOR key with ipad and opad values */
        for (i=0; i<64; i++) {
                k_ipad[i] ^= 0x36;
                k_opad[i] ^= 0x5c;
        }
        /*
         * perform inner MD5
         */
        MD5Init(&context);                   /* init context for 1st
                                              * pass */
        MD5Update(&context, k_ipad, 64)      /* start with inner pad */
        MD5Update(&context, text, text_len); /* then text of datagram */
        MD5Final(digest, &context);          /* finish up 1st pass */
        /*
         * perform outer MD5
         */
        MD5Init(&context);                   /* init context for 2nd
                                              * pass */
        MD5Update(&context, k_opad, 64);     /* start with outer pad */
        MD5Update(&context, digest, 16);     /* then results of 1st
                                              * hash */
        MD5Final(digest, &context);          /* finish up 2nd pass */
}

RFC 3414: User-based Security Model (USM) for version 3 of the Simple Network Management Protocol (SNMPv3)

////通过md5生成key
void password_to_key_md5(
      u_char *password,    /* IN */
      u_int   passwordlen, /* IN */
      u_char *engineID,    /* IN  - pointer to snmpEngineID  */
      u_int   engineLength,/* IN  - length of snmpEngineID */
      u_char *key)         /* OUT - pointer to caller 16-octet buffer */
   {
      MD5_CTX     MD;
      u_char     *cp, password_buf[64];
      u_long      password_index = 0;
      u_long      count = 0, i;

      MD5Init (&MD);   /* initialize MD5 */

      /**********************************************/
      /* Use while loop until we've done 1 Megabyte */
      /**********************************************/
      while (count < 1048576) {
         cp = password_buf;
         for (i = 0; i < 64; i++) {
             /*************************************************/
             /* Take the next octet of the password, wrapping */
             /* to the beginning of the password as necessary.*/
             /*************************************************/
             *cp++ = password[password_index++ % passwordlen];
         }
         MD5Update (&MD, password_buf, 64);
         count += 64;
      }
      MD5Final (key, &MD);          /* tell MD5 we're done */

      /*****************************************************/
      /* Now localize the key with the engineID and pass   */
      /* through MD5 to produce final key                  */
      /* May want to ensure that engineLength <= 32,       */
      /* otherwise need to use a buffer larger than 64     */
      /*****************************************************/
      memcpy(password_buf, key, 16);
      memcpy(password_buf+16, engineID, engineLength);
      memcpy(password_buf+16+engineLength, key, 16);

      MD5Init(&MD);
      MD5Update(&MD, password_buf, 32+engineLength);
      MD5Final(key, &MD);
      return;
   }
//通过sha1生成key

 void password_to_key_sha(
      u_char *password,    /* IN */
      u_int   passwordlen, /* IN */
      u_char *engineID,    /* IN  - pointer to snmpEngineID  */
      u_int   engineLength,/* IN  - length of snmpEngineID */
      u_char *key)         /* OUT - pointer to caller 20-octet buffer */
   {
      SHA_CTX     SH;
      u_char     *cp, password_buf[72];
      u_long      password_index = 0;
      u_long      count = 0, i;

      SHAInit (&SH);   /* initialize SHA */

      /**********************************************/
      /* Use while loop until we've done 1 Megabyte */
      /**********************************************/
      while (count < 1048576) {
         cp = password_buf;
         for (i = 0; i < 64; i++) {
             /*************************************************/
             /* Take the next octet of the password, wrapping */
             /* to the beginning of the password as necessary.*/
             /*************************************************/
             *cp++ = password[password_index++ % passwordlen];
         }
         SHAUpdate (&SH, password_buf, 64);
         count += 64;
      }
      SHAFinal (key, &SH);          /* tell SHA we're done */

      /*****************************************************/
      /* Now localize the key with the engineID and pass   */
      /* through SHA to produce final key                  */
      /* May want to ensure that engineLength <= 32,       */
      /* otherwise need to use a buffer larger than 72     */
      /*****************************************************/
      memcpy(password_buf, key, 20);
      memcpy(password_buf+20, engineID, engineLength);
      memcpy(password_buf+20+engineLength, key, 20);

      SHAInit(&SH);
      SHAUpdate(&SH, password_buf, 40+engineLength);
      SHAFinal(key, &SH);
      return;
   }
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值