233 lines
6.2 KiB
C
233 lines
6.2 KiB
C
|
/*
|
||
|
* libZRTP SDK library, implements the ZRTP secure VoIP protocol.
|
||
|
* Copyright (c) 2006-2009 Philip R. Zimmermann. All rights reserved.
|
||
|
* Contact: http://philzimmermann.com
|
||
|
* For licensing and other legal details, see the file zrtp_legal.c.
|
||
|
*
|
||
|
* Viktor Krykun <v.krikun at zfoneproject.com>
|
||
|
*/
|
||
|
|
||
|
#if (defined(ZRTP_USE_EXTERN_SRTP) && (ZRTP_USE_EXTERN_SRTP == 1))
|
||
|
|
||
|
/* exactly in this order (for winsock) */
|
||
|
#include <srtp.h>
|
||
|
#include "zrtp.h"
|
||
|
|
||
|
struct zrtp_srtp_ctx
|
||
|
{
|
||
|
srtp_t outgoing_srtp;
|
||
|
srtp_t incoming_srtp;
|
||
|
};
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
void init_policy(crypto_policy_t *sp, zrtp_srtp_policy_t *zp)
|
||
|
{
|
||
|
//TODO: make incoming policy crypto algorithm check for David A. McGrew's implementation support
|
||
|
|
||
|
/* there are no another appropriate ciphers in the David A. McGrew's implementation yet */
|
||
|
sp->cipher_type = AES_128_ICM;
|
||
|
sp->cipher_key_len = zp->cipher_key_len;
|
||
|
sp->auth_type = HMAC_SHA1;
|
||
|
sp->auth_key_len = zp->auth_key_len;
|
||
|
sp->auth_tag_len = zp->auth_tag_len->tag_length ? zp->auth_tag_len->tag_length : 10;
|
||
|
sp->sec_serv = sec_serv_conf_and_auth;
|
||
|
}
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
zrtp_status_t create_srtp_stream( srtp_t *srtp_stream,
|
||
|
zrtp_srtp_profile_t *profile,
|
||
|
ssrc_type_t ssrc_type )
|
||
|
{
|
||
|
srtp_policy_t policy;
|
||
|
uint8_t *tmp_key;
|
||
|
|
||
|
init_policy(&policy.rtp, &profile->rtp_policy);
|
||
|
init_policy(&policy.rtcp, &profile->rtcp_policy);
|
||
|
|
||
|
policy.ssrc.type = ssrc_type;
|
||
|
policy.ssrc.value = 0;
|
||
|
|
||
|
/* David A. McGrew's implementation uses key and salt as whole buffer, so let's make it */
|
||
|
tmp_key = (uint8_t*)zrtp_sys_alloc(profile->key.length + profile->salt.length);
|
||
|
if(NULL == tmp_key){
|
||
|
return zrtp_status_fail;
|
||
|
}
|
||
|
zrtp_memcpy(tmp_key, profile->key.buffer, profile->key.length);
|
||
|
zrtp_memcpy(tmp_key+profile->key.length, profile->salt.buffer, profile->salt.length);
|
||
|
|
||
|
policy.key = tmp_key;
|
||
|
policy.next = NULL;
|
||
|
|
||
|
/* add salt length to the key length of each policy */
|
||
|
policy.rtp.cipher_key_len += 14;
|
||
|
policy.rtcp.cipher_key_len += 14;
|
||
|
|
||
|
if(err_status_ok != srtp_create(srtp_stream, &policy)){
|
||
|
zrtp_sys_free(tmp_key);
|
||
|
return zrtp_status_fail;
|
||
|
}
|
||
|
|
||
|
zrtp_sys_free(tmp_key);
|
||
|
return zrtp_status_ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*===========================================================================*/
|
||
|
/* Public interface */
|
||
|
/*===========================================================================*/
|
||
|
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
zrtp_status_t zrtp_srtp_init(zrtp_global_ctx_t *zrtp_global)
|
||
|
{
|
||
|
err_status_t s = srtp_init();
|
||
|
return (err_status_ok == s) ? zrtp_status_ok : s;
|
||
|
}
|
||
|
|
||
|
zrtp_status_t zrtp_srtp_down( zrtp_global_ctx_t *zrtp_global )
|
||
|
{
|
||
|
return zrtp_status_ok;
|
||
|
}
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
zrtp_srtp_ctx_t * zrtp_srtp_create( zrtp_srtp_global_t *srtp_global,
|
||
|
zrtp_srtp_profile_t *inc_profile,
|
||
|
zrtp_srtp_profile_t *out_profile)
|
||
|
{
|
||
|
zrtp_status_t res = zrtp_status_ok;
|
||
|
zrtp_srtp_ctx_t *srtp_ctx = NULL;
|
||
|
|
||
|
if(NULL == inc_profile || NULL == out_profile){
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
do{
|
||
|
srtp_policy_t *policy_head, *policy_next;
|
||
|
|
||
|
srtp_ctx = zrtp_sys_alloc(sizeof(zrtp_srtp_ctx_t));
|
||
|
if(NULL == srtp_ctx){
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
res = create_srtp_stream(&srtp_ctx->incoming_srtp, inc_profile, ssrc_any_inbound);
|
||
|
if(zrtp_status_ok != res){
|
||
|
zrtp_sys_free(srtp_ctx);
|
||
|
srtp_ctx = NULL;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
res = create_srtp_stream(&srtp_ctx->outgoing_srtp, out_profile, ssrc_any_outbound);
|
||
|
if(zrtp_status_ok != res){
|
||
|
srtp_dealloc(srtp_ctx->incoming_srtp);
|
||
|
zrtp_sys_free(srtp_ctx);
|
||
|
srtp_ctx = NULL;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}while(0);
|
||
|
|
||
|
return srtp_ctx;
|
||
|
}
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
zrtp_status_t zrtp_srtp_destroy( zrtp_srtp_global_t *zrtp_srtp_global,
|
||
|
zrtp_srtp_ctx_t *srtp_ctx )
|
||
|
{
|
||
|
srtp_dealloc(srtp_ctx->incoming_srtp);
|
||
|
srtp_dealloc(srtp_ctx->outgoing_srtp);
|
||
|
zrtp_sys_free(srtp_ctx);
|
||
|
return zrtp_status_ok;
|
||
|
}
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
zrtp_status_t zrtp_srtp_protect( zrtp_srtp_global_t *srtp_global,
|
||
|
zrtp_srtp_ctx_t *srtp_ctx,
|
||
|
zrtp_rtp_info_t *packet)
|
||
|
{
|
||
|
err_status_t res;
|
||
|
res = srtp_protect(srtp_ctx->outgoing_srtp, packet->packet, packet->length);
|
||
|
if(err_status_ok != res){
|
||
|
return zrtp_status_fail;
|
||
|
}else{
|
||
|
return zrtp_status_ok;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
zrtp_status_t zrtp_srtp_unprotect( zrtp_srtp_global_t *srtp_global,
|
||
|
zrtp_srtp_ctx_t *srtp_ctx,
|
||
|
zrtp_rtp_info_t *packet)
|
||
|
{
|
||
|
err_status_t res;
|
||
|
res = srtp_unprotect(srtp_ctx->incoming_srtp, packet->packet, packet->length);
|
||
|
if(err_status_ok != res){
|
||
|
return zrtp_status_fail;
|
||
|
}else{
|
||
|
return zrtp_status_ok;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
zrtp_status_t zrtp_srtp_protect_rtcp( zrtp_srtp_global_t *srtp_global,
|
||
|
zrtp_srtp_ctx_t *srtp_ctx,
|
||
|
zrtp_rtp_info_t *packet)
|
||
|
{
|
||
|
err_status_t res;
|
||
|
res = srtp_protect_rtcp(srtp_ctx->outgoing_srtp, packet->packet, packet->length);
|
||
|
if(err_status_ok != res){
|
||
|
return zrtp_status_fail;
|
||
|
}else{
|
||
|
return zrtp_status_ok;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
zrtp_status_t zrtp_srtp_unprotect_rtcp( zrtp_srtp_global_t *srtp_global,
|
||
|
zrtp_srtp_ctx_t *srtp_ctx,
|
||
|
zrtp_rtp_info_t *packet)
|
||
|
{
|
||
|
err_status_t res;
|
||
|
res = srtp_unprotect_rtcp(srtp_ctx->incoming_srtp, packet->packet, packet->length);
|
||
|
if(err_status_ok != res){
|
||
|
return zrtp_status_fail;
|
||
|
}else{
|
||
|
return zrtp_status_ok;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
uint64_t make64(uint32_t high, uint32_t low)
|
||
|
{
|
||
|
uint64_t_ res;
|
||
|
uint32_t *p = (uint32_t*)&res;
|
||
|
|
||
|
#if ZRTP_BYTE_ORDER == ZBO_LITTLE_ENDIAN
|
||
|
*p++ = low;
|
||
|
*p = high;
|
||
|
#else
|
||
|
*p++ = high;
|
||
|
*p = low;
|
||
|
#endif
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
uint32_t high32(uint64_t x)
|
||
|
{
|
||
|
uint32_t *p = &x;
|
||
|
#if ZRTP_BYTE_ORDER == ZBO_LITTLE_ENDIAN
|
||
|
p++;
|
||
|
#endif
|
||
|
return *p;
|
||
|
}
|
||
|
|
||
|
uint32_t low32(uint64_t x)
|
||
|
{
|
||
|
uint32_t *p = &x;
|
||
|
#if ZRTP_BYTE_ORDER == ZBO_BIG_ENDIAN
|
||
|
p++;
|
||
|
#endif
|
||
|
return *p;
|
||
|
}
|
||
|
|
||
|
#endif /*ZRTP_USE_EXTERN_SRTP*/
|