Skip to content

Commit 51c53e9

Browse files
committed
Add: PoC of video frames encryption using AES-CTR
This PoC demonstrates the use of AES-CTR encryption of video frames transmitted between the Tx and Rx sessions. It shows that video frames can be treated as binary blobs that could be encrypted. The PoC uses https://github.com/intel/intel-ipsec-mb for the AES-CTR encryption. Sample file can be generated with: ``` ffmpeg -an -y -f lavfi -i \ testsrc=d=5:s=1920x1080:r=25,format=yuv422p10be -f rawvideo \ /tmp/yuv422p10le.yuv ``` To run PoC: ``` ./tests/tools/RxTxApp/build/RxTxApp --config_file \ config/tx-rx-encryption.json --test_time=10 ``` RxTxApp sends the input file in a loop, the output file can have data from the input file written to in multiple times. known issues: - There is no key exchange mechanism implemented in this PoC, the key is hardcoded in the code. - Transport format has to be the same as the input format. Mismatch causes corruption of the data - It works only for uncompressed video formats. (not for SMPTE 2110-22) - Everything is done in an application instead of in the library
1 parent fcefbb9 commit 51c53e9

File tree

5 files changed

+192
-3
lines changed

5 files changed

+192
-3
lines changed

config/tx-rx-encryption.json

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
{
2+
"tx_no_chain": false,
3+
"interfaces": [
4+
{
5+
"name": "0000:4b:01.0",
6+
"ip": "192.168.17.101"
7+
},
8+
{
9+
"name": "0000:4b:01.1",
10+
"ip": "192.168.17.102"
11+
}
12+
],
13+
"tx_sessions": [
14+
{
15+
"dip": [
16+
"192.168.17.102"
17+
],
18+
"interface": [
19+
0
20+
],
21+
"video": [],
22+
"st20p": [
23+
{
24+
"replicas": 1,
25+
"start_port": 20000,
26+
"payload_type": 112,
27+
"width": 1920,
28+
"height": 1080,
29+
"fps": "p25",
30+
"interlaced": false,
31+
"device": "AUTO",
32+
"pacing": "gap",
33+
"packing": "BPM",
34+
"input_format": "YUV422RFC4175PG2BE10",
35+
"transport_format": "YUV_422_10bit",
36+
"st20p_url": "/tmp/yuv422p10be.yuv",
37+
"display": false,
38+
"enable_rtcp": false
39+
}
40+
],
41+
"st22p": [],
42+
"st30p": [],
43+
"audio": [],
44+
"ancillary": [],
45+
"fastmetadata": []
46+
}
47+
],
48+
"rx_sessions": [
49+
{
50+
"ip": [
51+
"192.168.17.101"
52+
],
53+
"interface": [
54+
1
55+
],
56+
"video": [],
57+
"st20p": [
58+
{
59+
"replicas": 1,
60+
"start_port": 20000,
61+
"payload_type": 112,
62+
"width": 1920,
63+
"height": 1080,
64+
"fps": "p25",
65+
"interlaced": false,
66+
"device": "AUTO",
67+
"pacing": "gap",
68+
"packing": "BPM",
69+
"output_format": "YUV422RFC4175PG2BE10",
70+
"transport_format": "YUV_422_10bit",
71+
"measure_latency": false,
72+
"display": false,
73+
"enable_rtcp": false,
74+
"st20p_url": "/tmp/out.yuv"
75+
}
76+
],
77+
"st22p": [],
78+
"st30p": [],
79+
"audio": [],
80+
"ancillary": [],
81+
"fastmetadata": []
82+
}
83+
]
84+
}

tests/tools/RxTxApp/meson.build

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ libm = cc.find_library('m', required : true)
2424
libpthread = cc.find_library('pthread', required : true)
2525
libjson_c = dependency('json-c', required : true)
2626
libpcap = dependency('pcap', required: true)
27+
libIPSec_MB = cc.find_library('IPSec_MB', required: true)
28+
2729

2830
libsdl2 = dependency('sdl2', required: false)
2931
if libsdl2.found()
@@ -90,5 +92,5 @@ executable('RxTxApp', sources,
9092
c_args : app_c_args,
9193
link_args: app_ld_args,
9294
# asan should be always the first dep
93-
dependencies: [asan_dep, mtl, libjson_c, libpcap, libsdl2, libsdl2_ttf, libm, libpthread, ws2_32_dep, mman_dep, libopenssl]
95+
dependencies: [asan_dep, mtl, libjson_c, libpcap, libsdl2, libsdl2_ttf, libm, libpthread, ws2_32_dep, mman_dep, libopenssl, libIPSec_MB]
9496
)

