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{
	//加密rtp
 	void (*encrypt_rtp)(zrtp_handle_t *pthis, int channel, unsigned char* in_data,unsigned char* out_data,int bytes_in,	int* bytes_out);
	//解密rtp
 	void (*decrypt_rtp)(zrtp_handle_t *pthis, int channel, unsigned char* in_data, unsigned char* out_data, int bytes_in, int* bytes_out);
	//加密rtcp
 	void (*encrypt_rtcp)(zrtp_handle_t *pthis, int channel, unsigned char* in_data,unsigned char* out_data, int bytes_in,int* bytes_out);
	//解密rtcp
 	void (*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) {
        // invalid
        return 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_memcpy(packet, in_data, bytes_in);
	unsigned int size =  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) {
        // invalid
        
        return 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 data
		
		memcpy(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: {
			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: 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) {
        // invalid
        return;
    }

	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 data
		memcpy(out_data, in_data, bytes_in);
		*bytes_out = bytes_in;
		return;
	}
	
	char packet[IP_PACKET_SIZE];
	
	/* Get RTP body from PGP words lists. Put RTCP marker at the beginning */
	zrtp_memcpy(packet, "RTCP", 4);		
	zrtp_memcpy(packet + 4, in_data, bytes_in);
	size = 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) {
        // invalid
        return;
    }

	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 data
		memcpy(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: {
			memcpy(out_data, packet, size;
			*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抓包显示的交互流程。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ffmpeg交叉编译移植是将ffmpeg库从一个平台编译并移植到另一个平台的过程。这个过程可以让我们在目标平台上运行ffmpeg库,并使用其功能。 要进行ffmpeg交叉编译移植,可以按照以下步骤进行操作: 1. 确定目标平台和编译环境。 在交叉编译移植之前,需要确定目标平台的操作系统和架构,并准备好相应的编译环境。例如,如果目标平台是ARM架构的嵌入式设备,需要安装适用于ARM平台的交叉编译工具链。 2. 获取ffmpeg源代码。 可以从FFmpeg的官方GitHub存储库中获取ffmpeg的源代码。使用git clone命令或直接下载源代码压缩包来获取代码。 3. 配置编译选项。 进入ffmpeg源代码目录,并使用configure命令来配置编译选项。根据目标平台和需求,选择适当的选项进行配置。可以参考FFmpeg的官方文档或者之前成功移植的经验来确定合适的选项。 4. 进行交叉编译。 在完成配置后,使用make命令进行交叉编译。根据编译环境的不同,可能需要使用特定的编译选项或命令来进行交叉编译。可以参考之前成功移植的经验或相关的教程来进行操作。 5. 测试和调试。 在编译完成后,将生成的ffmpeg库移植到目标平台上,并进行测试和调试。可以使用一些示例代码或自己编写的代码来测试ffmpeg库的功能和性能。 请注意,由于不同的平台和需求,ffmpeg的交叉编译移植可能会有一些特定的问题和挑战。在遇到问题时,可以参考相关的文档、教程和社区讨论来获取帮助和解决方案。引用提供了一些关于在Windows平台上编译带有libx264和libmp3lame的FFmpeg库的详细步骤,可以参考这些资源来获取更具体的信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值