void * sender_thread (void *arg) { err_status_t status; thread_parms_t *tp = (thread_parms_t*)arg; rtp_sender_t snd[NUM_SSRC_PER_THREAD]; int cnt = 0; int i; srtp_ctx_t *srtp_ctx = NULL; printf("\nStarting sender thread (port: %d base-ssrc: %x stream_cnt: %d)\n", tp->port, tp->ssrc, tp->stream_cnt); /* initialize sender's rtp and srtp contexts */ status = srtp_create(&srtp_ctx, tp->policy); if (status) { fprintf(stderr, "error: srtp_create() failed with code %d\n", status); exit(1); } /* now add the streams on the session */ for (i = 0; i < tp->stream_cnt; i++) { rtp_sender_init(&snd[i], tp->sock, tp->name, tp->ssrc); snd[i].srtp_ctx = srtp_ctx; status = srtp_add_stream(snd[i].srtp_ctx, tp->policy); if (status) { fprintf(stderr, "error: srtp_add_stream() failed with code %d\n", status); exit(1); } tp->policy->ssrc.value++; tp->ssrc++; } while (cnt < THREAD_PKT_CNT) { for (i = 0; i < tp->stream_cnt; i++) { rtp_sendto(&snd[i], test_data, DATA_LEN); cnt++; if (cnt % STAT_WINDOW == 0) { printf("Thread id %d transmit count is %d\n", tp->thread_num, cnt); } } usleep(SLEEP_LEN); } /* * Clean up the session */ srtp_dealloc(srtp_ctx); return NULL; }
err_status_t ortp_srtp_add_stream(srtp_t session, const srtp_policy_t *policy) { return srtp_add_stream(session, policy); }
/** * SRTP crypto data ready for the sender or receiver. * * The ZRTP implementation calls this method right after all SRTP * secrets are computed and ready to be used. The parameter points * to a structure that contains pointers to the SRTP secrets and a * <code>enum Role</code>. The called method (the implementation * of this abstract method) must either copy the pointers to the SRTP * data or the SRTP data itself to a save place. The SrtpSecret_t * structure is destroyed after the callback method returns to the * ZRTP implementation. * * The SRTP data themselves are obtained in the ZRtp object and are * valid as long as the ZRtp object is active. TheZRtp's * destructor clears the secrets. Thus the called method needs to * save the pointers only, ZRtp takes care of the data. * * The implementing class may enable SRTP processing in this * method or delay it to srtpSecertsOn(). * * @param ctx * Pointer to the opaque ZrtpContext structure. * @param secrets A pointer to a SrtpSecret_t structure that * contains all necessary data. * * @param part for which part (Sender or Receiver) this data is * valid. * * @return Returns false if something went wrong during * initialization of SRTP context, for example memory shortage. */ static int32_t ozrtp_srtpSecretsReady (ZrtpContext* ctx, C_SrtpSecret_t* secrets, int32_t part ) { srtp_policy_t policy; err_status_t srtpCreateStatus; err_status_t addStreamStatus; OrtpZrtpContext *userData = user_data(ctx); ortp_message("ZRTP secrets for %s are ready; auth tag len is %i", (part == ForSender) ? "sender" : "receiver",secrets->srtpAuthTagLen); // Get authentication and cipher algorithms in srtp format if (secrets->authAlgorithm != zrtp_Sha1) { ortp_fatal("unsupported authentication algorithm by srtp"); } if (secrets->symEncAlgorithm != zrtp_Aes) { ortp_fatal("unsupported cipher algorithm by srtp"); } /* * Don't use crypto_policy_set_from_profile_for_rtp(), it is totally buggy. */ memset(&policy,0,sizeof(policy)); if (secrets->srtpAuthTagLen == 32){ crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp); crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtcp); }else if (secrets->srtpAuthTagLen == 80){ crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp); crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); }else{ ortp_fatal("unsupported auth tag len"); } if (part == ForSender) { srtpCreateStatus=srtp_create(&userData->srtpSend, NULL); policy.ssrc.type=ssrc_specific; policy.ssrc.value=userData->session->snd.ssrc; // us policy.key=key_with_salt(secrets, secrets->role); addStreamStatus=srtp_add_stream(userData->srtpSend, &policy); } else { //if (part == ForReceiver) srtpCreateStatus=srtp_create(&userData->srtpRecv, NULL); policy.ssrc.type = ssrc_any_inbound; /*we don't know the incoming ssrc will be */ int32_t peerRole=secrets->role == Initiator ? Responder : Initiator; policy.key=key_with_salt(secrets,peerRole); addStreamStatus=srtp_add_stream(userData->srtpRecv, &policy); } ortp_free(policy.key); if (srtpCreateStatus != err_status_ok) { ortp_error("ZRTP Error %u during creation of SRTP context for %s", srtpCreateStatus, (part == ForSender) ? "sender" : "receiver"); return 0; } if (addStreamStatus != err_status_ok) { ortp_error("ZRTP Error %u during addition of SRTP stream for %s", addStreamStatus, (part == ForSender) ? "sender" : "receiver"); return 0; } return 1; }
static int add_srtp_stream(srtp_t srtp, MSCryptoSuite suite, uint32_t ssrc, const char* b64_key, bool_t inbound) { srtp_policy_t policy; uint8_t* key; int key_size; err_status_t err; unsigned b64_key_length = strlen(b64_key); ssrc_t ssrc_conf; memset(&policy,0,sizeof(policy)); switch(suite){ case MS_AES_128_SHA1_32: crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp); // srtp doc says: not adapted to rtcp... crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtcp); break; case MS_AES_128_NO_AUTH: crypto_policy_set_aes_cm_128_null_auth(&policy.rtp); // srtp doc says: not adapted to rtcp... crypto_policy_set_aes_cm_128_null_auth(&policy.rtcp); break; case MS_NO_CIPHER_SHA1_80: crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtp); crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtcp); break; case MS_AES_128_SHA1_80: /*default mode*/ crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp); crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); break; case MS_AES_256_SHA1_80: crypto_policy_set_aes_cm_256_hmac_sha1_80(&policy.rtp); crypto_policy_set_aes_cm_256_hmac_sha1_80(&policy.rtcp); break; case MS_AES_256_SHA1_32: crypto_policy_set_aes_cm_256_hmac_sha1_32(&policy.rtp); crypto_policy_set_aes_cm_256_hmac_sha1_32(&policy.rtcp); break; case MS_CRYPTO_SUITE_INVALID: return -1; break; } key_size = b64_decode(b64_key, b64_key_length, 0, 0); if (key_size != policy.rtp.cipher_key_len) { ortp_error("Key size (%d) doesn't match the selected srtp profile (required %d)", key_size, policy.rtp.cipher_key_len); return -1; } key = (uint8_t*) ortp_malloc0(key_size+2); /*srtp uses padding*/ if (b64_decode(b64_key, b64_key_length, key, key_size) != key_size) { ortp_error("Error decoding key"); ortp_free(key); return -1; } if (!inbound) policy.allow_repeat_tx=1; /*necessary for telephone-events*/ /*ssrc_conf.type=inbound ? ssrc_any_inbound : ssrc_specific;*/ ssrc_conf.type=ssrc_specific; ssrc_conf.value=ssrc; policy.ssrc = ssrc_conf; policy.key = key; policy.next = NULL; err = srtp_add_stream(srtp, &policy); if (err != err_status_ok) { ortp_error("Failed to add stream to srtp session (%d)", err); ortp_free(key); return -1; } ortp_free(key); return 0; }
/* Create a stream in the session */ static err_status_t init_session_stream (GstSrtpDec * filter, guint32 ssrc, GstSrtpDecSsrcStream * stream) { err_status_t ret; srtp_policy_t policy; GstMapInfo map; guchar tmp[1]; memset (&policy, 0, sizeof (srtp_policy_t)); if (!stream) return err_status_bad_param; GST_INFO_OBJECT (filter, "Setting RTP policy..."); set_crypto_policy_cipher_auth (stream->rtp_cipher, stream->rtp_auth, &policy.rtp); GST_INFO_OBJECT (filter, "Setting RTCP policy..."); set_crypto_policy_cipher_auth (stream->rtcp_cipher, stream->rtcp_auth, &policy.rtcp); if (stream->key) { gst_buffer_map (stream->key, &map, GST_MAP_READ); policy.key = (guchar *) map.data; } else { policy.key = tmp; } policy.ssrc.value = ssrc; policy.ssrc.type = ssrc_specific; policy.window_size = filter->replay_window_size; policy.next = NULL; /* If it is the first stream, create the session * If not, add the stream policy to the session */ if (filter->first_session) ret = srtp_create (&filter->session, &policy); else ret = srtp_add_stream (filter->session, &policy); if (stream->key) gst_buffer_unmap (stream->key, &map); if (ret == err_status_ok) { srtp_stream_t srtp_stream; srtp_stream = srtp_get_stream (filter->session, htonl (ssrc)); if (srtp_stream) { /* Here, we just set the ROC, but we also need to set the initial * RTP sequence number later, otherwise libsrtp will not be able * to get the right packet index. */ rdbx_set_roc (&srtp_stream->rtp_rdbx, stream->roc); filter->roc_changed = TRUE; } filter->first_session = FALSE; g_hash_table_insert (filter->streams, GUINT_TO_POINTER (stream->ssrc), stream); } return ret; }
srtp_err_status_t test_dtls_srtp(void) { srtp_hdr_t *test_packet; int test_packet_len = 80; srtp_t s; srtp_policy_t policy; uint8_t key[SRTP_MAX_KEY_LEN]; uint8_t salt[SRTP_MAX_KEY_LEN]; unsigned int key_len, salt_len; srtp_profile_t profile; srtp_err_status_t err; /* create a 'null' SRTP session */ err = srtp_create(&s, NULL); if (err) return err; /* * verify that packet-processing functions behave properly - we * expect that these functions will return srtp_err_status_no_ctx */ test_packet = srtp_create_test_packet(80, 0xa5a5a5a5); if (test_packet == NULL) return srtp_err_status_alloc_fail; err = srtp_protect(s, test_packet, &test_packet_len); if (err != srtp_err_status_no_ctx) { printf("wrong return value from srtp_protect() (got code %d)\n", err); return srtp_err_status_fail; } err = srtp_unprotect(s, test_packet, &test_packet_len); if (err != srtp_err_status_no_ctx) { printf("wrong return value from srtp_unprotect() (got code %d)\n", err); return srtp_err_status_fail; } err = srtp_protect_rtcp(s, test_packet, &test_packet_len); if (err != srtp_err_status_no_ctx) { printf("wrong return value from srtp_protect_rtcp() (got code %d)\n", err); return srtp_err_status_fail; } err = srtp_unprotect_rtcp(s, test_packet, &test_packet_len); if (err != srtp_err_status_no_ctx) { printf("wrong return value from srtp_unprotect_rtcp() (got code %d)\n", err); return srtp_err_status_fail; } /* * set keys to known values for testing */ profile = srtp_profile_aes128_cm_sha1_80; key_len = srtp_profile_get_master_key_length(profile); salt_len = srtp_profile_get_master_salt_length(profile); memset(key, 0xff, key_len); memset(salt, 0xee, salt_len); srtp_append_salt_to_key(key, key_len, salt, salt_len); policy.key = key; /* initialize SRTP policy from profile */ err = srtp_crypto_policy_set_from_profile_for_rtp(&policy.rtp, profile); if (err) return err; err = srtp_crypto_policy_set_from_profile_for_rtcp(&policy.rtcp, profile); if (err) return err; policy.ssrc.type = ssrc_any_inbound; policy.ekt = NULL; policy.window_size = 128; policy.allow_repeat_tx = 0; policy.next = NULL; err = srtp_add_stream(s, &policy); if (err) return err; err = srtp_dealloc(s); if (err) return err; free(test_packet); return srtp_err_status_ok; }
void * receiver_thread (void *arg) { err_status_t status; rtp_receiver_t rcvr[NUM_SSRC_PER_THREAD]; int cnt = 0; thread_parms_t *tp = (thread_parms_t*)arg; int len = DATA_LEN; char data[DATA_LEN + RTP_HEADER_LEN + 20]; //Adding 20 bytes for UDP header??? srtp_ctx_t *srtp_ctx = NULL; int i; printf("\nStarting receiver thread (port: %d base-ssrc: %x stream_cnt: %d)\n", tp->port, tp->ssrc, tp->stream_cnt); if (bind(tp->sock, (struct sockaddr*)&tp->name, sizeof(tp->name)) < 0) { close(tp->sock); pthread_mutex_lock(&t_mutex); fprintf(output, "receiver socket bind error\n"); fflush(output); pthread_mutex_unlock(&t_mutex); perror(NULL); exit(1); } status = srtp_create(&srtp_ctx, tp->policy); if (status) { pthread_mutex_lock(&t_mutex); fprintf(output, "error: srtp_create() failed with code %d\n", status); fflush(output); pthread_mutex_unlock(&t_mutex); exit(1); } /* now add the streams on the session */ for (i = 0; i < tp->stream_cnt; i++) { rtp_receiver_init(&rcvr[i], tp->sock, tp->name, tp->ssrc); rcvr[i].srtp_ctx = srtp_ctx; status = srtp_add_stream(rcvr[i].srtp_ctx, tp->policy); if (status) { pthread_mutex_lock(&t_mutex); fprintf(output, "error: srtp_add_stream() failed with code %d\n", status); fflush(output); pthread_mutex_unlock(&t_mutex); exit(1); } tp->policy->ssrc.value++; tp->ssrc++; } /* get next packet and loop */ while (cnt < THREAD_PKT_CNT) { len = DATA_LEN + RTP_HEADER_LEN + 20; if (rtp_recvfrom(&rcvr[0], data, &len) > -1) { cnt++; if (cnt % STAT_WINDOW == 0) { pthread_mutex_lock(&t_mutex); fprintf(output, "Thread id %d receive count is %d\n", tp->thread_num, cnt); fflush(output); pthread_mutex_unlock(&t_mutex); } } } /* * Clean up the session */ srtp_dealloc(srtp_ctx); return (NULL); }