📄 srtp.c
字号:
/* we assume the hdr is 32-bit aligned to start */ /* * look up ssrc in srtp_stream list, and process the packet with * the appropriate stream. if we haven't seen this stream before, * there's only one key for this srtp_session, and the cipher * supports key-sharing, then we assume that a new stream using * that key has just started up */ stream = srtp_get_stream(ctx, hdr->ssrc); if (stream == NULL) { if (ctx->stream_template != NULL) { srtp_stream_ctx_t *new_stream; /* allocate and initialize a new stream */ status = srtp_stream_clone(ctx->stream_template, hdr->ssrc, &new_stream); if (status) return status; /* add new stream to the head of the stream_list */ new_stream->next = ctx->stream_list; ctx->stream_list = new_stream; /* set stream (the pointer used in this function) */ stream = new_stream; } else { /* no template stream, so we return an error */ return err_status_no_ctx; } } /* * verify that stream is for sending traffic - this check will * detect SSRC collisions, since a stream that appears in both * srtp_protect() and srtp_unprotect() will fail this test in one of * those functions. */ if (stream->direction != dir_srtp_sender) { if (stream->direction == dir_unknown) { stream->direction = dir_srtp_sender; } else { srtp_handle_event(ctx, stream, event_ssrc_collision); } } /* get tag length from stream context */ tag_len = auth_get_tag_length(stream->rtcp_auth); /* * set encryption start and encryption length - if we're not * providing confidentiality, set enc_start to NULL */ enc_start = (uint32_t *)hdr + uint32s_in_rtcp_header; enc_octet_len = *pkt_octet_len - octets_in_rtcp_header; /* all of the packet, except the header, gets encrypted */ /* NOTE: hdr->length is not usable - it refers to only the first RTCP report in the compound packet! */ /* NOTE: trailer is 32-bit aligned because RTCP 'packets' are always multiples of 32-bits (RFC 3550 6.1) */ trailer = (uint32_t *) ((char *)enc_start + enc_octet_len); if (stream->rtcp_services & sec_serv_conf) { *trailer = htonl(SRTCP_E_BIT); /* set encrypt bit */ } else { enc_start = NULL; enc_octet_len = 0; /* 0 is network-order independant */ *trailer = 0x00000000; /* set encrypt bit */ } /* * set the auth_start and auth_tag pointers to the proper locations * (note that srtpc *always* provides authentication, unlike srtp) */ /* Note: This would need to change for optional mikey data */ auth_start = (uint32_t *)hdr; auth_tag = (uint8_t *)hdr + *pkt_octet_len + sizeof(srtcp_trailer_t); /* * check sequence number for overruns, and copy it into the packet * if its value isn't too big */ status = rdb_increment(&stream->rtcp_rdb); if (status) return status; seq_num = rdb_get_value(&stream->rtcp_rdb); *trailer |= htonl(seq_num); debug_print(mod_srtp, "srtcp index: %x", seq_num); /* * if we're using rindael counter mode, set nonce and seq */ if (stream->rtcp_cipher->type == &aes_icm) { v128_t iv; iv.v32[0] = 0; iv.v32[1] = hdr->ssrc; /* still in network order! */ iv.v32[2] = htonl(seq_num >> 16); iv.v32[3] = htonl(seq_num << 16); status = aes_icm_set_iv((aes_icm_ctx_t*)stream->rtcp_cipher->state, &iv); } else { v128_t iv; /* otherwise, just set the index to seq_num */ iv.v32[0] = 0; iv.v32[1] = 0; iv.v32[2] = 0; iv.v32[3] = htonl(seq_num); status = cipher_set_iv(stream->rtcp_cipher, &iv); } if (status) return err_status_cipher_fail; /* * if we're authenticating using a universal hash, put the keystream * prefix into the authentication tag */ /* if auth_start is non-null, then put keystream into tag */ if (auth_start) { /* put keystream prefix into auth_tag */ prefix_len = auth_get_prefix_length(stream->rtcp_auth); status = cipher_output(stream->rtcp_cipher, auth_tag, prefix_len); debug_print(mod_srtp, "keystream prefix: %s", octet_string_hex_string(auth_tag, prefix_len)); if (status) return err_status_cipher_fail; } /* if we're encrypting, exor keystream into the message */ if (enc_start) { status = cipher_encrypt(stream->rtcp_cipher, (uint8_t *)enc_start, &enc_octet_len); if (status) return err_status_cipher_fail; } /* initialize auth func context */ auth_start(stream->rtcp_auth); /* * run auth func over packet (including trailer), and write the * result at auth_tag */ status = auth_compute(stream->rtcp_auth, (uint8_t *)auth_start, (*pkt_octet_len) + sizeof(srtcp_trailer_t), auth_tag); debug_print(mod_srtp, "srtcp auth tag: %s", octet_string_hex_string(auth_tag, tag_len)); if (status) return err_status_auth_fail; /* increase the packet length by the length of the auth tag and seq_num*/ *pkt_octet_len += (tag_len + sizeof(srtcp_trailer_t)); return err_status_ok; }err_status_t srtp_unprotect_rtcp(srtp_t ctx, void *srtcp_hdr, int *pkt_octet_len) { srtcp_hdr_t *hdr = (srtcp_hdr_t *)srtcp_hdr; uint32_t *enc_start; /* pointer to start of encrypted portion */ uint32_t *auth_start; /* pointer to start of auth. portion */ uint32_t *trailer; /* pointer to start of trailer */ unsigned enc_octet_len = 0;/* number of octets in encrypted portion */ uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ uint8_t tmp_tag[SRTP_MAX_TAG_LEN]; err_status_t status; int tag_len; srtp_stream_ctx_t *stream; int prefix_len; uint32_t seq_num; /* we assume the hdr is 32-bit aligned to start */ /* * look up ssrc in srtp_stream list, and process the packet with * the appropriate stream. if we haven't seen this stream before, * there's only one key for this srtp_session, and the cipher * supports key-sharing, then we assume that a new stream using * that key has just started up */ stream = srtp_get_stream(ctx, hdr->ssrc); if (stream == NULL) { if (ctx->stream_template != NULL) { stream = ctx->stream_template; debug_print(mod_srtp, "srtcp using provisional stream (SSRC: 0x%08x)", hdr->ssrc); } else { /* no template stream, so we return an error */ return err_status_no_ctx; } } /* get tag length from stream context */ tag_len = auth_get_tag_length(stream->rtcp_auth); /* * set encryption start, encryption length, and trailer */ enc_octet_len = *pkt_octet_len - (octets_in_rtcp_header + tag_len + sizeof(srtcp_trailer_t)); /* index & E (encryption) bit follow normal data. hdr->len is the number of words (32-bit) in the normal packet minus 1 */ /* This should point trailer to the word past the end of the normal data. */ /* This would need to be modified for optional mikey data */ /* * NOTE: trailer is 32-bit aligned because RTCP 'packets' are always * multiples of 32-bits (RFC 3550 6.1) */ trailer = (uint32_t *) ((char *) hdr + *pkt_octet_len -(tag_len + sizeof(srtcp_trailer_t))); if (*((unsigned char *) trailer) & SRTCP_E_BYTE_BIT) { enc_start = (uint32_t *)hdr + uint32s_in_rtcp_header; } else { enc_octet_len = 0; enc_start = NULL; /* this indicates that there's no encryption */ } /* * set the auth_start and auth_tag pointers to the proper locations * (note that srtcp *always* uses authentication, unlike srtp) */ auth_start = (uint32_t *)hdr; auth_tag = (uint8_t *)hdr + *pkt_octet_len - tag_len; /* * check the sequence number for replays */ /* this is easier than dealing with bitfield access */ seq_num = ntohl(*trailer) & SRTCP_INDEX_MASK; debug_print(mod_srtp, "srtcp index: %x", seq_num); status = rdb_check(&stream->rtcp_rdb, seq_num); if (status) return status; /* * if we're using aes counter mode, set nonce and seq */ if (stream->rtcp_cipher->type == &aes_icm) { v128_t iv; iv.v32[0] = 0; iv.v32[1] = hdr->ssrc; /* still in network order! */ iv.v32[2] = htonl(seq_num >> 16); iv.v32[3] = htonl(seq_num << 16); status = aes_icm_set_iv((aes_icm_ctx_t*)stream->rtcp_cipher->state, &iv); } else { v128_t iv; /* otherwise, just set the index to seq_num */ iv.v32[0] = 0; iv.v32[1] = 0; iv.v32[2] = 0; iv.v32[3] = htonl(seq_num); status = cipher_set_iv(stream->rtcp_cipher, &iv); } if (status) return err_status_cipher_fail; /* initialize auth func context */ auth_start(stream->rtcp_auth); /* run auth func over packet, put result into tmp_tag */ status = auth_compute(stream->rtcp_auth, (uint8_t *)auth_start, *pkt_octet_len - tag_len, tmp_tag); debug_print(mod_srtp, "srtcp computed tag: %s", octet_string_hex_string(tmp_tag, tag_len)); if (status) return err_status_auth_fail; /* compare the tag just computed with the one in the packet */ debug_print(mod_srtp, "srtcp tag from packet: %s", octet_string_hex_string(auth_tag, tag_len)); if (octet_string_is_eq(tmp_tag, auth_tag, tag_len)) return err_status_auth_fail; /* * if we're authenticating using a universal hash, put the keystream * prefix into the authentication tag */ prefix_len = auth_get_prefix_length(stream->rtcp_auth); if (prefix_len) { status = cipher_output(stream->rtcp_cipher, auth_tag, prefix_len); debug_print(mod_srtp, "keystream prefix: %s", octet_string_hex_string(auth_tag, prefix_len)); if (status) return err_status_cipher_fail; } /* if we're decrypting, exor keystream into the message */ if (enc_start) { status = cipher_encrypt(stream->rtcp_cipher, (uint8_t *)enc_start, &enc_octet_len); if (status) return err_status_cipher_fail; } /* decrease the packet length by the length of the auth tag and seq_num*/ *pkt_octet_len -= (tag_len + sizeof(srtcp_trailer_t)); /* * verify that stream is for received traffic - this check will * detect SSRC collisions, since a stream that appears in both * srtp_protect() and srtp_unprotect() will fail this test in one of * those functions. * * we do this check *after* the authentication check, so that the * latter check will catch any attempts to fool us into thinking * that we've got a collision */ if (stream->direction != dir_srtp_receiver) { if (stream->direction == dir_unknown) { stream->direction = dir_srtp_receiver; } else { srtp_handle_event(ctx, stream, event_ssrc_collision); } } /* * if the stream is a 'provisional' one, in which the template context * is used, then we need to allocate a new stream at this point, since * the authentication passed */ if (stream == ctx->stream_template) { srtp_stream_ctx_t *new_stream; /* * allocate and initialize a new stream * * note that we indicate failure if we can't allocate the new * stream, and some implementations will want to not return * failure here */ status = srtp_stream_clone(ctx->stream_template, hdr->ssrc, &new_stream); if (status) return status; /* add new stream to the head of the stream_list */ new_stream->next = ctx->stream_list; ctx->stream_list = new_stream; /* set stream (the pointer used in this function) */ stream = new_stream; } /* we've passed the authentication check, so add seq_num to the rdb */ rdb_add_index(&stream->rtcp_rdb, seq_num); return err_status_ok; }/* * dtls keying for srtp */err_status_tcrypto_policy_set_from_profile_for_rtp(crypto_policy_t *policy, srtp_profile_t profile) { /* set SRTP policy from the SRTP profile in the key set */ switch(profile) { case srtp_profile_aes128_cm_sha1_80: crypto_policy_set_aes_cm_128_hmac_sha1_80(policy); crypto_policy_set_aes_cm_128_hmac_sha1_80(policy); break; case srtp_profile_aes128_cm_sha1_32: crypto_policy_set_aes_cm_128_hmac_sha1_32(policy); crypto_policy_set_aes_cm_128_hmac_sha1_80(policy); break; case srtp_profile_null_sha1_80: crypto_policy_set_null_cipher_hmac_sha1_80(policy); crypto_policy_set_null_cipher_hmac_sha1_80(policy); break; /* the following profiles are not (yet) supported */ case srtp_profile_null_sha1_32: case srtp_profile_aes256_cm_sha1_80: case srtp_profile_aes256_cm_sha1_32: default: return err_status_bad_param; } return err_status_ok;}err_status_tcrypto_policy_set_from_profile_for_rtcp(crypto_policy_t *policy, srtp_profile_t profile) { /* set SRTP policy from the SRTP profile in the key set */ switch(profile) { case srtp_profile_aes128_cm_sha1_80: crypto_policy_set_aes_cm_128_hmac_sha1_80(policy); break; case srtp_profile_aes128_cm_sha1_32: crypto_policy_set_aes_cm_128_hmac_sha1_80(policy); break; case srtp_profile_null_sha1_80: crypto_policy_set_null_cipher_hmac_sha1_80(policy); break; /* the following profiles are not (yet) supported */ case srtp_profile_null_sha1_32: case srtp_profile_aes256_cm_sha1_80: case srtp_profile_aes256_cm_sha1_32: default: return err_status_bad_param; } return err_status_ok;}voidappend_salt_to_key(uint8_t *key, unsigned int bytes_in_key, uint8_t *salt, unsigned int bytes_in_salt) { memcpy(key + bytes_in_key, salt, bytes_in_salt);}unsigned intsrtp_profile_get_master_key_length(srtp_profile_t profile) { switch(profile) { case srtp_profile_aes128_cm_sha1_80: return 16; break; case srtp_profile_aes128_cm_sha1_32: return 16; break; case srtp_profile_null_sha1_80: return 16; break; /* the following profiles are not (yet) supported */ case srtp_profile_null_sha1_32: case srtp_profile_aes256_cm_sha1_80: case srtp_profile_aes256_cm_sha1_32: default: return 0; /* indicate error by returning a zero */ }}unsigned intsrtp_profile_get_master_salt_length(srtp_profile_t profile) { switch(profile) { case srtp_profile_aes128_cm_sha1_80: return 14; break; case srtp_profile_aes128_cm_sha1_32: return 14; break; case srtp_profile_null_sha1_80: return 14; break; /* the following profiles are not (yet) supported */ case srtp_profile_null_sha1_32: case srtp_profile_aes256_cm_sha1_80: case srtp_profile_aes256_cm_sha1_32: default: return 0; /* indicate error by returning a zero */ }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -