ZRTP交叉编译与移植

1 ZRTP源码下载

这里采用的是libzrtp来自于freeswitch:libs/libzrtp。

2 ZRTP交叉编译

zrtp编译比较简单,采用configure进行编译在根目录心中zrtp编译脚本,只需要指定交叉编译工具链和安装地址即可。脚本如下所示:

unset CC CFLAGS LDFLAGS CPPFLAGS CPP LD STRIP
./configure --host=arm-linux-androideabi --prefix=`pwd`/../objects/ 

成果物如下所示include和lib库:
在这里插入图片描述
在这里插入图片描述

3 ZRTP移植

zrtp移植主要对zrtp库进行封装,对外提供初始化和加密解密能力。接口设计如下:

3.1 API设计

typedef void ZrtpEventObserver(int id, BOOL encrypt);typedef struct zrtp_handle_t zrtp_handle_t;typedef struct zrtp_handle_t{//加密rtpvoid (*encrypt_rtp)(zrtp_handle_t *pthis, int channel, unsigned char* in_data,unsigned char* out_data,int bytes_in,	int* bytes_out);//解密rtpvoid (*decrypt_rtp)(zrtp_handle_t *pthis, int channel, unsigned char* in_data, unsigned char* out_data, int bytes_in, int* bytes_out);//加密rtcpvoid (*encrypt_rtcp)(zrtp_handle_t *pthis, int channel, unsigned char* in_data,unsigned char* out_data, int bytes_in,int* bytes_out);//解密rtcpvoid (*decrypt_rtcp)(zrtp_handle_t *pthis, int channel, unsigned char* in_data, unsigned char* out_data, int bytes_in, int* bytes_out);BOOL (*is_enabled)(zrtp_handle_t *pthis);void *priv;
}zrtp_handle_t;//构建zrtp会话
int zrtp_handle_alloc(zrtp_handle_t **ppthis, const WebRtc_Word32 id, ZrtpEventObserver *observer);
//释放zrtp会话
void zrtp_handle_free(zrtp_handle_t *pthis);
//初始化
int zrtp_handle_init();
//反初始化
void zrtp_handle_denit();

3.2 初始化

初始化只需要初始化一次,初始化需要注册发送回调函数,这里协商发送的数据包构造好后最终是有这个接口on_send_packet返回到应用发送。

int zrtp_handle_init()
{zrtp_config_defaults(&g_zrtp_config);zrtp_randstr2((unsigned char *)g_zrtp_config.client_id, sizeof(zrtp_client_id_t));
//	zrtp_randstr2((unsigned char *)g_zrtp_config.zid, sizeof(zrtp_zid_t));g_zrtp_config.lic_mode = ZRTP_LICENSE_MODE_ACTIVE;g_zrtp_config.cb.misc_cb.on_send_packet			= on_send_packet;g_zrtp_config.cb.event_cb.on_zrtp_protocol_event	= on_zrtp_protocol_event;g_zrtp_config.cb.event_cb.on_zrtp_security_event	= on_zrtp_security_event;g_zrtp_config.cb.event_cb.on_zrtp_secure			= on_zrtp_secure;g_zrtp_config.cb.event_cb.on_zrtp_not_secure		= on_zrtp_not_secure;zrtp_status_t s = zrtp_init(&g_zrtp_config, &g_pzrtp_global);if (zrtp_status_ok != s) {printf("ZRTP init failed, status = %d \n", s);return -1;}return 0;
}void zrtp_handle_denit()
{if (NULL != g_pzrtp_global) {zrtp_down(g_pzrtp_global);g_pzrtp_global = NULL;}
}

3.3 会话实例

每一路会话需要实例化一个zrtphandle对象,需要传入一个随机的zrtpid,和观察者。

