onvif 鉴权不使用ssl

来源:互联网 发布:java 汉字转拼音 编辑:程序博客网 时间:2024/05/16 14:39

有些设备没有做鉴权,有些操作不需要鉴权,使用Onvif协议时都应注意这些。
最开始使用的是OpenSSL,但觉得为了一个摘要加密使用这么大一个库,而且我要做跨平台,Windows直接把2个dll放在exe目录下即可,但对Linux不熟,配置OpenSSL很苦恼,于是想自己实现摘要加密。

实现

因自己有一个在Windows上实现了Onvif客户端操作的简单demo,里面使用的是OpenSSL,于是跟踪调试发现调用OpenSSL加密的函数在wsseapi.cppsoap_wsse_add_UsernameTokenDigest函数里的calc_digest,所以替换这个函数即可。这里感谢企鹅 609342205的指导!
当然soap_wsse_add_UsernameTokenDigest用到的其他函数也要一并拷贝到新文件里才能编译通过,摘要加密用的Secure Hashing Algorithm (SHA-1)
下面是代码(接口保持原样):

OnvifDigest.h

/** SHA1 digest size in octets */#define SOAP_SMD_SHA1_SIZE(20)/** Size of the random nonce */#define SOAP_WSSE_NONCELEN(20)#define TOKEN_TIMESTAMP 5class COnvifDigest{public:COnvifDigest(const char * szUsername, const char * szPassword);~COnvifDigest(void);void Authentication(soap * pSoap, bool bAuth = true, const std::string strId = "");const char * GetUsername(void);const char * GetPassword(void);private:void TokenTimestmap(soap * pSoap, time_t lifetime = TOKEN_TIMESTAMP);void calc_nonce(struct soap *soap, char nonce[SOAP_WSSE_NONCELEN]);struct _wsse__Security* soap_wsse_add_Security(struct soap *soap);int  soap_wsse_add_UsernameTokenText(struct soap *soap, const char *id, const char *username, const char *password);int  soap_wsse_add_UsernameTokenDigest(struct soap *soap, const char *id, const char *username, const char *password);int  soap_wsse_add_Timestamp(struct soap *soap, const char *id, time_t lifetime);void calc_digest(struct soap *soap, const char *created, const char *nonce, int noncelen, const char *password, char hash[SOAP_SMD_SHA1_SIZE]);private:std::string m_strUsername;std::string m_strPassword;};

OnvifDigest.cpp

