RTMP complex handshake,變更的握手,支持h264/aac
當(dāng)服務(wù)器和客戶(hù)端的握手是按照rtmp協(xié)議進(jìn)行,是不支持h264/aac的,有數(shù)據(jù),就是沒(méi)有視頻和聲音。
原因是adobe變更了握手的數(shù)據(jù)結(jié)構(gòu),標(biāo)準(zhǔn)rtmp協(xié)議的握手的包是隨機(jī)的1536字節(jié)(S1S2C1C2),變更后的是需要進(jìn)行摘要和加密。
rtmp協(xié)議定義的為simple handshake,變更后加密握手可稱(chēng)為complex handshake。
本文詳細(xì)分析了rtmpd(ccrtmpserver)中的處理邏輯,以及rtmpdump的處理邏輯,從一個(gè)全是魔法數(shù)字的世界找到他們的數(shù)據(jù)結(jié)構(gòu)和算法。
complex handshake C1S1結(jié)構(gòu)complex handshake將C1S1分為4個(gè)部分,它們的順序(schema)一種可能是:
[plain]view plaincopy //c1s1schema0 time:4bytes version:4bytes key:764bytes digest:764bytes 其中,key和digest可能會(huì)交換位置,即schema可能是:
[plain]view plaincopy //c1s1schema1 time:4bytes version:4bytes digest:764bytes key:764bytes
客戶(hù)端來(lái)決定使用哪種schema,服務(wù)器端則需要先嘗試按照schema0解析,失敗則用schema1解析。如下圖所示:
無(wú)論key和digest位置如何,它們的結(jié)構(gòu)是不變的:
[plain]view plaincopy //764byteskey結(jié)構(gòu) random-data:(offset)bytes key-data:128bytes random-data:(764-offset-128-4)bytes offset:4bytes //764bytesdigest結(jié)構(gòu) offset:4bytes random-data:(offset)bytes digest-data:32bytes random-data:(764-4-offset-32)bytes 備注:發(fā)現(xiàn)FMS只認(rèn)識(shí)digest-key結(jié)構(gòu)。
如下圖所示:
crtmp中這些全是魔法數(shù)字。
C2S2主要是提供對(duì)C1S1的驗(yàn)證。結(jié)構(gòu)如下:
[plain]view plaincopy //1536bytesC2S2結(jié)構(gòu) random-data:1504bytes digest-data:32bytes
C2S2的結(jié)構(gòu)相對(duì)比較簡(jiǎn)單。如下圖所示:
下面介紹C1S1C2S2的生成以及驗(yàn)證算法。
complex handshake C1S1算法C1S1中都是包含32字節(jié)的digest,而且digest將C1S1分成兩部分:
[plain]view plaincopy //C1S1被digest分成兩部分 c1s1-part1:nbytes digest-data:32bytes c1s1-part2:(1536-n-32)bytes
如下圖所示:
在生成C1時(shí),需要用到c1s1-part1和c1s1-part2這兩個(gè)部分的字節(jié)拼接起來(lái)的字節(jié),定義為:
[plain]view plaincopy c1s1-joined=bytes_join(c1s1-part1,c1s1-part2)
也就是說(shuō),把1536字節(jié)的c1s1中的32字節(jié)的digest拿剪刀剪掉,剩下的頭和尾加在一起就是c1s1-joined。
用到的兩個(gè)常量FPKey和FMSKey:
[plain]view plaincopy u_int8_tFMSKey[]={ 0x47,0x65,0x6e,0x75,0x69,0x6e,0x65,0x20, 0x41,0x64,0x6f,0x62,0x65,0x20,0x46,0x6c, 0x61,0x73,0x68,0x20,0x4d,0x65,0x64,0x69, 0x61,0x20,0x53,0x65,0x72,0x76,0x65,0x72, 0x20,0x30,0x30,0x31,//GenuineAdobeFlashMediaServer001 0xf0,0xee,0xc2,0x4a,0x80,0x68,0xbe,0xe8, 0x2e,0x00,0xd0,0xd1,0x02,0x9e,0x7e,0x57, 0x6e,0xec,0x5d,0x2d,0x29,0x80,0x6f,0xab, 0x93,0xb8,0xe6,0x36,0xcf,0xeb,0x31,0xae };//68 u_int8_tFPKey[]={ 0x47,0x65,0x6E,0x75,0x69,0x6E,0x65,0x20, 0x41,0x64,0x6F,0x62,0x65,0x20,0x46,0x6C, 0x61,0x73,0x68,0x20,0x50,0x6C,0x61,0x79, 0x65,0x72,0x20,0x30,0x30,0x31,//GenuineAdobeFlashPlayer001 0xF0,0xEE,0xC2,0x4A,0x80,0x68,0xBE,0xE8, 0x2E,0x00,0xD0,0xD1,0x02,0x9E,0x7E,0x57, 0x6E,0xEC,0x5D,0x2D,0x29,0x80,0x6F,0xAB, 0x93,0xB8,0xE6,0x36,0xCF,0xEB,0x31,0xAE };//62 生成C1的算法如下:
[plain]view plaincopy calc_c1_digest(c1,schema){ getc1s1-joinedfromc1byspecifiedschema digest-data=HMACsha256(c1s1-joined,FPKey,30) returndigest-data; } randomfill1536bytesc1//alsofillthec1-128bytes-key time=time()//c1[0-3] version=[0x80,0x00,0x07,0x02]//c1[4-7] schema=chooseschema0orschema1 digest-data=calc_c1_digest(c1,schema) copydigest-datatoc1 生成S1的算法如下:
[plain]view plaincopy /*decodec1tryschema0thenschema1*/ c1-digest-data=get-c1-digest-data(schema0) ifc1-digest-dataequalstocalc_c1_digest(c1,schema0){ c1-key-data=get-c1-key-data(schema0) schema=schema0 }else{ c1-digest-data=get-c1-digest-data(schema1) ifc1-digest-datanotequalstocalc_c1_digest(c1,schema1){ switchtosimplehandshake. return } c1-key-data=get-c1-key-data(schema1) schema=schema1 } /*generates1*/ randomfill1536bytess1 time=time()//c1[0-3] version=[0x04,0x05,0x00,0x01]//s1[4-7] s1-key-data=shared_key=DH_compute_key(peer_pub_key=c1-key-data) getc1s1-joinedbyspecifiedschema s1-digest-data=HMACsha256(c1s1-joined,FMSKey,36) copys1-digest-dataands1-key-datatos1.
C1S1的算法完畢。
complex handshake C2S2C2S2的生成算法如下:
[plain]view plaincopy randomfillc2s21536bytes //clientgenerateC2,orservervalidC2 temp-key=HMACsha256(s1-digest,FPKey,62) c2-digest-data=HMACsha256(c2-random-data,temp-key,32) //servergenerateS2,orclientvalidS2 temp-key=HMACsha256(c1-digest,FMSKey,68) s2-digest-data=HMACsha256(s2-random-data,temp-key,32) 驗(yàn)證的算法是一樣的。
代碼實(shí)現(xiàn)
[cpp]view plaincopy /* TheMITLicense(MIT) Copyright(c)2013-2014winlin Permissionisherebygranted,freeofcharge,toanypersonobtainingacopyof thissoftwareandassociateddocumentationfiles(the"Software"),todealin theSoftwarewithoutrestriction,includingwithoutlimitationtherightsto use,copy,modify,merge,publish,distribute,sublicense,and/orsellcopiesof theSoftware,andtopermitpersonstowhomtheSoftwareisfurnishedtodoso, subjecttothefollowingconditions: Theabovecopyrightnoticeandthispermissionnoticeshallbeincludedinall copiesorsubstantialportionsoftheSoftware. THESOFTWAREISPROVIDED"ASIS",WITHOUTWARRANTYOFANYKIND,EXPRESSOR IMPLIED,INCLUDINGBUTNOTLIMITEDTOTHEWARRANTIESOFMERCHANTABILITY,FITNESS FORAPARTICULARPURPOSEANDNONINFRINGEMENT.INNOEVENTSHALLTHEAUTHORSOR COPYRIGHTHOLDERSBELIABLEFORANYCLAIM,DAMAGESOROTHERLIABILITY,WHETHER INANACTIONOFCONTRACT,TORTOROTHERWISE,ARISINGFROM,OUTOFORIN CONNECTIONWITHTHESOFTWAREORTHEUSEOROTHERDEALINGSINTHESOFTWARE. */ #ifndefSRS_RTMP_PROTOCOL_HANDSHKAE_HPP #defineSRS_RTMP_PROTOCOL_HANDSHKAE_HPP /* #include */ #include classISrsProtocolReaderWriter; classSrsComplexHandshake; classSrsHandshakeBytes; classSrsStream; #ifdefSRS_AUTO_SSL //foropenssl. #include namespace_srs_internal { //thedigestkeygeneratesize. #define__SRS_OpensslHashSize512 externu_int8_tSrsGenuineFMSKey[]; externu_int8_tSrsGenuineFPKey[]; intopenssl_HMACsha256(constvoid*key,intkey_size,constvoid*data,intdata_size,void*digest); intopenssl_generate_key(char*public_key,int32_tsize); /** *theDHwrapper. */ classSrsDH { private: DH*pdh; public: SrsDH(); virtual~SrsDH(); public: /** *initializedh,generatethepublicandprivatekey. *@paramensure_128bytes_public_keywhetherensurepublickeyis128bytes, *sometimesopensslgenerate127bytespublickey. *defaulttofalsetodonotensure. */ virtualintinitialize(boolensure_128bytes_public_key=false); /** *copythepublickey. *@parampkeythebytestocopythepublickey. *@parampkey_sizethemaxpublickeysize,outputtheactualpublickeysize. *usershouldneverignorethissize. *@remark,whenensure_128bytes_public_key,thesizealways128. */ virtualintcopy_public_key(char*pkey,int32_t&pkey_size); /** *generateandcopythesharedkey. *generatethesharedkeywithpeerpublickey. *@paramppkeypeerpublickey. *@paramppkey_sizethesizeofppkey. *@paramskeythecomputedsharedkey. *@paramskey_sizethemaxsharedkeysize,outputtheactualsharedkeysize. *usershouldneverignorethissize. */ virtualintcopy_shared_key(constchar*ppkey,int32_tppkey_size,char*skey,int32_t&skey_size); private: virtualintdo_initialize(); }; /** *theschematype. */ enumsrs_schema_type { srs_schema_invalid=2, /** *key-digestsequence */ srs_schema0=0, /** *digest-keysequence *@remark,FMSrequirestheschema1(digest-key),orconnectfailed. */ // srs_schema1=1, }; /** *764byteskeystructure *random-data:(offset)bytes *key-data:128bytes *random-data:(764-offset-128-4)bytes *offset:4bytes *@seealso:http://blog.csdn.net/win_lin/article/details/13006803 */ classkey_block { public: //(offset)bytes char*random0; intrandom0_size; //128bytes charkey[128]; //(764-offset-128-4)bytes char*random1; intrandom1_size; //4bytes int32_toffset; public: key_block(); virtual~key_block(); public: //parsekeyblockfromc1s1. //ifcreated,usermustfreeitbysrs_key_block_free //@streamcontainsc1s1_key_bytesthekeystartbytes intparse(SrsStream*stream); private: //calctheoffsetofkey, //thekey->offsetcannotbeusedastheoffsetofkey. intcalc_valid_offset(); }; /** *764bytesdigeststructure *offset:4bytes *random-data:(offset)bytes *digest-data:32bytes *random-data:(764-4-offset-32)bytes *@seealso:http://blog.csdn.net/win_lin/article/details/13006803 */ classdigest_block { public: //4bytes int32_toffset; //(offset)bytes char*random0; intrandom0_size; //32bytes chardigest[32]; //(764-4-offset-32)bytes char*random1; intrandom1_size; public: digest_block(); virtual~digest_block(); public: //parsedigestblockfromc1s1. //ifcreated,usermustfreeitbysrs_digest_block_free //@streamcontainsc1s1_digest_bytesthedigeststartbytes intparse(SrsStream*stream); private: //calctheoffsetofdigest, //thekey->offsetcannotbeusedastheoffsetofdigest. intcalc_valid_offset(); }; classc1s1; /** *thec1s1strategy,useschema0orschema1. *thetemplatemethodclasstodefinescommonbehaviors, *whiletheconcreteclasstoimplementsinschema0orschema1. */ classc1s1_strategy { protected: key_blockkey; digest_blockdigest; public: c1s1_strategy(); virtual~c1s1_strategy(); public: /** *getthescema. */ virtualsrs_schema_typeschema()=0; /** *getthedigest. */ virtualchar*get_digest(); /** *getthekey. */ virtualchar*get_key(); /** *copytobytes. *@paramsizemustbe1536. */ virtualintdump(c1s1*owner,char*_c1s1,intsize); /** *server:parsethec1s1,discoverythekeyanddigestbyschema. *usethec1_validate_digest()tovalidthedigestofc1. */ virtualintparse(char*_c1s1,intsize)=0; public: /** *client:createandsignc1byschema. *signthec1,generatethedigest. *calc_c1_digest(c1,schema){ *getc1s1-joinedfromc1byspecifiedschema *digest-data=HMACsha256(c1s1-joined,FPKey,30) *returndigest-data; *} *randomfill1536bytesc1//alsofillthec1-128bytes-key *time=time()//c1[0-3] *version=[0x80,0x00,0x07,0x02]//c1[4-7] *schema=chooseschema0orschema1 *digest-data=calc_c1_digest(c1,schema) *copydigest-datatoc1 */ virtualintc1_create(c1s1*owner); /** *server:validatetheparsedc1schema */ virtualintc1_validate_digest(c1s1*owner,bool&is_valid); /** *server:createandsignthes1fromc1. *//decodec1tryschema0thenschema1 *c1-digest-data=get-c1-digest-data(schema0) *ifc1-digest-dataequalstocalc_c1_digest(c1,schema0){ *c1-key-data=get-c1-key-data(schema0) *schema=schema0 *}else{ *c1-digest-data=get-c1-digest-data(schema1) *ifc1-digest-datanotequalstocalc_c1_digest(c1,schema1){ *switchtosimplehandshake. *return *} *c1-key-data=get-c1-key-data(schema1) *schema=schema1 *} * *//generates1 *randomfill1536bytess1 *time=time()//c1[0-3] *version=[0x04,0x05,0x00,0x01]//s1[4-7] *s1-key-data=shared_key=DH_compute_key(peer_pub_key=c1-key-data) *getc1s1-joinedbyspecifiedschema *s1-digest-data=HMACsha256(c1s1-joined,FMSKey,36) *copys1-digest-dataands1-key-datatos1. *@paramc1,togetthepeer_pub_keyofclient. */ virtualints1_create(c1s1*owner,c1s1*c1); /** *server:validatetheparseds1schema */ virtualints1_validate_digest(c1s1*owner,bool&is_valid); public: /** *calcthedigestforc1 */ virtualintcalc_c1_digest(c1s1*owner,char*&c1_digest); /** *calcthedigestfors1 */ virtualintcalc_s1_digest(c1s1*owner,char*&s1_digest); /** *copywholec1s1tobytes. *@paramsizemustalwaysbe1536withdigest,and1504withoutdigest. */ virtualintcopy_to(c1s1*owner,char*bytes,intsize,boolwith_digest)=0; /** *copytimeandversiontostream. */ virtualvoidcopy_time_version(SrsStream*stream,c1s1*owner); /** *copykeytostream. */ virtualvoidcopy_key(SrsStream*stream); /** *copydigesttostream. */ virtualvoidcopy_digest(SrsStream*stream,boolwith_digest); }; /** *c1s1schema0 *key:764bytes *digest:764bytes */ classc1s1_strategy_schema0:publicc1s1_strategy { public: c1s1_strategy_schema0(); virtual~c1s1_strategy_schema0(); public: virtualsrs_schema_typeschema(); virtualintparse(char*_c1s1,intsize); public: virtualintcopy_to(c1s1*owner,char*bytes,intsize,boolwith_digest); }; /** *c1s1schema1 *digest:764bytes *key:764bytes */ classc1s1_strategy_schema1:publicc1s1_strategy { public: c1s1_strategy_schema1(); virtual~c1s1_strategy_schema1(); public: virtualsrs_schema_typeschema(); virtualintparse(char*_c1s1,intsize); public: virtualintcopy_to(c1s1*owner,char*bytes,intsize,boolwith_digest); }; /** *c1s1schema0 *time:4bytes *version:4bytes *key:764bytes *digest:764bytes *c1s1schema1 *time:4bytes *version:4bytes *digest:764bytes *key:764bytes *@seealso:http://blog.csdn.net/win_lin/article/details/13006803 */ classc1s1 { public: //4bytes int32_ttime; //4bytes int32_tversion; //764bytes+764bytes c1s1_strategy*payload; public: c1s1(); virtual~c1s1(); public: /** *getthescema. */ virtualsrs_schema_typeschema(); /** *getthedigestkey. */ virtualchar*get_digest(); /** *getthekey. */ virtualchar*get_key(); public: /** *copytobytes. *@paramsize,mustalwaysbe1536. */ virtualintdump(char*_c1s1,intsize); /** *server:parsethec1s1,discoverythekeyanddigestbyschema. *@paramsize,mustalwaysbe1536. *usethec1_validate_digest()tovalidthedigestofc1. *usethes1_validate_digest()tovalidthedigestofs1. */ virtualintparse(char*_c1s1,intsize,srs_schema_type_schema); public: /** *client:createandsignc1byschema. *signthec1,generatethedigest. *calc_c1_digest(c1,schema){ *getc1s1-joinedfromc1byspecifiedschema *digest-data=HMACsha256(c1s1-joined,FPKey,30) *returndigest-data; *} *randomfill1536bytesc1//alsofillthec1-128bytes-key *time=time()//c1[0-3] *version=[0x80,0x00,0x07,0x02]//c1[4-7] *schema=chooseschema0orschema1 *digest-data=calc_c1_digest(c1,schema) *copydigest-datatoc1 */ virtualintc1_create(srs_schema_type_schema); /** *server:validatetheparsedc1schema */ virtualintc1_validate_digest(bool&is_valid); public: /** *server:createandsignthes1fromc1. *//decodec1tryschema0thenschema1 *c1-digest-data=get-c1-digest-data(schema0) *ifc1-digest-dataequalstocalc_c1_digest(c1,schema0){ *c1-key-data=get-c1-key-data(schema0) *schema=schema0 *}else{ *c1-digest-data=get-c1-digest-data(schema1) *ifc1-digest-datanotequalstocalc_c1_digest(c1,schema1){ *switchtosimplehandshake. *return *} *c1-key-data=get-c1-key-data(schema1) *schema=schema1 *} * *//generates1 *randomfill1536bytess1 *time=time()//c1[0-3] *version=[0x04,0x05,0x00,0x01]//s1[4-7] *s1-key-data=shared_key=DH_compute_key(peer_pub_key=c1-key-data) *getc1s1-joinedbyspecifiedschema *s1-digest-data=HMACsha256(c1s1-joined,FMSKey,36) *copys1-digest-dataands1-key-datatos1. */ virtualints1_create(c1s1*c1); /** *server:validatetheparseds1schema */ virtualints1_validate_digest(bool&is_valid); }; /** *thec2s2complexhandshakestructure. *random-data:1504bytes *digest-data:32bytes *@seealso:http://blog.csdn.net/win_lin/article/details/13006803 */ classc2s2 { public: charrandom[1504]; chardigest[32]; public: c2s2(); virtual~c2s2(); public: /** *copytobytes. *@paramsize,mustalwaysbe1536. */ virtualintdump(char*_c2s2,intsize); /** *parsethec2s2 *@paramsize,mustalwaysbe1536. */ virtualintparse(char*_c2s2,intsize); public: /** *createc2. *randomfillc2s21536bytes * *//clientgenerateC2,orservervalidC2 *temp-key=HMACsha256(s1-digest,FPKey,62) *c2-digest-data=HMACsha256(c2-random-data,temp-key,32) */ virtualintc2_create(c1s1*s1); /** *validatethec2fromclient. */ virtualintc2_validate(c1s1*s1,bool&is_valid); public: /** *creates2. *randomfillc2s21536bytes * *//servergenerateS2,orclientvalidS2 *temp-key=HMACsha256(c1-digest,FMSKey,68) *s2-digest-data=HMACsha256(s2-random-data,temp-key,32) */ virtualints2_create(c1s1*c1); /** *validatethes2fromserver. */ virtualints2_validate(c1s1*c1,bool&is_valid); }; } #endif /** *simplehandshake. *usercantrycomplexhandshakefirst, *rollbacktosimplehandshakeiferrorERROR_RTMP_TRY_SIMPLE_HS */ classSrsSimpleHandshake { public: SrsSimpleHandshake(); virtual~SrsSimpleHandshake(); public: /** *simplehandshake. */ virtualinthandshake_with_client(SrsHandshakeBytes*hs_bytes,ISrsProtocolReaderWriter*io); virtualinthandshake_with_server(SrsHandshakeBytes*hs_bytes,ISrsProtocolReaderWriter*io); }; /** *rtmpcomplexhandshake, *@seealsocrtmp(crtmpserver)orlibrtmp, *@seealso:http://blog.csdn.net/win_lin/article/details/13006803 */ classSrsComplexHandshake { public: SrsComplexHandshake(); virtual~SrsComplexHandshake(); public: /** *complexhanshake. *@returnusermust: *continueconnectappifsuccess, *trysimplehandshakeiferrorisERROR_RTMP_TRY_SIMPLE_HS, *otherwise,disconnect */ virtualinthandshake_with_client(SrsHandshakeBytes*hs_bytes,ISrsProtocolReaderWriter*io); virtualinthandshake_with_server(SrsHandshakeBytes*hs_bytes,ISrsProtocolReaderWriter*io); }; #endif /* TheMITLicense(MIT) Copyright(c)2013-2014winlin Permissionisherebygranted,freeofcharge,toanypersonobtainingacopyof thissoftwareandassociateddocumentationfiles(the"Software"),todealin theSoftwarewithoutrestriction,includingwithoutlimitationtherightsto use,copy,modify,merge,publish,distribute,sublicense,and/orsellcopiesof theSoftware,andtopermitpersonstowhomtheSoftwareisfurnishedtodoso, subjecttothefollowingconditions: Theabovecopyrightnoticeandthispermissionnoticeshallbeincludedinall copiesorsubstantialportionsoftheSoftware. THESOFTWAREISPROVIDED"ASIS",WITHOUTWARRANTYOFANYKIND,EXPRESSOR IMPLIED,INCLUDINGBUTNOTLIMITEDTOTHEWARRANTIESOFMERCHANTABILITY,FITNESS FORAPARTICULARPURPOSEANDNONINFRINGEMENT.INNOEVENTSHALLTHEAUTHORSOR COPYRIGHTHOLDERSBELIABLEFORANYCLAIM,DAMAGESOROTHERLIABILITY,WHETHER INANACTIONOFCONTRACT,TORTOROTHERWISE,ARISINGFROM,OUTOFORIN CONNECTIONWITHTHESOFTWAREORTHEUSEOROTHERDEALINGSINTHESOFTWARE. */ #include #include #include #include #include #include #include #include #include #ifdefSRS_AUTO_SSL usingnamespace_srs_internal; //foropenssl_HMACsha256 #include #include //for__openssl_generate_key #include namespace_srs_internal { //68bytesFMSkeywhichisusedtosigntheseverpacket. u_int8_tSrsGenuineFMSKey[]={ 0x47,0x65,0x6e,0x75,0x69,0x6e,0x65,0x20, 0x41,0x64,0x6f,0x62,0x65,0x20,0x46,0x6c, 0x61,0x73,0x68,0x20,0x4d,0x65,0x64,0x69, 0x61,0x20,0x53,0x65,0x72,0x76,0x65,0x72, 0x20,0x30,0x30,0x31,//GenuineAdobeFlashMediaServer001 0xf0,0xee,0xc2,0x4a,0x80,0x68,0xbe,0xe8, 0x2e,0x00,0xd0,0xd1,0x02,0x9e,0x7e,0x57, 0x6e,0xec,0x5d,0x2d,0x29,0x80,0x6f,0xab, 0x93,0xb8,0xe6,0x36,0xcf,0xeb,0x31,0xae };//68 //62bytesFPkeywhichisusedtosigntheclientpacket. u_int8_tSrsGenuineFPKey[]={ 0x47,0x65,0x6E,0x75,0x69,0x6E,0x65,0x20, 0x41,0x64,0x6F,0x62,0x65,0x20,0x46,0x6C, 0x61,0x73,0x68,0x20,0x50,0x6C,0x61,0x79, 0x65,0x72,0x20,0x30,0x30,0x31,//GenuineAdobeFlashPlayer001 0xF0,0xEE,0xC2,0x4A,0x80,0x68,0xBE,0xE8, 0x2E,0x00,0xD0,0xD1,0x02,0x9E,0x7E,0x57, 0x6E,0xEC,0x5D,0x2D,0x29,0x80,0x6F,0xAB, 0x93,0xB8,0xE6,0x36,0xCF,0xEB,0x31,0xAE };//62 int__openssl_HMACsha256(HMAC_CTX*ctx,constvoid*data,intdata_size,void*digest,unsignedint*digest_size) { intret=ERROR_SUCCESS; if(HMAC_Update(ctx,(unsignedchar*)data,data_size)<0){ ret=ERROR_OpenSslSha256Update; returnret; } if(HMAC_Final(ctx,(unsignedchar*)digest,digest_size)<0){ ret=ERROR_OpenSslSha256Final; returnret; } returnret; } /** *sha256digestalgorithm. *@paramkeythesha256key,NULLtouseEVP_Digest,forinstance, *hashlib.sha256(data).digest(). */ intopenssl_HMACsha256(constvoid*key,intkey_size,constvoid*data,intdata_size,void*digest) { intret=ERROR_SUCCESS; unsignedintdigest_size=0; unsignedchar*__key=(unsignedchar*)key; unsignedchar*__digest=(unsignedchar*)digest; if(key==NULL){ //usedatatodigest. //@see./crypto/sha/sha256t.c //@see./crypto/evp/digest.c if(EVP_Digest(data,data_size,__digest,&digest_size,EVP_sha256(),NULL)<0) { ret=ERROR_OpenSslSha256EvpDigest; returnret; } }else{ //usekey-datatodigest. HMAC_CTXctx; //@remark,ifnokey,useEVP_Digesttodigest, //forinstance,inpython,hashlib.sha256(data).digest(). HMAC_CTX_init(&ctx); if(HMAC_Init_ex(&ctx,__key,key_size,EVP_sha256(),NULL)<0){ ret=ERROR_OpenSslSha256Init; returnret; } ret=__openssl_HMACsha256(&ctx,data,data_size,__digest,&digest_size); HMAC_CTX_cleanup(&ctx); if(ret!=ERROR_SUCCESS){ returnret; } } if(digest_size!=32){ ret=ERROR_OpenSslSha256DigestSize; returnret; } returnret; } #defineRFC2409_PRIME_1024 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" "FFFFFFFFFFFFFFFF" SrsDH::SrsDH() { pdh=NULL; } SrsDH::~SrsDH() { if(pdh!=NULL){ if(pdh->p!=NULL){ BN_free(pdh->p); pdh->p=NULL; } if(pdh->g!=NULL){ BN_free(pdh->g); pdh->g=NULL; } DH_free(pdh); pdh=NULL; } } intSrsDH::initialize(boolensure_128bytes_public_key) { intret=ERROR_SUCCESS; for(;;){ if((ret=do_initialize())!=ERROR_SUCCESS){ returnret; } if(ensure_128bytes_public_key){ int32_tkey_size=BN_num_bytes(pdh->pub_key); if(key_size!=128){ srs_warn("regenerate128Bkey,current=%dB",key_size); continue; } } break; } returnret; } intSrsDH::copy_public_key(char*pkey,int32_t&pkey_size) { intret=ERROR_SUCCESS; //copypublickeytobytes. //sometimes,thekey_sizeis127,seemsok. int32_tkey_size=BN_num_bytes(pdh->pub_key); srs_assert(key_size>0); //maybethekey_sizeis127,butdhwillwriteall128bytespkey, //so,donotneedtoset/initializethepkey. //@seehttps://github.com/winlinvip/simple-rtmp-server/issues/165 key_size=BN_bn2bin(pdh->pub_key,(unsignedchar*)pkey); srs_assert(key_size>0); //outputthesizeofpublickey. //@seehttps://github.com/winlinvip/simple-rtmp-server/issues/165 srs_assert(key_size<=pkey_size); pkey_size=key_size; returnret; } intSrsDH::copy_shared_key(constchar*p