/* * 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 */ #if (defined(ZRTP_USE_EXTERN_SRTP) && (ZRTP_USE_EXTERN_SRTP == 1)) /* exactly in this order (for winsock) */ #include #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*/