1. 程式人生 > >Linux裝置上的Onvif實現17:實現RTSP摘要認證

Linux裝置上的Onvif實現17:實現RTSP摘要認證

1 RTSP協議中定義了兩種認證方法,基本認證(basic authentication),摘要認證(digest authentication)。基本認證是http1.0提出的認證方案,其密碼傳輸的加密演算法(base64)是可逆演算法,很容易被截獲破解。摘要認證是http1.1提出的替代方案,其密碼經過MD5雜湊轉換因此具有更高的安全性。 本文只介紹摘要認證。

3 先看一段抓包下來的正確的摘要認證訊息。示例中的使用者名稱是“admin”,密碼是“admin”。

//預設無認證----------------------------
DESCRIBE rtsp://192.168.0.112:540/live/h264_ulaw/VGA RTSP/1.0
CSeq: 6
User-Agent: LibVLC/1.1.11 (LIVE555 Streaming Media v2011.05.25)
Accept: application/sdp

RTSP/1.0 401 Unauthorized
CSeq: 6
WWW-Authenticate: Basic realm="Server"
WWW-Authenticate: Digest realm="Server", nonce="52bb051ecad61e78d67664700e67407ad865c429bde208b7ea1e6e22aa7d8ccf"

//使用摘要認證----------------------------
DESCRIBE rtsp://192.168.0.112:540/live/h264_ulaw/VGA RTSP/1.0
CSeq: 7
Authorization: Digest username="admin", realm="Server", nonce="52bb051ecad61e78d67664700e67407ad865c429bde208b7ea1e6e22aa7d8ccf", uri="rtsp://192.168.0.112:540/live/h264_ulaw/VGA", response="1ac6f141f4c740ba54088914941f094f"
User-Agent: LibVLC/1.1.11 (LIVE555 Streaming Media v2011.05.25)
Accept: application/sdp

RTSP/1.0 200 OK
CSeq: 7
Content-Base: rtsp://192.168.0.112:540/live/h264_ulaw/VGA/
Content-Type: application/sdp
Cache-Control: must-revalidate
x-Accept-Dynamic-Rate: 1
Content-Length: 305
sdp內容略過

//建立視訊通道連線----------------------------
SETUP rtsp://192.168.0.112:540/live/h264_ulaw/VGA/track1 RTSP/1.0
CSeq: 8
Authorization: Digest username="admin", realm="Server", nonce="52bb051ecad61e78d67664700e67407ad865c429bde208b7ea1e6e22aa7d8ccf", uri="rtsp://192.168.0.112:540/live/h264_ulaw/VGA/", response="ff71e2de4489997fa2fd058462ca48df"
User-Agent: LibVLC/1.1.11 (LIVE555 Streaming Media v2011.05.25)
Transport: RTP/AVP;unicast;client_port=57704-57705

RTSP/1.0 200 OK
CSeq: 8
Transport: RTP/AVP;unicast;client_port=57704-57705;server_port=59024-59025
x-dynamic-rate: 1
Session: D694FB02673D8FFC816E78EB384E09

//建立音訊通道連線----------------------------
SETUP rtsp://192.168.0.112:540/live/h264_ulaw/VGA/track3 RTSP/1.0
CSeq: 9
Authorization: Digest username="admin", realm="Server", nonce="52bb051ecad61e78d67664700e67407ad865c429bde208b7ea1e6e22aa7d8ccf", uri="rtsp://192.168.0.112:540/live/h264_ulaw/VGA/", response="ff71e2de4489997fa2fd058462ca48df"
User-Agent: LibVLC/1.1.11 (LIVE555 Streaming Media v2011.05.25)
Transport: RTP/AVP;unicast;client_port=57706-57707
Session: D694FB02673D8FFC816E78EB384E09

RTSP/1.0 200 OK
CSeq: 9
Transport: RTP/AVP;unicast;client_port=57706-57707;server_port=53570-53571
x-dynamic-rate: 1
Session: D694FB02673D8FFC816E78EB384E09

//----------------------------
PLAY rtsp://192.168.0.112:540/live/h264_ulaw/VGA/ RTSP/1.0
CSeq: 10
Authorization: Digest username="admin", realm="Server", nonce="52bb051ecad61e78d67664700e67407ad865c429bde208b7ea1e6e22aa7d8ccf", uri="rtsp://192.168.0.112:540/live/h264_ulaw/VGA/", response="a0187b5bb73d8cfaedab47365b0b8848"
User-Agent: LibVLC/1.1.11 (LIVE555 Streaming Media v2011.05.25)
Session: D694FB02673D8FFC816E78EB384E09
Range: npt=0.000-

RTSP/1.0 200 OK
CSeq: 10
Session: D694FB02673D8FFC816E78EB384E09
Range: npt=now-
RTP-Info: url=rtsp://192.168.0.112:540/live/h264_ulaw/VGA//track1;seq=52039;rtptime=3232015484,url=rtsp://192.168.0.112:540/live/h264_ulaw/VGA//track3;seq=36501;rtptime=34449408


//----------------------------
TEARDOWN rtsp://192.168.0.112:540/live/h264_ulaw/VGA/ RTSP/1.0
CSeq: 12
Authorization: Digest username="admin", realm="Server", nonce="52bb051ecad61e78d67664700e67407ad865c429bde208b7ea1e6e22aa7d8ccf", uri="rtsp://192.168.0.112:540/live/h264_ulaw/VGA/", response="41ca24c00f22e5175df3b3666f6f3ead"
User-Agent: LibVLC/1.1.11 (LIVE555 Streaming Media v2011.05.25)
Session: D694FB02673D8FFC816E78EB384E09

