static vod_status_t mp4_encrypt_video_snpf_build_auxiliary_data(mp4_encrypt_video_state_t* state) { u_char iv[MP4_AES_CTR_IV_SIZE]; uint32_t bytes_of_encrypted_data; uint16_t bytes_of_clear_data; bool_t init_track; u_char* p; state->default_auxiliary_sample_size = sizeof(cenc_sample_auxiliary_data_t) + sizeof(cenc_sample_auxiliary_data_subsample_t); state->saiz_sample_count = state->base.sequence->total_frame_count; p = vod_alloc( state->base.request_context->pool, state->default_auxiliary_sample_size * state->base.sequence->total_frame_count); if (p == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, state->base.request_context->log, 0, "mp4_encrypt_video_snpf_build_auxiliary_data: vod_alloc failed"); return VOD_ALLOC_FAILED; } state->auxiliary_data.start = p; bytes_of_clear_data = state->base.cur_clip->first_track->media_info.u.video.nal_packet_size_length + 1; vod_memcpy(iv, state->base.iv, sizeof(iv)); for (;;) { if (!mp4_encrypt_move_to_next_frame(&state->base, &init_track)) { break; } if (init_track) { bytes_of_clear_data = state->base.cur_clip->first_track->media_info.u.video.nal_packet_size_length + 1; } // cenc_sample_auxiliary_data_t p = vod_copy(p, iv, sizeof(iv)); mp4_aes_ctr_increment_be64(iv); write_be16(p, 1); // subsample count // cenc_sample_auxiliary_data_subsample_t bytes_of_encrypted_data = state->base.cur_frame->size - bytes_of_clear_data; write_be16(p, bytes_of_clear_data); write_be32(p, bytes_of_encrypted_data); state->base.cur_frame++; } state->auxiliary_data.pos = p; // reset the state state->base.cur_clip = state->base.sequence->filtered_clips; mp4_encrypt_init_track(&state->base, state->base.cur_clip->first_track); return VOD_OK; }
u_char* mp4_encrypt_audio_write_auxiliary_data(mp4_encrypt_state_t* state, u_char* p) { u_char* end_pos = p + sizeof(state->iv) * state->sequence->total_frame_count; u_char iv[MP4_AES_CTR_IV_SIZE]; vod_memcpy(iv, state->iv, sizeof(iv)); while (p < end_pos) { p = vod_copy(p, iv, sizeof(iv)); mp4_aes_ctr_increment_be64(iv); } return p; }
vod_status_t mp4_aes_ctr_process(mp4_aes_ctr_state_t* state, u_char* dest, const u_char* src, uint32_t size) { const u_char* src_end = src + size; const u_char* cur_end_pos; u_char* encrypted_counter_pos; int out_size; while (src < src_end) { if (state->block_offset == 0) { if (1 != EVP_EncryptUpdate( &state->cipher, state->encrypted_counter, &out_size, state->counter, sizeof(state->counter)) || out_size != sizeof(state->encrypted_counter)) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "mp4_aes_ctr_process: EVP_EncryptUpdate failed"); return VOD_UNEXPECTED; } mp4_aes_ctr_increment_be64(state->counter + 8); } encrypted_counter_pos = state->encrypted_counter + state->block_offset; cur_end_pos = src + MP4_AES_CTR_COUNTER_SIZE - state->block_offset; cur_end_pos = vod_min(cur_end_pos, src_end); state->block_offset += cur_end_pos - src; state->block_offset &= (MP4_AES_CTR_COUNTER_SIZE - 1); while (src < cur_end_pos) { *dest++ = *src++ ^ *encrypted_counter_pos++; } } return VOD_OK; }
static vod_status_t mp4_encrypt_start_frame(mp4_encrypt_state_t* state) { // make sure we have a frame if (state->cur_frame >= state->last_frame) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "mp4_encrypt_start_frame: no more frames"); return VOD_BAD_DATA; } // get the frame size state->frame_size_left = state->cur_frame->size; state->cur_frame++; // set and increment the iv mp4_aes_ctr_set_iv(&state->cipher, state->iv); mp4_aes_ctr_increment_be64(state->iv); return VOD_OK; }
vod_status_t mp4_aes_ctr_process(mp4_aes_ctr_state_t* state, u_char* dest, const u_char* src, uint32_t size) { const u_char* src_end = src + size; const u_char* cur_end_pos; u_char* encrypted_counter_pos; u_char* cur_block; u_char* next_block; u_char* end_block; size_t encrypted_size; int out_size; while (src < src_end) { if (state->encrypted_pos >= state->encrypted_end) { // find the size of the data to encrypt encrypted_size = aes_round_up_to_block_exact(src_end - src); if (encrypted_size > sizeof(state->counter)) { encrypted_size = sizeof(state->counter); } // initialize the clear counters (the first counter is already initialized) end_block = state->counter + encrypted_size - AES_BLOCK_SIZE; for (cur_block = state->counter; cur_block < end_block; cur_block = next_block) { next_block = cur_block + AES_BLOCK_SIZE; vod_memcpy(next_block, cur_block, AES_BLOCK_SIZE); mp4_aes_ctr_increment_be64(next_block + 8); } // encrypt the clear counters if (1 != EVP_EncryptUpdate( &state->cipher, state->encrypted_counter, &out_size, state->counter, encrypted_size) || out_size != (int)encrypted_size) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "mp4_aes_ctr_process: EVP_EncryptUpdate failed"); return VOD_UNEXPECTED; } // update the first counter if (encrypted_size > AES_BLOCK_SIZE) { vod_memcpy(state->counter, end_block, AES_BLOCK_SIZE); } mp4_aes_ctr_increment_be64(state->counter + 8); state->encrypted_end = state->encrypted_counter + encrypted_size; encrypted_counter_pos = state->encrypted_counter; cur_end_pos = src + encrypted_size; } else { encrypted_counter_pos = state->encrypted_pos; cur_end_pos = src + (state->encrypted_end - encrypted_counter_pos); } if (src_end < cur_end_pos) { cur_end_pos = src_end; } while (src < cur_end_pos) { *dest++ = *src++ ^ *encrypted_counter_pos++; } state->encrypted_pos = encrypted_counter_pos; } return VOD_OK; }