#include "OnvifDigest.h"#include "onvif/sha1.h"const char *wsse_PasswordTextURI = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";const char *wsse_PasswordDigestURI = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest";const char *wsse_Base64BinaryURI = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary";COnvifDigest::COnvifDigest( const char * szUsername, const char * szPassword ): m_strUsername(szUsername), m_strPassword(szPassword){}COnvifDigest::~COnvifDigest( void ){}void COnvifDigest::Authentication( soap * pSoap, bool bAuth /*= true*/, const std::string strId /*= ""*/ ){const char * szId = strId.empty() ? NULL : strId.c_str();if (bAuth){soap_wsse_add_UsernameTokenDigest(pSoap, szId, m_strUsername.c_str(), m_strPassword.c_str());TokenTimestmap(pSoap);}}const char * COnvifDigest::GetUsername( void ){return m_strUsername.c_str();}const char * COnvifDigest::GetPassword( void ){return m_strPassword.c_str();}/* private */void COnvifDigest::TokenTimestmap( soap *pSoap, time_t lifetime /*= TOKEN_TIMESTAMP*/ ){soap_wsse_add_Timestamp(pSoap, "Time", lifetime);}void COnvifDigest::calc_nonce(struct soap *soap, char nonce[SOAP_WSSE_NONCELEN]){int i;time_t r = time(NULL);memcpy(nonce, &r, 4);for (i = 4; i < SOAP_WSSE_NONCELEN; i += 4){ r = soap_random;memcpy(nonce + i, &r, 4);}}struct _wsse__Security* COnvifDigest::soap_wsse_add_Security(struct soap *soap){/* if we don't have a SOAP Header, create one */soap_header(soap);/* if we don't have a wsse:Security element in the SOAP Header, create one */if (!soap->header->wsse__Security){ soap->header->wsse__Security = (_wsse__Security*)soap_malloc(soap, sizeof(_wsse__Security));soap_default__wsse__Security(soap, soap->header->wsse__Security);}return soap->header->wsse__Security;}int COnvifDigest::soap_wsse_add_UsernameTokenText(struct soap *soap, const char *id, const char *username, const char *password){ _wsse__Security *security = soap_wsse_add_Security(soap);/* allocate a UsernameToken if we don't have one already */if (!security->UsernameToken)security->UsernameToken = (_wsse__UsernameToken*)soap_malloc(soap, sizeof(_wsse__UsernameToken));soap_default__wsse__UsernameToken(soap, security->UsernameToken);/* populate the UsernameToken */security->UsernameToken->wsu__Id = soap_strdup(soap, id);security->UsernameToken->Username = soap_strdup(soap, username);/* allocate and populate the Password */if (password){ security->UsernameToken->Password = (_wsse__Password*)soap_malloc(soap, sizeof(_wsse__Password));soap_default__wsse__Password(soap, security->UsernameToken->Password);security->UsernameToken->Password->Type = (char*)wsse_PasswordTextURI;security->UsernameToken->Password->__item = soap_strdup(soap, password);}return SOAP_OK;}int COnvifDigest::soap_wsse_add_UsernameTokenDigest(struct soap *soap, const char *id, const char *username, const char *password){ _wsse__Security *security = soap_wsse_add_Security(soap);time_t now = time(NULL);const char *created = soap_dateTime2s(soap, now);char HA[SOAP_SMD_SHA1_SIZE], HABase64[29];char nonce[SOAP_WSSE_NONCELEN], *nonceBase64;/* generate a nonce */calc_nonce(soap, nonce);nonceBase64 = soap_s2base64(soap, (unsigned char*)nonce, NULL, SOAP_WSSE_NONCELEN);/* The specs are not clear: compute digest over binary nonce or base64 nonce? *//* compute SHA1(created, nonce, password) *//*// boost计算结果不对,应该是我的使用方法不对unsigned int Digest[5] = {0};boost::uuids::detail::sha1sha;sha.process_bytes(nonce, strlen(nonce));sha.process_bytes(created, strlen(created));sha.process_bytes(password, strlen(password));sha.get_digest(Digest);for (int n=0,i=0; n<SOAP_SMD_SHA1_SIZE; ){HA[n++] = (Digest[i] >> 24) & 0xFF;HA[n++] = (Digest[i] >> 16) & 0xFF;HA[n++] = (Digest[i] >> 8) & 0xFF;HA[n++] = Digest[i] & 0xFF;i++;}*/calc_digest(soap, created, nonce, SOAP_WSSE_NONCELEN, password, HA);//calc_digest(soap, created, nonce, SOAP_WSSE_NONCELEN, password, HA);/*calc_digest(soap, created, nonceBase64, strlen(nonceBase64), password, HA);*/soap_s2base64(soap, (unsigned char*)HA, HABase64, SOAP_SMD_SHA1_SIZE);/* populate the UsernameToken with digest */soap_wsse_add_UsernameTokenText(soap, id, username, HABase64);/* populate the remainder of the password, nonce, and created */security->UsernameToken->Password->Type = (char*)wsse_PasswordDigestURI;security->UsernameToken->Nonce = nonceBase64;security->UsernameToken->wsu__Created = soap_strdup(soap, created);return SOAP_OK;}int COnvifDigest::soap_wsse_add_Timestamp( struct soap *soap, const char *id, time_t lifetime ){_wsse__Security *security = soap_wsse_add_Security(soap);time_t now = time(NULL);char *created = soap_strdup(soap, soap_dateTime2s(soap, now));char *expired = lifetime ? soap_strdup(soap, soap_dateTime2s(soap, now + lifetime)) : NULL;/* allocate a Timestamp if we don't have one already */if (!security->wsu__Timestamp)security->wsu__Timestamp = (_wsu__Timestamp*)soap_malloc(soap, sizeof(_wsu__Timestamp));soap_default__wsu__Timestamp(soap, security->wsu__Timestamp);/* populate the wsu:Timestamp element */security->wsu__Timestamp->wsu__Id = soap_strdup(soap, id);security->wsu__Timestamp->Created = created;security->wsu__Timestamp->Expires = expired;return SOAP_OK;}void COnvifDigest::calc_digest( struct soap *soap, const char *created, const char *nonce, int noncelen, const char *password, char hash[SOAP_SMD_SHA1_SIZE] ){SHA1Context sha;SHA1Reset(&sha);SHA1Input(&sha, (unsigned char *)nonce, noncelen);SHA1Input(&sha, (unsigned char *)created, strlen(created));SHA1Input(&sha, (unsigned char *)password, strlen(password));if (!SHA1Result(&sha)){fprintf(stderr, "ERROR-- could not compute message digest\n");}else{int j = 0;for(int i = 0; i < 5 ; i++){hash[j++] = sha.Message_Digest[i] >> 24;hash[j++] = sha.Message_Digest[i] >> 16;hash[j++] = sha.Message_Digest[i] >> 8;hash[j++] = sha.Message_Digest[i] >> 0;}}}

加密库:Secure Hashing Algorithm (SHA-1),有C、C++两个版本。
0 0