当前位置:   article > 正文

【rtsp client取海康IPC H264视频流】——摘要认证_hik device gateway 摘要认证

hik device gateway 摘要认证

        当我们下发DESCRIBE方法获取sdp数据的时候,神奇的一幕出现了。

DESCRIBE rtsp://192.168.1.65:554/cam/realmonitor?channel=1&subtype=0 RTSP/1.0

CSeq: 3

User-Agent: LibVLC/3.0.16 (LIVE555 Streaming Media v2016.11.28)

Accept: application/sdp

RTSP/1.0 401 Unauthorized

CSeq: 3

WWW-Authenticate: Digest realm="IP Camera(G8735)", nonce="251223aed58c9ed59d99e14dc6215ae1", stale="FALSE"

Date: Fri, Jun 24 2022 14:42:01 GMT

        401 未认证,既然server大佬说了要认证,那作为client的小弟,就按部就班的进行认证,可以看出server大佬告诉了小弟,认证方法和一些参数,其中认证方式采用摘要认证(Digest),realm为“IP Camera(G8735)”,nonce为251223aed58c9ed59d99e14dc6215ae1。

        在进行认证之前先了解一下摘要认证。如下图所示,当发送POST请求的时候,服务器返回401 Unauthorized,并且返回信息头中WWW-Authenticate:中包含了认证方式以及认证信息,其中:

realm:领域

nonce:这是由服务器规定的数据字符串,每次请求的时候这个参数都不一样,服务器根据自己的规则生成的。

qop:一般可以为“auth” “auth-int” 或者这个字段可以缺少,也就是服务器可以不返回。

algorithm:计算算法,如:MD5

算法

A1

MD5

A1 =MD5(<user>:<realm>:<password>

MD5-sess

A1 = MD5(<usr>:<realm>:<password>):<nonce>:<cnonce>

qop

A2

未定义

MD5(<request-method>:<uri-directive-value>)

auth

MD5(<request-method>:<uri-directive-value>)

auth-int

MD5(<request-method>:<uri-directive-value>:H(<reuest-entity-body>))

qop

摘要计算

未定义

MD5(<A1>:<nonce>:<A2>)

auth

MD5(<A1>:<nonce>:<nc>:<cnonce>:<qop>:<A2>)

 根据上述计算摘要步骤,我们一步一步进行计算,

首先根据Algorithm=“MD5”,如果服务器返回的该字段缺少,则依旧采用MD5,此时我们计算A1,A1=MD5(<user>:<realm>:<password>)

user:admin   realm:example.com   password:admin123456

A1=MD5(admin:example.com:admin123456)  

A1=01584afdc23b82c514d4a6368c3b9530

由于server返回qop="auth",因此这里A2的计算方式根据上面公式可以得到

A2=MD5(<request-method>:<uri-directive-value>)

其中request-method表示请求的方法,这里请求的方法为POST

uri-directive-value表示请求uri跳转值,这里为/test_api/user/login

A2=MD5(POST:/test_api/user/login)

A2=0168a093f66f599ef4930de5b537a377

好了到此我们需要计算出摘要,也就是请求中的response带的参数

        摘要计算是根据qop的值而不同,当qop为定义的时候,也就是server返回401的时候没有带qop参数,此时采用MD5(<A1>:<nonce>:<A2>) 而qop带参数的时候如"auth"或者"auth-int"的时候摘要计算方式为MD5(<A1>:<nonce>:<nc>:<cnonce>:<qop>:<A2>)

        这里nc是一个计数器,累加,用一个十六进制8位的字符串表示,如demo中的00000001,cnonce是客户端生成的一个随机字符。

response=MD5(<A1>:<nonce>:<nc>:<cnonce>:<qop>:<A2>)

response=MD5(01584afdc23b82c514d4a6368c3b9530:ZXhhbXBsZS5jb206NTBmYTYyMzU6NA==:00000001:5cqIUuPK:auth:0168a093f66f599ef4930de5b537a377)

response=e9b7e9780568c90c6011e1980013542f

至此我们的摘要计算完成。

代码也是通过一步一步实现摘要计算,通过先计算A1,A2,最后再计算摘要

A1的计算方式:

  1. static void md5_A1(char A1[33],const char *algorithm,const char *usr,const char *pwd,const char *realm,const char *nonce,const char *cnonce)
  2. {
  3. //A1 = <user>:<realm>:<password>
  4. //md5(A1)
  5. MD5_CTX ctx;
  6. unsigned char md5[16];
  7. MD5_Init(&ctx);
  8. MD5_Update(&ctx,(unsigned char*)usr,(unsigned int)strlen(usr));
  9. MD5_Update(&ctx,(unsigned char*)":",1);
  10. MD5_Update(&ctx,(unsigned char*)realm,(unsigned int)strlen(realm));
  11. MD5_Update(&ctx,(unsigned char*)":",1);
  12. MD5_Update(&ctx,(unsigned char*)pwd,(unsigned int)strlen(pwd));
  13. MD5_Final(md5,&ctx);
  14. base16(A1,md5,16);
  15. }

A2的计算方式:

  1. static void md5_A2(char A2[33],const char *method,const char *uri,const char *qop)
  2. {
  3. //A2=<request-method>:<url-directive-value>
  4. //md5(A2)
  5. MD5_CTX ctx;
  6. unsigned char md5[16];
  7. MD5_Init(&ctx);
  8. MD5_Update(&ctx,(unsigned char*)method,(unsigned int)strlen(method));
  9. MD5_Update(&ctx,(unsigned char*)":",1);
  10. MD5_Update(&ctx,(unsigned char*)uri,(unsigned int)strlen(uri));
  11. if(0 == strcmp(qop,"auth-int")){
  12. //TODO
  13. }
  14. MD5_Final(md5,&ctx);
  15. base16(A2,md5,16);
  16. }

response计算(摘要):

  1. static void md5_response(char *response,const char *A1,const char *A2,const char *nonce,int nc,const char *cnonce,const char *qop)
  2. {
  3. //MD5(MD5(A1):<nonce>:<nc>:<conce>:<qop>:MD5(A2))
  4. MD5_CTX ctx;
  5. unsigned char md5[16];
  6. char hex[32];
  7. memset(hex,0x00,sizeof(hex));
  8. MD5_Init(&ctx);
  9. MD5_Update(&ctx,(unsigned char*)A1,32);
  10. MD5_Update(&ctx,(unsigned char*)":",1);
  11. MD5_Update(&ctx,(unsigned char*)nonce,(unsigned int)strlen(nonce));
  12. MD5_Update(&ctx,(unsigned char*)":",1);
  13. if(*qop){
  14. snprintf(hex,sizeof(hex),"%08x",nc);
  15. MD5_Update(&ctx,(unsigned char*)hex,(unsigned int)strlen(hex));
  16. MD5_Update(&ctx,(unsigned char*)":",1);
  17. MD5_Update(&ctx,(unsigned char*)cnonce,(unsigned int)strlen(cnonce));
  18. MD5_Update(&ctx,(unsigned char*)":",1);
  19. MD5_Update(&ctx,(unsigned char*)qop,(unsigned int)strlen(qop));
  20. MD5_Update(&ctx,(unsigned char*)":",1);
  21. }
  22. MD5_Update(&ctx,(unsigned char*)A2,32);
  23. MD5_Final(md5,&ctx);
  24. base16(response,md5,16);
  25. }
  1. static void base16(char* str, const uint8_t* data, int bytes)
  2. {
  3. int i;
  4. const char hex[] = "0123456789abcdef";
  5. for (i = 0; i < bytes; i++)
  6. {
  7. str[i * 2] = hex[data[i] >> 4];
  8. str[i * 2 + 1] = hex[data[i] & 0xF];
  9. }
  10. str[bytes * 2] = 0;
  11. }

然后在封装RTSP协议中的认证字段,也就是Authorization响应头。

  1. int http_header_auth(struct http_www_authenticate_t *auth,char *pwd,char *method)
  2. {
  3. char A1[33];
  4. char A2[33];
  5. memset(A1,0x00,sizeof(A1));
  6. memset(A2,0x00,sizeof(A2));
  7. //根据信息计算出respone
  8. if(NULL == auth){
  9. return -1;
  10. }
  11. printf("auth->cnonce is %s\n",auth->cnonce);
  12. //nc+1
  13. auth->nc += 1;
  14. if(auth->scheme == HTTP_AUTH_DIGEST){
  15. md5_A1(A1,auth->algorithm,auth->username,pwd,auth->realm,auth->nonce,auth->cnonce);
  16. md5_A2(A2,method,auth->uri,auth->qop);
  17. md5_response(auth->response,A1,A2,auth->nonce,auth->nc,auth->cnonce,auth->qop);
  18. return 0;
  19. }
  20. return -1;
  21. }
  1. int digest_auth_authorization(struct http_www_authenticate_t *auth,char *pwd,char *method,char *auth_buf,int auth_buf_size)
  2. {
  3. if(NULL == auth || NULL == pwd || NULL == method || NULL == auth_buf)
  4. {
  5. return -1;
  6. }
  7. if(http_header_auth(auth,pwd,method) < 0){
  8. return -1;
  9. }
  10. snprintf(auth_buf,auth_buf_size,"Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"",
  11. auth->username,auth->realm,auth->nonce,auth->uri,auth->response);
  12. return 0;
  13. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/186429
推荐阅读
相关标签
  

闽ICP备14008679号