int zrtp_handle_alloc(zrtp_handle_t **ppthis, const WebRtc_Word32 id, ZrtpEventObserver *observer)
{if(!ppthis)return -1;      zrtp_handle_t *phl = (zrtp_handle_t *)malloc(sizeof(zrtp_handle_t));	if(!phl){return -1;}priv_t *ppriv = (priv_t *)malloc(sizeof(priv_t));	if(!ppriv){free(phl);return -1;}memset(phl, 0, sizeof(zrtp_handle_t));memset(ppriv, 0, sizeof(priv_t));phl->priv = ppriv;   ppriv->__zrtp_session = NULL;ppriv->__zrtp_audio = NULL;ppriv->__lSSRC = 0;ppriv->__rSSRC = 0;ppriv->__stream_seq = 0;ppriv->__stream_timestamp = 0;ppriv->__is_first_start_stream = 0;ppriv->__is_need_send_hello = 0;ppriv->__is_zrtp_enable = 0;ppriv->__obverserptr = observer;ppriv->id = id;ppriv->__buffer_out_data = (char *)malloc(IP_PACKET_SIZE);phl->audio_encrypt_rtp = encrypt;phl->audio_decrypt_rtp = decrypt;phl->audio_encrypt_rtcp = encrypt_rtcp;phl->audio_decrypt_rtcp = decrypt_rtcp;*ppthis = phl;return 0;
}void zrtp_handle_free(zrtp_handle_t *pthis) 
{if(!pthis)return;DisableZsrtp(pthis);priv_t *ppriv = pthis->priv;if (NULL != ppriv->__buffer_out_data) {free(ppriv->__buffer_out_data);ppriv->__buffer_out_data = NULL;}if (pthis->priv){free(pthis->priv);pthis->priv = NULL;}	free(pthis);pthis = NULL;
}

3.4 加解密实现

加解密会用首先会进入到协商流程zrtp_stream_start完成协商,之后再进入加解密流程zrtp_process_rtp。