RTSP/1.0 200 OK
CSeq: 12
Session: D694FB02673D8FFC816E78EB384E09

4 RFC2617中的標準計算方法
  在RFC2617中給出了標準的計算方法程式碼,在檔案digtest.c中預定義了以下引數:
void main(int argc, char ** argv)
{
    char * pszNonce = "52bb051ecad61e78d67664700e67407ad865c429bde208b7ea1e6e22aa7d8ccf";
    char * pszCNonce = "";
    char * pszUser = "admin";
    char * pszRealm = "Server";
    char * pszPass = "admin";
    char * pszAlg = "md5";
    char szNonceCount[9] = "00000001";
    char * pszMethod = "GET";
    char * pszQop = "auth";
    char * pszURI = "rtsp://192.168.0.112:540/live/h264_ulaw/VGA/";
    HASHHEX HA1;
    HASHHEX HA2 = "";
    HASHHEX Response;
   
    DigestCalcHA1(pszAlg, pszUser, pszRealm, pszPass, pszNonce, pszCNonce, HA1);
    DigestCalcResponse(HA1, pszNonce, szNonceCount, pszCNonce, pszQop, pszMethod, pszURI, HA2, Response);
    printf("00 Response = %s\n", Response);

這是非常標準的計算過程,但是用此計算不出上面示例中的response。

5 經過試驗發現RTSP中採用了簡化演算法,實際的計算過程如下:
HA1 = MD5(username:realm:password)
HA2 = MD5(method:uri)
response = MD5(HA1:nonce:HA2)

method不能是http規範中的GET、POST,而是這條RTSP命令的名稱,例如:DESCRIBE、SETUP、PLAY、TEARDOWN。
uri一般是RTSP命令的url。
    在上述示例中,建立視訊、音訊通道命令中的url不同,但是uri相同,導致計算出的摘要完全相同,這說明客戶端計算方法有些不妥。

6 簡化的計算函式如下:
void NewDigestCalcHA1(char * pszUserName, char * pszRealm, char * pszPassword, HASHHEX SessionKey)
{
      MD5_CTX Md5Ctx;
      HASH HA1;
      MD5Init(&Md5Ctx);
      MD5Update(&Md5Ctx, pszUserName, strlen(pszUserName));
      MD5Update(&Md5Ctx, ":", 1);
      MD5Update(&Md5Ctx, pszRealm, strlen(pszRealm));
      MD5Update(&Md5Ctx, ":", 1);
      MD5Update(&Md5Ctx, pszPassword, strlen(pszPassword));
      MD5Final(HA1, &Md5Ctx);
     
      CvtHex(HA1, SessionKey);
}

void NewDigestCalcResponse(
    IN HASHHEX HA1,           /* H(A1) */
    IN char * pszNonce,       /* nonce from server */
    IN char * pszDigestUri,   /* requested URL */
    IN char * pszMethod,      /* requested method */
    OUT HASHHEX Response      /* request-digest or response-digest */
    )
{
    MD5_CTX Md5Ctx;
    HASH HA2;
    HASH RespHash;
    HASHHEX HA2Hex;
   
    // calculate H(A2)
    MD5Init(&Md5Ctx);
    MD5Update(&Md5Ctx, pszMethod, strlen(pszMethod));
    MD5Update(&Md5Ctx, ":", 1);
    MD5Update(&Md5Ctx, pszDigestUri, strlen(pszDigestUri));   
    MD5Final(HA2, &Md5Ctx);
    CvtHex(HA2, HA2Hex);
    printf("11 HA2Hex= %s\n", HA2Hex);

    // calculate response
    MD5Init(&Md5Ctx);
    MD5Update(&Md5Ctx, HA1, HASHHEXLEN);
    MD5Update(&Md5Ctx, ":", 1);
    MD5Update(&Md5Ctx, pszNonce, strlen(pszNonce));
    MD5Update(&Md5Ctx, ":", 1);   
    MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN);
    MD5Final(RespHash, &Md5Ctx);
    CvtHex(RespHash, Response);   
}

void main(int argc, char ** argv)
{
    char * pszNonce = "52bb051ecad61e78d67664700e67407ad865c429bde208b7ea1e6e22aa7d8ccf";
    char * pszUser = "admin";
    char * pszRealm = "Server";
    char * pszPass = "admin";
    char * pszMethod = "PLAY";
    char * pszURI = "rtsp://192.168.0.112:540/live/h264_ulaw/VGA/";
    HASHHEX HA1;
    HASHHEX HA2 = "";
    HASHHEX Response;
   
    NewDigestCalcHA1(pszUser, pszRealm, pszPass, HA1);
    printf("11 HA1= %s\n", HA1);
    NewDigestCalcResponse(HA1, pszNonce, pszURI, pszMethod, Response);
    printf("11 Response2 = %s\n", Response);
};

對於PLAY命令執行資料如下:與上面的結果相同。
11 HA1= 28741c6548e7c36bb42560990c84be58
11 HA2Hex= 05e91f857dfec84b76883702bffb2426
11 Response2 = a0187b5bb73d8cfaedab47365b0b8848