tests/tools/RxTxApp/src/app_base.h

+2
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,8 @@ struct st_app_rx_st20p_session {
558558

559559
bool measure_latency;
560560
uint64_t stat_latency_us_sum;
561+
562+
void* tmp_framebuff;
561563
};
562564

563565
struct st_app_tx_st30p_session {

tests/tools/RxTxApp/src/rx_st20p_app.c

+55-1
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,54 @@
44

55
#include "rx_st20p_app.h"
66

7+
#include <intel-ipsec-mb.h>
8+
9+
static IMB_MGR* mgr;
10+
11+
static uint8_t cipher_key[16] = {0};
12+
static uint8_t cipher_iv[16] = {0};
13+
DECLARE_ALIGNED(static uint32_t exp_enc_key[4 * 15], 16);
14+
DECLARE_ALIGNED(static uint32_t exp_dec_key[4 * 15], 16);
15+
static IMB_JOB* job;
16+
717
static void app_rx_st20p_consume_frame(struct st_app_rx_st20p_session* s,
818
struct st_frame* frame) {
919
struct st_display* d = s->display;
1020
int idx = s->idx;
1121

1222
if (s->st20p_destination_file) {
13-
if (!fwrite(frame->addr[0], 1, s->st20p_frame_size, s->st20p_destination_file)) {
23+
job = IMB_GET_NEXT_JOB(mgr);
24+
job->src = frame->addr[0];
25+
job->dst = s->tmp_framebuff;
26+
job->cipher_mode = IMB_CIPHER_CNTR;
27+
job->hash_alg = IMB_AUTH_NULL;
28+
job->enc_keys = exp_enc_key;
29+
job->dec_keys = exp_dec_key;
30+
job->iv = cipher_iv;
31+
job->cipher_direction = IMB_DIR_DECRYPT;
32+
job->chain_order = IMB_ORDER_HASH_CIPHER;
33+
job->key_len_in_bytes = 16;
34+
job->iv_len_in_bytes = 16;
35+
job->cipher_start_src_offset_in_bytes = 0;
36+
job->msg_len_to_cipher_in_bytes = s->st20p_frame_size;
37+
job = IMB_SUBMIT_JOB(mgr);
38+
if (job == NULL) {
39+
const int err = imb_get_errno(mgr);
40+
printf(
41+
"%d Unexpected null return from submit job()\n"
42+
"\t Error code %d, %s\n",
43+
__LINE__, err, imb_get_strerror(err));
44+
exit(1);
45+
}
46+
if (job->status != IMB_STATUS_COMPLETED) {
47+
const int err = imb_get_errno(mgr);
48+
printf(
49+
"%d Wrong job status\n"
50+
"\t Error code %d, %s\n",
51+
__LINE__, err, imb_get_strerror(err));
52+
}
53+
54+
if (!fwrite(s->tmp_framebuff, 1, s->st20p_frame_size, s->st20p_destination_file)) {
1455
err("%s(%d), failed to write frame to file %s\n", __func__, idx,
1556
s->st20p_destination_url);
1657
}
@@ -57,6 +98,10 @@ static void* app_rx_st20p_frame_thread(void* arg) {
5798
uint8_t shas[SHA256_DIGEST_LENGTH];
5899
int idx = s->idx;
59100

101+
mgr = alloc_mb_mgr(0);
102+
init_mb_mgr_auto(mgr, NULL);
103+
IMB_AES_KEYEXP_128(mgr, cipher_key, exp_enc_key, exp_dec_key);
104+
60105
info("%s(%d), start\n", __func__, s->idx);
61106
while (!s->st20p_app_thread_stop) {
62107
frame = st20p_rx_get_frame(s->handle);
@@ -103,6 +148,8 @@ static void* app_rx_st20p_frame_thread(void* arg) {
103148
}
104149
info("%s(%d), stop\n", __func__, s->idx);
105150

151+
free_mb_mgr(mgr);
152+
106153
return NULL;
107154
}
108155

@@ -286,6 +333,12 @@ static int app_rx_st20p_init(struct st_app_context* ctx,
286333
s->handle = handle;
287334

288335
s->st20p_frame_size = st20p_rx_frame_size(handle);
336+
s->tmp_framebuff = malloc(s->st20p_frame_size);
337+
if (!s->tmp_framebuff) {
338+
err("%s(%d), failed to allocate tmp frame buffer\n", __func__, idx);
339+
app_rx_st20p_uinit(s);
340+
return -ENOMEM;
341+
}
289342

290343
ret = app_rx_st20p_init_frame_thread(s);
291344
if (ret < 0) {
@@ -374,6 +427,7 @@ int st_app_rx_st20p_sessions_uinit(struct st_app_context* ctx) {
374427
for (i = 0; i < ctx->rx_st20p_session_cnt; i++) {
375428
s = &ctx->rx_st20p_sessions[i];
376429
app_rx_st20p_uinit(s);
430+
free(s->tmp_framebuff);
377431
}
378432
st_app_free(ctx->rx_st20p_sessions);
379433

tests/tools/RxTxApp/src/tx_st20p_app.c

+48-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@
44

55
#include "tx_st20p_app.h"
66

7+
#include <intel-ipsec-mb.h>
8+
9+
static IMB_MGR* mgr;
10+
11+
static uint8_t cipher_key[16] = {0};
12+
static uint8_t cipher_iv[16] = {0};
13+
DECLARE_ALIGNED(static uint32_t exp_enc_key[4 * 15], 16);
14+
DECLARE_ALIGNED(static uint32_t exp_dec_key[4 * 15], 16);
15+
static IMB_JOB* job;
16+
717
static void app_tx_st20p_display_frame(struct st_app_tx_st20p_session* s,
818
struct st_frame* frame) {
919
struct st_display* d = s->display;
@@ -46,7 +56,38 @@ static void app_tx_st20p_build_frame(struct st_app_tx_st20p_session* s,
4656
uint8_t* src = s->st20p_frame_cursor;
4757

4858
if (!s->ctx->tx_copy_once || !s->st20p_frames_copied) {
49-
mtl_memcpy(frame->addr[0], src, frame_size);
59+
// mtl_memcpy(frame->addr[0], src, frame_size);
60+
job = IMB_GET_NEXT_JOB(mgr);
61+
job->src = src;
62+
job->dst = frame->addr[0];
63+
job->cipher_mode = IMB_CIPHER_CNTR;
64+
job->hash_alg = IMB_AUTH_NULL;
65+
job->enc_keys = exp_enc_key;
66+
job->dec_keys = exp_dec_key;
67+
job->iv = cipher_iv;
68+
job->cipher_direction = IMB_DIR_ENCRYPT;
69+
job->chain_order = IMB_ORDER_CIPHER_HASH;
70+
job->key_len_in_bytes = 16;
71+
job->iv_len_in_bytes = 16;
72+
job->cipher_start_src_offset_in_bytes = 0;
73+
job->msg_len_to_cipher_in_bytes = frame_size;
74+
job = IMB_SUBMIT_JOB(mgr);
75+
if (job == NULL) {
76+
const int err = imb_get_errno(mgr);
77+
printf(
78+
"%d Unexpected null return from submit job()\n"
79+
"\t Error code %d, %s\n",
80+
__LINE__, err, imb_get_strerror(err));
81+
exit(1);
82+
}
83+
if (job->status != IMB_STATUS_COMPLETED) {
84+
const int err = imb_get_errno(mgr);
85+
printf(
86+
"%d Wrong job status\n"
87+
"\t Error code %d, %s\n",
88+
__LINE__, err, imb_get_strerror(err));
89+
exit(1);
90+
}
5091
}
5192
/* point to next frame */
5293
s->st20p_frame_cursor += frame_size;
@@ -65,6 +106,10 @@ static void* app_tx_st20p_frame_thread(void* arg) {
65106
struct st_frame* frame;
66107
uint8_t shas[SHA256_DIGEST_LENGTH];
67108

109+
mgr = alloc_mb_mgr(0);
110+
init_mb_mgr_auto(mgr, NULL);
111+
IMB_AES_KEYEXP_128(mgr, cipher_key, exp_enc_key, exp_dec_key);
112+
68113
info("%s(%d), start\n", __func__, idx);
69114
while (!s->st20p_app_thread_stop) {
70115
frame = st20p_tx_get_frame(handle);
@@ -82,6 +127,8 @@ static void* app_tx_st20p_frame_thread(void* arg) {
82127
}
83128
info("%s(%d), stop\n", __func__, idx);
84129

130+
free_mb_mgr(mgr);
131+
85132
return NULL;
86133
}
87134

0 commit comments

Comments
 (0)