int encrypt(zrtp_handle_t *pthis,int channel,unsigned char* in_data,unsigned char* out_data,int bytes_in,int* bytes_out) {priv_t *ppriv = pthis->priv;if (!ppriv->__is_zrtp_enable || NULL == in_data || NULL == out_data|| 0 > bytes_in || NULL == bytes_out) {// invalidreturn 0;}if(ppriv->__is_need_send_hello){zrtp_stream_start(ppriv->__zrtp_audio, ppriv->__lSSRC);ppriv->__is_need_send_hello = RL_FALSE;}if(!ppriv->__buffer_out_data_consumed){++ppriv->__buffer_out_data_retry;memcpy(out_data, ppriv->__buffer_out_data, ppriv->__buffer_out_data_bytes);*bytes_out = ppriv->__buffer_out_data_bytes;ppriv->__buffer_out_data_consumed = RL_TRUE;return 0;}if (-1 == ppriv->__voice_encrypt_status && ppriv->__buffer_out_data_retry == ZRTP_COUNT_THRESHOLD_DEFAULT){// LinKy: Rollback to unecrypt, this operation will close zrtp session!UpdateEncryptStatus(pthis, RL_FALSE);//return 0;}if (ppriv->__zrtp_audio->state != ZRTP_STATE_SECURE) {// Not ready, use original data	memcpy(out_data, in_data, bytes_in);*bytes_out = bytes_in;return 1;}char packet[IP_PACKET_SIZE];ZRTP_UNALIGNED(zrtp_rtp_hdr_t) *rtp_hdr = (zrtp_rtp_hdr_t*)packet;/* Fill RTP Header according to the specification */zrtp_memset(rtp_hdr, 0, sizeof(zrtp_rtp_hdr_t));rtp_hdr->version = 2;						/* Current RTP version 2 */rtp_hdr->pt = 0;							/* PCMU padding type */rtp_hdr->ssrc = zrtp_hton32(ppriv->__lSSRC);		/* Use stream Identifier as it's SSRC */if (ppriv->__stream_seq >= 0xFFFF) {ppriv->__stream_seq = 0;}rtp_hdr->seq = libzrtp_swap16(ppriv->__stream_seq++);rtp_hdr->ts = zrtp_hton32(ppriv->__stream_timestamp);ppriv->__stream_timestamp += 20;					// LinKy: Assume the interval is 20mszrtp_memcpy(packet + sizeof(zrtp_rtp_hdr_t), in_data, bytes_in);unsigned int size = sizeof(zrtp_rtp_hdr_t) + bytes_in;zrtp_status_t s = zrtp_process_rtp(ppriv->__zrtp_audio, packet, &size);switch (s) {case zrtp_status_ok: {//// Packet was successfully decrypted. Dont forget that packet// size was changed during decryption. New size now in size //memcpy(out_data, packet, size);*bytes_out = size;return 2;}break;case zrtp_status_drop: {//// This is a protocol ZRTP packet or masked RTP media.// In either case the packet must be dropped to protect your // private data and media codec// LinKy: Shall we rollback to unencrypt here?return 3;}break;case zrtp_status_fail: {//// This is some kind of error - see logs for more information.// Don't put such packet to the network. It is not secure.//memcpy(out_data, in_data, bytes_in);*bytes_out = bytes_in;return 4;}break;}return 0;
}int decrypt(zrtp_handle_t *pthis,int channel,unsigned char* in_data,unsigned char* out_data,int bytes_in,int* bytes_out) {unsigned int size = bytes_in;priv_t *ppriv = pthis->priv;if (!ppriv->__is_zrtp_enable || NULL == in_data || NULL == out_data|| 0 > bytes_in || NULL == bytes_out) {// invalidreturn 0;}if(ppriv->__is_need_send_hello){zrtp_stream_start(ppriv->__zrtp_audio, ppriv->__lSSRC);ppriv->__is_need_send_hello = RL_FALSE;}//if zrtp success,ppriv->__buffer_in_data_retry Approximately equals 18;if (-1 == ppriv->__voice_encrypt_status && ppriv->__buffer_in_data_retry >= ZRTP_COUNT_THRESHOLD_DEFAULT){//if (ppriv->__zrtp_audio->state != ZRTP_STATE_SECURE){// Not ready, use original datamemcpy(out_data, in_data, bytes_in);*bytes_out = bytes_in;return 1;}else if(ppriv->__voice_encrypt_status == 0){memcpy(out_data, in_data, bytes_in);*bytes_out = bytes_in;return 1;}ppriv->__buffer_in_data_retry++;char packet[IP_PACKET_SIZE];memcpy(packet, in_data, bytes_in);zrtp_status_t s = zrtp_process_srtp(ppriv->__zrtp_audio, packet, &size);switch (s) {case zrtp_status_ok: {//// Packet was successfully decrypted. Dont forget that packet// size was changed during decryption. New size now in size //char *body = packet + sizeof(zrtp_rtp_hdr_t);memcpy(out_data, body, size - sizeof(zrtp_rtp_hdr_t));*bytes_out = size - sizeof(zrtp_rtp_hdr_t);return 2;}break;case zrtp_status_drop: {//// This is a protocol ZRTP packet or masked RTP media.// In either case the packet must be dropped to protect your // private data and media codec// LinKy: Yep, we drop it, use original data to play!memcpy(out_data, in_data, bytes_in);*bytes_out = bytes_in;return 3;}break;case zrtp_status_fail: {//// This is some kind of error - see logs for more information.// Don't put such packet to the network. It is not secure.//// LinKy: Be careful! This may cause noise if data is encrypted actually!memcpy(out_data, in_data, bytes_in);*bytes_out = bytes_in;return 4;}break;}return 0;
}void encrypt_rtcp(zrtp_handle_t *pthis,int channel,unsigned char* in_data,unsigned char* out_data,int bytes_in,int* bytes_out) {priv_t *ppriv = pthis->priv;unsigned int size = bytes_in;if (!ppriv->__is_zrtp_enable || NULL == in_data || NULL == out_data|| 0 > bytes_in || NULL == bytes_out) {// invalidreturn;}if(ppriv->__is_need_send_hello){zrtp_stream_start(ppriv->__zrtp_audio, ppriv->__lSSRC);ppriv->__is_need_send_hello = RL_FALSE;}if (ppriv->__zrtp_audio->state != ZRTP_STATE_SECURE) {// Not ready, use original datamemcpy(out_data, in_data, bytes_in);*bytes_out = bytes_in;return;}char packet[IP_PACKET_SIZE];ZRTP_UNALIGNED(zrtp_rtcp_hdr_t) *rtcp_hdr = (zrtp_rtcp_hdr_t*)packet;/* Fill RTCP Header according to the specification */rtcp_hdr->rc = 0;rtcp_hdr->version = 2;rtcp_hdr->ssrc = zrtp_hton32(ppriv->__lSSRC);/* Get RTP body from PGP words lists. Put RTCP marker at the beginning */zrtp_memcpy(packet + sizeof(zrtp_rtcp_hdr_t), "RTCP", 4);		zrtp_memcpy(packet + sizeof(zrtp_rtcp_hdr_t) + 4, in_data, bytes_in);size = sizeof(zrtp_rtcp_hdr_t) + bytes_in + 4;/* RTCP packets sould be 32 byes aligned */size += (size % 4) ? (4 - size % 4) : 0;zrtp_status_t s = zrtp_process_rtcp(ppriv->__zrtp_audio, packet, &size);switch (s) {case zrtp_status_ok: {//// Packet was successfully decrypted. Dont forget that packet// size was changed during decryption. New size now in size //memcpy(out_data, packet, size);*bytes_out = size;}break;case zrtp_status_drop: {//// This is a protocol ZRTP packet or masked RTP media.// In either case the packet must be dropped to protect your // private data and media codec// LinKy: Shall we rollback to unencrypt here?}break;case zrtp_status_fail: {//// This is some kind of error - see logs for more information.// Don't put such packet to the network. It is not secure.//memcpy(out_data, in_data, bytes_in);*bytes_out = bytes_in;}break;}
}void decrypt_rtcp(zrtp_handle_t *pthis,int channel,unsigned char* in_data,unsigned char* out_data,int bytes_in,int* bytes_out) {priv_t *ppriv = pthis->priv;unsigned int size = bytes_in;if (!ppriv->__is_zrtp_enable || NULL == in_data || NULL == out_data|| 0 > bytes_in || NULL == bytes_out) {// invalidreturn;}if(ppriv->__is_first_start_stream){zrtp_stream_start(ppriv->__zrtp_audio, channel);ppriv->__is_first_start_stream = RL_FALSE;}if (ppriv->__zrtp_audio->state != ZRTP_STATE_SECURE) {// Not ready, use original datamemcpy(out_data, in_data, bytes_in);*bytes_out = bytes_in;return;}char packet[IP_PACKET_SIZE];memcpy(packet,in_data,bytes_in);zrtp_status_t s = zrtp_process_srtcp(ppriv->__zrtp_audio, packet, &size);switch (s) {case zrtp_status_ok: {//// Packet was successfully decrypted. Dont forget that packet// size was changed during decryption. New size now in size //char *body = packet + sizeof(zrtp_rtp_hdr_t);memcpy(out_data, body, size - sizeof(zrtp_rtp_hdr_t));*bytes_out = size - sizeof(zrtp_rtp_hdr_t);}break;case zrtp_status_drop: {//// This is a protocol ZRTP packet or masked RTP media.// In either case the packet must be dropped to protect your // private data and media codec// LinKy: Yep, we drop it, use original data to play!memcpy(out_data, in_data, bytes_in);*bytes_out = bytes_in;}break;case zrtp_status_fail: {//// This is some kind of error - see logs for more information.// Don't put such packet to the network. It is not secure.//// LinKy: Be careful! This may cause noise if data is encrypted actually!memcpy(out_data, in_data, bytes_in);*bytes_out = bytes_in;}break;}
}

4 ZRTP抓包分析

一个完整的ZRTP协商流程,首先是hello进双方加密方式的交换,之后会进行一个收到的应答,然后是commit消息确认HMAC秘钥,DHPart消息交换公钥,Confirm消息确认签名,最后是ConfACK应答。下面是wareshark抓包显示的交互流程。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/96163.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【刷题笔记10.6】LeetCode:汉明距离

LeetCode:汉明距离 一、题目描述 两个整数之间的汉明距离是指这两个数字对应二进制位不同的位置的数目。 给你两个整数x 和 y,计算并返回他们之间的汉明距离。 二、分析及代码实现 对于汉明距离问题我们其实可以将其转换为:计算x 和 y按…

使用opencv及FFmpeg编辑视频

使用opencv及FFmpeg编辑视频 1.融合两个视频2.为视频添加声音2.1 安装ffmpy Python包2.2 下载ffmpeg2.3 代码实现 3.效果参考文献 帮朋友做了一个小作业,具体实现分为几个过程: 将两个mp4格式视频融合到一起为新视频添加声音 1.融合两个视频 其中一个…

makeMakefile

一、 什么是make&Makefile ? ①make 是一条命令,makefile是一个文件,配合使用,通过依赖关系和依赖方法达到我们形成可执行程序的目的 ②makefile好处就是可以进行 自动化编译 ” ,极大的提高软件开发的效率,一旦写好,只需要一个 make 命令…

MySQL 事务隔离级别与锁机制详解

目录 一、前言二、事务及其ACID属性三、并发事务处理带来的问题四、事务隔离级别4.1、隔离级别分类4.2、查看当前数据库的事务隔离级别:4.3、临时修改数据库隔离级别(重启MySQL后恢复到配置中的级别) 五、表数据准备六、MySQL常见锁介绍5.1、锁分类5.2、…

【Pytorch笔记】6.Transforms

pytorch官方文档 - transforms transforms需要使用计算机视觉工具包:torchvision。 torchvision.transforms:常用的图像预处理方法; torchvision.datasets:常用数据集的dataset实现,如MNIST、CIFAR-10、ImageNet等&am…

【RK3588】YOLO V5在瑞芯微板子上部署问题记录汇总

YOLO V5训练模型部署到瑞芯微的板子上面,官方是有给出案例和转过详情的。并且也提供了Python版本的推理代码,以及C语言的代码。 但是,对于转换过程中的细节,哪些需要改?怎么改?如何改,和为什么…

1392. 最长快乐前缀

链接&#xff1a; 1392. 最长快乐前缀 题解&#xff1a; class Solution { public:string longestPrefix(string s) {if (s.size() < 0) {return "";}int MOD 1e9 7;// 构建26的n次方&#xff0c;预处理std::vector<long> pow26(s.size());pow26[0] 1…

vue3中使用return语句返回this.$emit(),在同一行不执行,换行后才执行,好奇怪!

今天练习TodoList任务列表案例,该案例效果如图所示&#xff1a; 此案例除了根组件App.vue&#xff0c;还有TodoList、TodoInput、TodoButton三个子组件。 因为有视频讲解&#xff0c;在制作TodoList、TodoInput时很顺利&#xff0c;只是在完成TodoButton这个组件时出了点问题…

《protobuf》基础语法3

文章目录 默认值更新规则保留字段未知字段 默认值 在反序列化时&#xff0c;若被反序列化的二进制序列中不包含某个字段&#xff0c;则在反序列化时&#xff0c;就会设置对应默认值。不同的类型默认值不同&#xff1a; 类型默认值字符串“”布尔型false数值类型0枚举型0设置了…

微信开放平台第三方代小程序开发,授权事件、消息与事件通知总结

大家好&#xff0c;我是小悟 时间过得真快&#xff0c;转眼就到了国庆节尾巴&#xff0c;小伙伴们吃好喝好玩好了么。 关于微信开放平台第三方代小程序开发的两个事件接收推送通知&#xff0c;是开放平台代小程序实现业务的重要功能。 授权事件推送&#xff0c;事件类型以In…

ssm+vue的培训机构运营管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。

演示视频&#xff1a; ssmvue的培训机构运营管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结…

二分查找:34. 在排序数组中查找元素的第一个和最后一个位置

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《算法》 文章目录 前言一、题目解析二、解题思路1. 暴力查找2. 一次二分查找 部分遍历3. 两次二分查找分别查找左右端点1.查找区间左端点2. 查找区间右端点 三、代码实现总结 前言 本篇文…

蓝桥杯每日一题2023.10.6

题目描述 门牌制作 - 蓝桥云课 (lanqiao.cn) 题目分析 #include<bits/stdc.h> using namespace std; int ans; int main() {for(int i 1; i < 2020; i ){int x i;while(x){int a x % 10;if(a 2)ans ;x / 10;}}cout << ans;return 0; } 题目描述 既约分数…

C++设计模式-桥接(Bridge)

目录 C设计模式-桥接&#xff08;Bridge&#xff09; 一、意图 二、适用性 三、结构 四、参与者 五、代码 C设计模式-桥接&#xff08;Bridge&#xff09; 一、意图 将抽象部分与它的实现部分分离&#xff0c;使它们都可以独立地变化。 二、适用性 你不希望在抽象和它…

Spring Cloud Gateway网关中各个过滤器的作用与介绍

文章目录 1. Route To Request URL Filter&#xff08;路由过滤器&#xff09;2. Gateway Filter&#xff08;全局过滤器&#xff09;3. Pre Filter&#xff08;前置过滤器&#xff09;4. Post Filter&#xff08;后置过滤器&#xff09;5. Error Filter&#xff08;错误过滤器…

Linux中的wc命令

2023年10月6月&#xff0c;周五晚上 目录 wc命令的主要功能和用法如下:统计文件行数、字数和字节数只统计行数只统计字数只统计字节数 wc命令在Linux/Unix系统中是word count的缩写,它用来统计文件的行数、字数和字节数。 wc命令的主要功能和用法如下: 统计文件行数、字数和字…

【C++设计模式之状态模式:行为型】分析及示例

简介 状态模式&#xff08;State Pattern&#xff09;是一种行为型设计模式&#xff0c;它允许对象在内部状态改变时改变其行为&#xff0c;看起来就像是改变了其类。状态模式将对象的状态封装成不同的类&#xff0c;并使得对象在不同状态下有不同的行为。 描述 状态模式通过…

Qt之显示PDF文件

之前使用过mupdf库&#xff0c;能够成功显示pdf&#xff0c;但是我用着有BUG&#xff0c;不太理解它的代码&#xff0c;搞了好久都不行。后面又试了其他库&#xff0c;如pdfium、popler、下载了很多例程&#xff0c;都跑不起来&#xff01;后面偶然得知xpdf库&#xff0c;看起来…

C++-封装unordered

本期我们来封装实现unordered系列&#xff0c;需要前置知识&#xff0c;没有看过哈希的建议先看看哈希&#xff0c;而且哈希的代码都在这里面&#xff0c;一会要用到 C-哈希Hash-CSDN博客 目录 代码实现 迭代器 const迭代器 全部代码 代码实现 首先我们要把V改为T&#xff…

2023-10-06 LeetCode每日一题(买卖股票的最佳时机含手续费)

2023-10-06每日一题 一、题目编号 714. 买卖股票的最佳时机含手续费二、题目链接 点击跳转到题目位置 三、题目描述 给定一个整数数组 prices&#xff0c;其中 prices[i]表示第 i 天的股票价格 &#xff1b;整数 fee 代表了交易股票的手续费用。 你可以无限次地完成交易&…