Onvif客户端与服务器通信时鉴权的自实现
导语
有些设备没有做鉴权,有些操作不需要鉴权,使用Onvif协议时都应注意这些。
最开始使用的是OpenSSL,但觉得为了一个摘要加密使用这么大一个库,而且我要做跨平台,Windows直接把2个dll放在exe目录下即可,但对Linux不熟,配置OpenSSL很苦恼,于是想自己实现摘要加密。
实现
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::sha1 sha;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++两个版本。
Onvif客户端与服务器通信时鉴权的自实现相关推荐
- 为什么获取crm服务器信息失败,为 Outlook 配置 Microsoft Dynamics CRM 客户端时出现 与 Microsoft Dynamics CRM 服务器通信时出现问题 错误...
症状 当您尝试配置 microsoft Office Outlook 的 Microsoft Dynamics CRM 客户端时,收到以下错误消息: 与 Microsoft Dynamics CRM ...
- Onvif协议学习:7、鉴权认证
Onvif协议学习:7.鉴权认证 文章目录 Onvif协议学习:7.鉴权认证 1.前言 2.ONVIF哪些接口需要认证 3.如何认证 4.安装OpenSSL 5.实现认证 6.特别注意 原文链接:ht ...
- Websocket(二)-客户端与服务器通信
Websocket(二)-客户端与服务器通信 服务端 客户端测试 const WebSocket = require('ws'); const Server = WebSocket.Server; c ...
- 输入URL,客户端到服务器通信的过程
输入URL,客户端到服务器通信全过程 按五层网络协议进行理解: 在主机上: 1.第五层--应用层:DNS解析 2.第四层--传输层:TCP三次握手.四次挥手 3.第三层--网络层:IP层 4.第2.5 ...
- 无法在Web服务器上启动调试。与Web服务器通信时出现身份验证错误
使用Visual Studio 2005(Visual Studio 2008亦存在此问题)调试设置了主机头的网站时出现如下错误信息: --------- Microsoft Visual Studi ...
- 关于“与google服务器通信时出现问题“
问题 Gmail等软件登录时不断核验设备,然后出现"与google服务器通信时出现问题"提示 解决方案 这个一般是应用设置上有问题 试着切换其他线路 全局设置的时候确认google ...
- Exchange邮件系统客户端与服务器通信常用网络端口
Exchange邮件系统:客户端与服务器通信常用网络端口 序号 用途 端口 1 未加密的web连接: •互联网日历发布 •Outlook on the web(重定向到443/TCP) •自动发现(4 ...
- java socket5源码_Java利用TCP协议实现客户端与服务器通信【附通信源码】
进行TCP协议网络程序的编写,关键在于ServerSocket套接字的熟练使用,TCP通信中所有的信息传输都是依托ServerSocket类的输入输出流进行的. TCP协议概念 先来了解一下TCP协议 ...
- RTSP安防网络摄像头/海康大华硬盘录像机网页无插件直播流媒体服务器EasyNVR之鉴权接口的调用配置说明
进入移动互联网时代以来,企业微信公众号已成为除官网以外非常重要的宣传渠道,当3.2亿直播用户与9亿微信用户的势能累加,在微信上开启直播已成为越来越多企业的必然选择. EasyNVR核心在于摄像机的音视 ...
- 全网疯传!Java利用TCP协议实现客户端与服务器通信【附通信源码
目录 TCP协议概念 ServerSocket类 服务器端程序 客户端程序 Hello!大家好哇!我是灰小猿! 上一篇博客和大家分享了在网络编程中要注意的基础知识,关于IP.TCP.UDP以及端口和套 ...
最新文章
- STM32控制OLCD显示中英文(NB-IoT专栏—基础篇6)
- Pycharm 社区版本Database Navigator 安装教程
- 失败的windows系统服务调用readfile():管道已结束?_操作系统之进程详解(一)
- matlab imfilter函数,Matlab的imfilter函数用法详解
- mysql数据库入门教程(14):函数
- JAX-RS 2.0:服务器端处理管道
- [react] 请说说什么是useEffect?
- 2020年10月抖音小红书美妆营销报告
- [Contest20180116]随机游走
- 向中级程序员转变的10个建议
- Delphi D10.X VCL和FireMonkey之间的常见差异介绍
- Java基础_week6
- 芭蕉树上第二十一根芭蕉-- matlab2017b安装的出现问题
- 区块链的概念定义是什么
- react-native-webrtc之采坑之旅
- 架构师速成4.4-我该学什么语言
- 【Swing】JTree:树组件
- firefly-rk3288开发板Linux驱动——LED驱动
- 一个控制键盘远程控制多台视频会议摄像机(转自搜狐)
- Cmpp MsgId 生成算法
热门文章
- delphi计算机语言排名,2020年3月TIOBE编程语言排行榜 Java继续蝉联榜首
- 国开大学计算机实操,国开大学计算机实操答案一 .pdf
- 使用python将视频按照帧转为图片
- java-net-php-python-jsp安利达物流公司管理系统计算机毕业设计程序
- 车牌识别算法实践(一):先验知识
- 搜索引擎提交软件_搜索引擎排名因素有哪些?
- OpenCL优化案例研究 (4)
- 个人邮箱与企业邮箱的区别
- Linux 程序 动态库 静态库依赖关系
- 计算机游戏测试软件,你的电脑能不能吃鸡,两款软件很简单就能测试出来