├── .gitignore ├── DTLS ├── Encryptions │ ├── aes.c │ ├── encryption.c │ ├── encryption.h │ └── rsa.c ├── dtls.c └── dtls.h ├── Documentation ├── RTP_PACKET.png ├── The h.264 Bitstream _ Matthew Szatmary.html ├── aes ├── h264 ├── ice ├── rsa ├── rtp ├── sdp ├── stun └── webrtc ├── GstreamerClient ├── Makefile ├── compile_commands.json ├── webrtc_recv └── webrtc_recv.c ├── ICE ├── ice.c └── ice.h ├── Makefile ├── Network ├── network.c └── network.h ├── README.md ├── RTP ├── rtp.h ├── rtp_session.c └── rtp_stream.c ├── SDP ├── sdp.c └── sdp.h ├── SRTP ├── srtp.c └── srtp.h ├── STUN ├── stun.c └── stun.h ├── SignallingClient ├── signalling_client.c └── signalling_client.h ├── SignallingServer ├── package-lock.json ├── package.json └── signallingServer.js ├── Utils ├── utils.c └── utils.h ├── WebRTC ├── webrtc.c └── webrtc.h ├── WebRTC_Browser_APP ├── package-lock.json ├── package.json ├── public │ ├── peer.html │ └── signalling_client.js └── serv.js ├── compile_commands.json ├── gpl-2.0.md ├── libAV └── read.c ├── minimal_offer.txt ├── parser └── h264_parser │ ├── h264_parser.c │ └── h264_parser.h ├── sample.h264 ├── test ├── mastersecretkey.txt └── test.c └── webrtc_app.c /.gitignore: -------------------------------------------------------------------------------- 1 | SignallingServer/node_modules 2 | WebRTC_Browser_APP/node_modules/ 3 | build/ 4 | video.h264 5 | minimal_offer.txt 6 | .vscode/ 7 | .cache/ 8 | webrtc 9 | SignallingServer/nohup.out 10 | nohup.out 11 | test/dtlsdebug.log 12 | -------------------------------------------------------------------------------- /DTLS/Encryptions/aes.c: -------------------------------------------------------------------------------- 1 | #include "../../Utils/utils.h" 2 | #include "encryption.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define AES_BLOCK_SIZE 16 15 | uint8_t s_box[16][16] = { 16 | {0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 17 | 0xfe, 0xd7, 0xab, 0x76}, 18 | {0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 19 | 0x9c, 0xa4, 0x72, 0xc0}, 20 | {0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 21 | 0x71, 0xd8, 0x31, 0x15}, 22 | {0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 23 | 0xeb, 0x27, 0xb2, 0x75}, 24 | {0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 25 | 0x29, 0xe3, 0x2f, 0x84}, 26 | {0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 27 | 0x4a, 0x4c, 0x58, 0xcf}, 28 | {0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 29 | 0x50, 0x3c, 0x9f, 0xa8}, 30 | {0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 31 | 0x10, 0xff, 0xf3, 0xd2}, 32 | {0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 33 | 0x64, 0x5d, 0x19, 0x73}, 34 | {0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 35 | 0xde, 0x5e, 0x0b, 0xdb}, 36 | {0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 37 | 0x91, 0x95, 0xe4, 0x79}, 38 | {0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 39 | 0x65, 0x7a, 0xae, 0x08}, 40 | {0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 41 | 0x4b, 0xbd, 0x8b, 0x8a}, 42 | {0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 43 | 0x86, 0xc1, 0x1d, 0x9e}, 44 | {0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 45 | 0xce, 0x55, 0x28, 0xdf}, 46 | {0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 47 | 0xb0, 0x54, 0xbb, 0x16}, 48 | }; 49 | uint8_t inv_s_box[16][16] = { 50 | 51 | {0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 52 | 0x81, 0xf3, 0xd7, 0xfb}, 53 | {0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 54 | 0xc4, 0xde, 0xe9, 0xcb}, 55 | {0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 56 | 0x42, 0xfa, 0xc3, 0x4e}, 57 | {0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 58 | 0x6d, 0x8b, 0xd1, 0x25}, 59 | {0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 60 | 0x5d, 0x65, 0xb6, 0x92}, 61 | {0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 62 | 0xa7, 0x8d, 0x9d, 0x84}, 63 | {0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 64 | 0xb8, 0xb3, 0x45, 0x06}, 65 | {0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 66 | 0x01, 0x13, 0x8a, 0x6b}, 67 | {0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 68 | 0xf0, 0xb4, 0xe6, 0x73}, 69 | {0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 70 | 0x1c, 0x75, 0xdf, 0x6e}, 71 | {0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 72 | 0xaa, 0x18, 0xbe, 0x1b}, 73 | {0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 74 | 0x78, 0xcd, 0x5a, 0xf4}, 75 | {0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 76 | 0x27, 0x80, 0xec, 0x5f}, 77 | {0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 78 | 0x93, 0xc9, 0x9c, 0xef}, 79 | {0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 80 | 0x83, 0x53, 0x99, 0x61}, 81 | {0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 82 | 0x55, 0x21, 0x0c, 0x7d}}; 83 | 84 | uint32_t round_constants[] = {0x00000001, 0x00000002, 0x00000004, 0x00000008, 85 | 0x00000010, 0x00000020, 0x00000040, 0x00000080, 86 | 0x0000001b, 0x00000036}; 87 | 88 | uint8_t aes_galois_fild[4][4] = {{0x02, 0x03, 0x01, 0x01}, 89 | {0x01, 0x02, 0x03, 0x01}, 90 | {0x01, 0x01, 0x02, 0x03}, 91 | {0x03, 0x01, 0x01, 0x02}}; 92 | 93 | uint8_t inv_aes_galois_fild[4][4] = {{0x0E, 0x0B, 0x0D, 0x09}, 94 | {0x09, 0x0E, 0x0B, 0x0D}, 95 | {0x0D, 0x09, 0x0E, 0x0B}, 96 | {0x0B, 0x0D, 0x09, 0x0E}}; 97 | 98 | uint32_t g_function(uint32_t word, uint16_t round_num); 99 | bool aes_expand_key(struct AesEnryptionCtx *ctx) { 100 | uint16_t aes_key_len = ctx->key_size; 101 | guchar *key = ctx->initial_key; 102 | 103 | // 104 | // for (int i = 0; i < num_row; i++) { 105 | // memcpy(ctx->initial_key[i], key, num_row); 106 | // key += num_row; 107 | // } 108 | // 109 | // uint32_t round0_key[num_row]; 110 | // for (int i = 0; i < num_row; i++) { 111 | // for (int j = 0; j < num_row; j++) { 112 | // round0_key[i] += ctx->initial_key[i][j]; 113 | // } 114 | // } 115 | 116 | // key expansion 117 | 118 | uint16_t expand_key_len = (aes_key_len * ctx->no_rounds) + aes_key_len; 119 | 120 | uint32_t expanded_keys[expand_key_len]; 121 | 122 | memcpy(expanded_keys, key, aes_key_len); 123 | 124 | uint8_t num_row = ctx->row_size; 125 | 126 | g_debug("aes key len %d expand key up to %d \n", aes_key_len, expand_key_len); 127 | 128 | for (int i = num_row; i <= expand_key_len; i++) { 129 | uint16_t round_num = (((int)floor(i / 4)) - 1); 130 | 131 | if ((i % num_row) == 0) { 132 | expanded_keys[i] = expanded_keys[i - num_row] ^ 133 | g_function(expanded_keys[i - 1], round_num % 10); 134 | continue; 135 | } 136 | expanded_keys[i] = expanded_keys[i - num_row] ^ expanded_keys[i - 1]; 137 | } 138 | 139 | for (int i = 0; i <= ctx->no_rounds; i++) { // one extran key 140 | uint8_t(*round_key)[4] = malloc(aes_key_len); 141 | memcpy(round_key, &(expanded_keys[i * 4]), aes_key_len); 142 | transpose_matrix(round_key); 143 | print_aes_matrix(round_key, 4); 144 | ctx->roundkeys[i] = round_key; 145 | } 146 | 147 | return true; 148 | } 149 | 150 | void transpose_matrix(uint8_t (*round_key)[4]) { 151 | uint8_t temp; 152 | for (int i = 0; i < 4; i++) { 153 | for (int j = i + 1; j < 4; j++) { 154 | temp = round_key[i][j]; 155 | round_key[i][j] = round_key[j][i]; 156 | round_key[j][i] = temp; 157 | } 158 | } 159 | } 160 | uint32_t g_func_sub_byte(uint32_t word) { 161 | uint8_t first_byte; 162 | uint32_t mask = 0xFFFFFFFF; 163 | 164 | for (int i = 0; i <= 3; i++) { 165 | uint8_t byte = ((word & mask) >> (i * 8)); 166 | 167 | uint8_t upper4bit = (byte & 0xF0) >> 4; 168 | uint8_t lower4bit = (byte & 0x0F); 169 | 170 | uint32_t replace_byte = 171 | (((uint32_t)(s_box[upper4bit][lower4bit])) << (i * 8)); 172 | 173 | word = replace_byte | (word & (~((uint32_t)0xFF << (i * 8)))); 174 | // some crazy bit wise shit that I will 175 | // not remember 176 | } 177 | return word; 178 | } 179 | 180 | uint32_t g_function(uint32_t word, uint16_t round_num) { 181 | uint32_t first_byte = (word & 0x000000FF) << (3 * 8); 182 | // g_debug("\n word %x first bypte %x \n", word, first_byte); 183 | word = word >> 8; 184 | word = (word & 0x00FFFFFF) | first_byte; 185 | 186 | // g_debug("rotated %x ", word); 187 | 188 | word = g_func_sub_byte(word); 189 | 190 | // g_debug("subutityed %x %d ", word, round_num); 191 | 192 | return word ^ round_constants[round_num]; 193 | } 194 | 195 | void sub_bytes(uint8_t (*block)[4]) { 196 | g_debug("before sub byte\n"); 197 | print_aes_matrix(block, 4); 198 | 199 | for (int i = 0; i < 4; i++) { 200 | for (int j = 0; j < 4; j++) { 201 | 202 | uint16_t byte = block[i][j]; 203 | uint8_t upper4bit = (byte & 0xF0) >> 4; 204 | uint8_t lower4bit = (byte & 0x0F); 205 | 206 | block[i][j] = s_box[upper4bit][lower4bit]; 207 | } 208 | } 209 | g_debug("after sub byte\n"); 210 | print_aes_matrix(block, 4); 211 | } 212 | 213 | void inv_sub_bytes(uint8_t (*block)[4]) { 214 | g_debug("before sub byte\n"); 215 | print_aes_matrix(block, 4); 216 | 217 | for (int i = 0; i < 4; i++) { 218 | for (int j = 0; j < 4; j++) { 219 | 220 | uint16_t byte = block[i][j]; 221 | uint8_t upper4bit = (byte & 0xF0) >> 4; 222 | uint8_t lower4bit = (byte & 0x0F); 223 | 224 | block[i][j] = inv_s_box[upper4bit][lower4bit]; 225 | } 226 | } 227 | g_debug("after sub byte\n"); 228 | print_aes_matrix(block, 4); 229 | } 230 | 231 | uint8_t gf_mult(uint8_t a, uint8_t b) { 232 | uint8_t p = 0; 233 | uint8_t hi_bit_set; 234 | for (int i = 0; i < 8; i++) { 235 | if (b & 1) { 236 | p ^= a; 237 | } 238 | hi_bit_set = a & 0x80; 239 | a <<= 1; 240 | if (hi_bit_set) { 241 | a ^= 0x1b; // modulo by irreducible polynomial 0x11b 242 | } 243 | b >>= 1; 244 | } 245 | return p; 246 | } 247 | void shift_rows(uint8_t (*block)[4]) { 248 | 249 | g_debug("before shift row\n"); 250 | print_aes_matrix(block, 4); 251 | for (int i = 1; i < 4; i++) { 252 | uint32_t block32 = (*(uint32_t(*)[4])block)[i]; 253 | 254 | uint32_t right_shifted = (block32) << (32 - (i * 8)); 255 | uint32_t left_shifted = (block32) >> ((i * 8)); 256 | 257 | (*(uint32_t(*)[4])block)[i] = right_shifted | left_shifted; 258 | } 259 | 260 | g_debug("after shift row\n"); 261 | print_aes_matrix(block, 4); 262 | } 263 | void inv_shift_rows(uint8_t (*block)[4]) { 264 | 265 | g_debug("before shift row\n"); 266 | print_aes_matrix(block, 4); 267 | for (int i = 1; i < 4; i++) { 268 | uint32_t block32 = (*(uint32_t(*)[4])block)[i]; 269 | 270 | uint32_t right_shifted = (block32) >> (32 - (i * 8)); 271 | uint32_t left_shifted = (block32) << ((i * 8)); 272 | 273 | (*(uint32_t(*)[4])block)[i] = right_shifted | left_shifted; 274 | } 275 | 276 | g_debug("after shift row\n"); 277 | print_aes_matrix(block, 4); 278 | } 279 | void mix_columns(uint8_t (*matrix)[4], uint8_t (*galois_fild)[4]) { 280 | g_debug("befroe mix columns\n"); 281 | uint8_t matrix_sum[4][4] = {0}; 282 | 283 | print_aes_matrix(matrix, 4); 284 | 285 | print_aes_matrix(aes_galois_fild, 4); 286 | 287 | for (int k = 0; k < 4; k++) { 288 | for (int i = 0; i < 4; i++) { 289 | for (int j = 0; j < 4; j++) { 290 | uint8_t mul = gf_mult(galois_fild[k][j], matrix[j][i]); 291 | matrix_sum[k][i] = matrix_sum[k][i] ^ mul; 292 | // g_debug(" %d %d %d %d \[ %d \] \[ %d \] = %x \[ %d \] " 293 | // "\[ %x \] = %x sum = %x %d %d\n", 294 | // k, j, j, i, k, j, aes_galois_fild[k][j], j, i, matrix[j][i], 295 | // matrix_sum[k][i], k, i); 296 | } 297 | } 298 | } 299 | for (int i = 0; i < 4; i++) { 300 | for (int j = 0; j < 4; j++) { 301 | matrix[i][j] = matrix_sum[i][j]; 302 | } 303 | } 304 | 305 | g_debug("after mix columns\n"); 306 | print_aes_matrix(matrix, 4); 307 | } 308 | void add_round_key(uint8_t (*roundkey)[4], uint8_t (*block)[4]) { 309 | 310 | g_debug("add round key before: \n"); 311 | 312 | g_debug("round key:\n"); 313 | print_aes_matrix(roundkey, 4); 314 | 315 | g_debug("block :\n"); 316 | print_aes_matrix(block, 4); 317 | 318 | for (int i = 0; i < 4; i++) { 319 | for (int j = 0; j < 4; j++) { 320 | block[i][j] = block[i][j] ^ roundkey[i][j]; 321 | } 322 | } 323 | 324 | g_debug("after round key :\n"); 325 | print_aes_matrix(block, 4); 326 | } 327 | 328 | void add_vector(uint8_t (*block)[4], uint8_t (*iv)[4]) { 329 | add_round_key(iv, block); 330 | } 331 | void add_aes_padding(uint8_t *block, uint16_t data_len, uint8_t padding_size, 332 | enum mode mode) { 333 | block = block + data_len; 334 | 335 | for (int i = 0; i < padding_size; i++) { 336 | if (mode == CBC) 337 | block[i] = padding_size - 1; 338 | else if (mode == CM) { 339 | printf("why herel"); 340 | block[i] = 0; 341 | } 342 | } 343 | } 344 | 345 | void aes_enc_opp(struct AesEnryptionCtx *ctx, uint8_t (*block)[4]) { 346 | 347 | add_round_key(ctx->roundkeys[0], block); 348 | 349 | for (int i = 1; i <= ctx->no_rounds; i++) { 350 | g_debug("round num :%d", i); 351 | sub_bytes(block); 352 | shift_rows(block); 353 | 354 | if (ctx->no_rounds != i) 355 | mix_columns(block, aes_galois_fild); 356 | 357 | add_round_key(ctx->roundkeys[i], block); 358 | } 359 | } 360 | 361 | uint32_t encrypt_aes(struct AesEnryptionCtx *ctx, uint8_t *block_data, 362 | uint16_t block_encrypt_offset, uint32_t total_packet_len) { 363 | 364 | g_debug("string encryption prooces\n"); 365 | 366 | uint16_t block_len = total_packet_len - block_encrypt_offset; 367 | uint8_t padding_size = AES_BLOCK_SIZE - (block_len % AES_BLOCK_SIZE); 368 | 369 | if (ctx->mode == CM && padding_size == AES_BLOCK_SIZE) { 370 | padding_size = 0; 371 | } 372 | 373 | uint16_t to_encypt_len = block_len + padding_size; 374 | 375 | uint8_t(*block)[4] = (block_data) + block_encrypt_offset; 376 | uint32_t data_encrytion_itration = (to_encypt_len) / AES_BLOCK_SIZE; 377 | 378 | add_aes_padding((uint8_t *)block, block_len, padding_size, ctx->mode); 379 | 380 | memcpy(ctx->recordIV, ctx->IV, AES_BLOCK_SIZE); 381 | 382 | transpose_matrix(ctx->IV); 383 | 384 | uint8_t counter[16]; 385 | for (int j = 0; j < data_encrytion_itration; j++) { 386 | 387 | g_debug("block\n"); 388 | print_hex(block, 16); 389 | g_debug("IV\n"); 390 | print_hex(ctx->IV, 16); 391 | transpose_matrix(block); 392 | 393 | if (ctx->mode == CBC) { 394 | add_vector(block, ctx->IV); 395 | aes_enc_opp(ctx, block); 396 | ctx->IV = block; 397 | } 398 | 399 | if (ctx->mode == CM) { 400 | memcpy(counter, ctx->IV, AES_BLOCK_SIZE); 401 | aes_enc_opp(ctx, counter); 402 | add_vector(block, counter); 403 | increment_counter(ctx->IV); 404 | } 405 | 406 | block = block + 4; 407 | } 408 | 409 | block = (block_data) + block_encrypt_offset; 410 | 411 | for (int i = 0; i < data_encrytion_itration; i++) { 412 | transpose_matrix(block); 413 | block = block + 4; 414 | } 415 | 416 | if (ctx->mode == CBC) 417 | get_random_string((gchar **)&ctx->IV, AES_BLOCK_SIZE, 1); 418 | 419 | return total_packet_len + padding_size; 420 | } 421 | void aes_dec_opp(struct AesEnryptionCtx *ctx, uint8_t (*block)[4]) { 422 | 423 | add_round_key(ctx->roundkeys[ctx->no_rounds], block); 424 | 425 | for (int i = ctx->no_rounds - 1; i >= 0; i--) { 426 | g_debug("round num :%d", i); 427 | inv_shift_rows(block); 428 | inv_sub_bytes(block); 429 | 430 | add_round_key(ctx->roundkeys[i], block); 431 | 432 | if (i != 0) 433 | mix_columns(block, inv_aes_galois_fild); 434 | } 435 | } 436 | uint32_t decrypt_aes(struct AesEnryptionCtx *ctx, uint8_t *block_data, 437 | uint16_t block_decryption_offset, uint32_t data_len) { 438 | 439 | uint8_t(*block)[4] = block_data + block_decryption_offset; 440 | 441 | if (data_len % 16 != 0) 442 | g_error("block len should be in multiple of 16 data len is %d", data_len); 443 | uint32_t data_dencrytion_itration = (data_len) / AES_BLOCK_SIZE; 444 | 445 | transpose_matrix(ctx->IV); 446 | 447 | uint8_t counter[16]; 448 | if (ctx->mode == CBC) { 449 | block = block + ((data_dencrytion_itration - 1) * 4); 450 | transpose_matrix(block); // startiing from last block to avoid mem copy 451 | for (int i = 0; i < data_dencrytion_itration; i++) { 452 | transpose_matrix(block - 4); 453 | aes_dec_opp(ctx, block); 454 | add_vector(block, block - 4); // passing previous block as iv 455 | block = block - 4; 456 | } 457 | } 458 | 459 | if (ctx->mode == CM) 460 | for (int i = 0; i < data_dencrytion_itration; i++) { 461 | transpose_matrix(block); 462 | memcpy(counter, ctx->IV, AES_BLOCK_SIZE); 463 | aes_enc_opp(ctx, counter); 464 | add_vector(block, counter); 465 | increment_counter(ctx->IV); 466 | block = block + 4; 467 | } 468 | 469 | block = (block_data) + block_decryption_offset; 470 | 471 | for (int i = 0; i < data_dencrytion_itration; i++) { 472 | transpose_matrix(block); 473 | block = block + 4; 474 | } 475 | 476 | return data_len; 477 | } 478 | 479 | struct AesEnryptionCtx *init_aes(struct AesEnryptionCtx **encryption_ctx, 480 | guchar *write_key, uint16_t write_key_size, 481 | guchar *write_mac_key, uint16_t mac_key_size, 482 | guchar *write_IV, enum mode mode) { 483 | 484 | struct AesEnryptionCtx *aes_encryption_ctx = 485 | calloc(1, sizeof(struct AesEnryptionCtx)); 486 | aes_encryption_ctx->key_size = write_key_size; 487 | 488 | if (aes_encryption_ctx->key_size == AES_BLOCK_SIZE) { 489 | aes_encryption_ctx->no_rounds = 10; 490 | } else { 491 | printf("key size not equels %d", aes_encryption_ctx->key_size); 492 | return false; 493 | } 494 | 495 | aes_encryption_ctx->mode = mode; 496 | aes_encryption_ctx->initial_key = write_key; 497 | 498 | aes_encryption_ctx->IV = g_memdup(write_IV, 16); 499 | 500 | aes_encryption_ctx->mac_key = write_mac_key; 501 | 502 | aes_encryption_ctx->row_size = 503 | (uint8_t)((float)aes_encryption_ctx->key_size / 4.0); 504 | 505 | aes_encryption_ctx->mac_key_size = mac_key_size; 506 | aes_encryption_ctx->iv_size = AES_BLOCK_SIZE; 507 | aes_encryption_ctx->key_size = write_key_size; 508 | aes_encryption_ctx->recordIV = calloc(1, AES_BLOCK_SIZE); 509 | 510 | aes_expand_key(aes_encryption_ctx); 511 | *encryption_ctx = aes_encryption_ctx; 512 | 513 | return aes_encryption_ctx; 514 | } 515 | -------------------------------------------------------------------------------- /DTLS/Encryptions/encryption.c: -------------------------------------------------------------------------------- 1 | 2 | #include "./encryption.h" 3 | #include "../../DTLS/dtls.h" 4 | #include "../../SRTP/srtp.h" 5 | #include "../../Utils/utils.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | guchar *PRF(BIGNUM *secret, guchar *label, BIGNUM *seed, 16 | GChecksumType checksum_type, uint16_t num_bytes) { 17 | 18 | uint16_t total_itration_required = 19 | ceil((float)num_bytes / g_checksum_type_get_length(checksum_type)); 20 | 21 | uint16_t secret_size = BN_num_bytes(secret); 22 | guchar secret_str[secret_size]; 23 | guchar seed_str[BN_num_bytes(seed)]; 24 | BN_bn2bin(secret, secret_str); 25 | BN_bn2bin(seed, seed_str); 26 | 27 | uint8_t label_len = strlen(label); 28 | gsize label_seed_len = label_len + BN_num_bytes(seed); 29 | 30 | guchar label_seed[label_seed_len]; 31 | memcpy(label_seed, label, label_len); 32 | memcpy(label_seed + label_len, seed_str, label_seed_len); 33 | 34 | gsize checksum_len = g_checksum_type_get_length(checksum_type); 35 | guchar a_concat_seed[checksum_len + label_seed_len]; 36 | gsize a_concat_seed_len = checksum_len + label_seed_len; 37 | memcpy(a_concat_seed + checksum_len, label_seed, label_seed_len); 38 | 39 | guchar *ALL_hmac = malloc(checksum_len * total_itration_required); 40 | for (int i = 1; i <= total_itration_required; i++) { 41 | 42 | guchar *A_seed = a_concat_seed + checksum_len; 43 | uint16_t A_seed_len = label_seed_len; 44 | for (int j = 0; j <= i - 1; j++) { 45 | 46 | GHmac *a_hmac = g_hmac_new(checksum_type, secret_str, secret_size); 47 | g_hmac_update(a_hmac, A_seed, A_seed_len); 48 | g_hmac_get_digest(a_hmac, a_concat_seed, &checksum_len); 49 | 50 | A_seed = a_concat_seed; 51 | A_seed_len = checksum_len; 52 | 53 | g_hmac_unref(a_hmac); 54 | } 55 | 56 | GHmac *hmac = g_hmac_new(G_CHECKSUM_SHA256, secret_str, secret_size); 57 | g_hmac_update(hmac, a_concat_seed, a_concat_seed_len); 58 | g_hmac_get_digest(hmac, ALL_hmac + ((i - 1) * checksum_len), &checksum_len); 59 | g_hmac_unref(hmac); 60 | } 61 | 62 | return ALL_hmac; 63 | } 64 | 65 | struct encryption_keys * 66 | get_srtp_enryption_keys(struct RTCDtlsTransport *transport, guchar *key_block) { 67 | 68 | uint16_t selected_cipher_suite = 69 | transport->srtp_cipher_suite->selected_cipher_suite; 70 | struct encryption_keys *encryption_keys = transport->encryption_keys; 71 | struct cipher_suite_info *cipher_info = transport->srtp_cipher_suite; 72 | encryption_keys->cipher_suite_info = cipher_info; 73 | 74 | g_assert(encryption_keys != NULL && cipher_info != NULL); 75 | 76 | encryption_keys->client_write_key = malloc(cipher_info->key_size); 77 | encryption_keys->server_write_key = malloc(cipher_info->key_size); 78 | 79 | encryption_keys->client_write_SRTP_salt = malloc(cipher_info->salt_key_len); 80 | encryption_keys->server_write_SRTP_salt = malloc(cipher_info->salt_key_len); 81 | 82 | encryption_keys->client_write_IV = malloc(cipher_info->iv_size); 83 | encryption_keys->server_write_IV = malloc(cipher_info->iv_size); 84 | 85 | copy_key_block( 86 | key_block, &encryption_keys->client_write_key, cipher_info->key_size, 87 | &encryption_keys->server_write_key, cipher_info->key_size, 88 | &encryption_keys->client_write_SRTP_salt, cipher_info->salt_key_len, 89 | &encryption_keys->server_write_SRTP_salt, cipher_info->salt_key_len, 90 | NULL); 91 | 92 | printf("------DTLS EXPORTER ------\n"); 93 | printf("Master Srtp Client write key: \n"); 94 | print_hex(encryption_keys->client_write_key, cipher_info->key_size); 95 | 96 | printf("Master Srtp Client write salt key \n"); 97 | print_hex(encryption_keys->client_write_SRTP_salt, cipher_info->salt_key_len); 98 | 99 | return encryption_keys; 100 | } 101 | struct encryption_keys * 102 | get_dtls_encryption_keys(struct RTCDtlsTransport *transport, 103 | guchar *key_block) { 104 | uint16_t selected_cipher_suite = transport->selected_cipher_suite; 105 | struct encryption_keys *encryption_keys = transport->encryption_keys; 106 | struct cipher_suite_info *cipher_info = transport->dtls_cipher_suite; 107 | encryption_keys->cipher_suite_info = cipher_info; 108 | 109 | encryption_keys->client_write_mac_key = malloc(cipher_info->hmac_len); 110 | encryption_keys->server_write_mac_key = malloc(cipher_info->hmac_len); 111 | 112 | encryption_keys->client_write_key = malloc(cipher_info->key_size); 113 | encryption_keys->server_write_key = malloc(cipher_info->key_size); 114 | 115 | encryption_keys->client_write_IV = malloc(cipher_info->iv_size); 116 | encryption_keys->server_write_IV = malloc(cipher_info->iv_size); 117 | 118 | copy_key_block(key_block, &encryption_keys->client_write_mac_key, 119 | cipher_info->hmac_len, &encryption_keys->server_write_mac_key, 120 | cipher_info->hmac_len, &encryption_keys->client_write_key, 121 | cipher_info->key_size, &encryption_keys->server_write_key, 122 | cipher_info->key_size, &encryption_keys->client_write_IV, 123 | cipher_info->iv_size, &encryption_keys->server_write_IV, 124 | cipher_info->iv_size, NULL); 125 | 126 | return encryption_keys; 127 | } 128 | 129 | bool init_dtls(struct dtls_ctx **encryption_ctx, 130 | struct encryption_keys *encryption_keys, 131 | struct cipher_suite_info *cipher_info) { 132 | 133 | struct dtls_ctx *dtls_encrytion_ctx = malloc(sizeof(struct dtls_ctx)); 134 | dtls_encrytion_ctx->client = calloc(1, sizeof(struct DtlsEncryptionCtx)); 135 | dtls_encrytion_ctx->server = calloc(1, sizeof(struct DtlsEncryptionCtx)); 136 | 137 | switch (cipher_info->symitric_algo) { 138 | case AES: 139 | 140 | if (encryption_keys->client_write_key) { 141 | init_aes((struct AesEnryptionCtx **)&dtls_encrytion_ctx->client 142 | ->encryption_ctx, 143 | encryption_keys->client_write_key, cipher_info->key_size, 144 | encryption_keys->client_write_mac_key, cipher_info->hmac_len, 145 | encryption_keys->client_write_IV, cipher_info->mode); 146 | } 147 | 148 | if (encryption_keys->server_write_key) { 149 | init_aes((struct AesEnryptionCtx **)&dtls_encrytion_ctx->server 150 | ->encryption_ctx, 151 | encryption_keys->server_write_key, cipher_info->key_size, 152 | encryption_keys->server_write_mac_key, cipher_info->hmac_len, 153 | encryption_keys->server_write_IV, cipher_info->mode); 154 | } 155 | dtls_encrytion_ctx->encrypt_func = &encrypt_aes; 156 | dtls_encrytion_ctx->decrypt_func = &decrypt_aes; 157 | 158 | *encryption_ctx = dtls_encrytion_ctx; 159 | break; 160 | } 161 | return true; 162 | } 163 | 164 | bool init_symitric_encryption(struct RTCDtlsTransport *transport) { 165 | BIGNUM *master_secret = transport->encryption_keys->master_secret; 166 | 167 | guchar *key_block = 168 | PRF(master_secret, "key expansion", 169 | get_dtls_rand_appended(transport->peer_random, transport->my_random), 170 | G_CHECKSUM_SHA256, 128); 171 | 172 | struct encryption_keys *encryption_keys = 173 | get_dtls_encryption_keys(transport, key_block); 174 | free(key_block); 175 | 176 | init_dtls(&transport->dtls_ctx, encryption_keys, 177 | transport->dtls_cipher_suite); 178 | 179 | // check if srtp is required SRTP 180 | 181 | key_block = 182 | PRF(master_secret, "EXTRACTOR-dtls_srtp", 183 | get_dtls_rand_appended(transport->my_random, transport->peer_random), 184 | G_CHECKSUM_SHA256, 128); 185 | 186 | encryption_keys = get_srtp_enryption_keys(transport, key_block); 187 | init_srtp(&transport->srtp_ctx, encryption_keys); 188 | 189 | free(key_block); 190 | 191 | return true; 192 | } 193 | bool set_cipher_suite_info(struct cipher_suite_info **pp_cipher_suite_info, 194 | uint16_t selected_cipher_suite) { 195 | struct cipher_suite_info *cipher_info = 196 | calloc(1, sizeof(struct cipher_suite_info)); 197 | 198 | cipher_info->selected_cipher_suite = selected_cipher_suite; 199 | 200 | switch (cipher_info->selected_cipher_suite) { 201 | case TLS_RSA_WITH_AES_128_CBC_SHA: 202 | cipher_info->hmac_algo = G_CHECKSUM_SHA1; 203 | cipher_info->hmac_len = g_checksum_type_get_length(cipher_info->hmac_algo); 204 | cipher_info->hmac_key_len = 20; 205 | cipher_info->key_size = 16; 206 | cipher_info->iv_size = 16; 207 | cipher_info->symitric_algo = AES; 208 | cipher_info->mode = CBC; 209 | *pp_cipher_suite_info = cipher_info; 210 | 211 | break; 212 | case SRTP_AES128_CM_HMAC_SHA1_80: 213 | cipher_info->hmac_algo = G_CHECKSUM_SHA1; 214 | cipher_info->hmac_len = 10; 215 | cipher_info->hmac_key_len = 20; 216 | cipher_info->key_size = 16; 217 | cipher_info->salt_key_len = 14; 218 | cipher_info->iv_size = 16; 219 | cipher_info->symitric_algo = AES; 220 | cipher_info->mode = CM; 221 | 222 | *pp_cipher_suite_info = cipher_info; 223 | 224 | break; 225 | default: 226 | printf("cipher sute not supported %x \n", selected_cipher_suite); 227 | exit(0); 228 | } 229 | return true; 230 | } 231 | -------------------------------------------------------------------------------- /DTLS/Encryptions/encryption.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #pragma once 11 | #ifndef _ENRYPTIONH_ 12 | #define _ENRYPTIONH_ 13 | 14 | // 128 10 15 | // 256 12 16 | // 256 14 17 | 18 | enum cipher_suite; 19 | struct RTCDtlsTransport; 20 | struct encryption_keys; 21 | struct cipher_suite_info; 22 | 23 | enum cipher_suite { 24 | TLS_RSA_WITH_AES_128_CBC_SHA = 0x2f00, 25 | SRTP_AES128_CM_HMAC_SHA1_80 = 0x0100 26 | }; 27 | 28 | enum mode { CBC, CM }; 29 | enum symitric_encrypt_algo { AES }; 30 | 31 | struct AesEnryptionCtx { 32 | uint8_t *initial_key; 33 | uint8_t *mac_key; 34 | uint16_t mac_key_size; 35 | uint16_t iv_size; 36 | uint16_t key_size; 37 | uint8_t row_size; 38 | enum mode mode; 39 | 40 | uint8_t no_rounds; 41 | 42 | uint8_t input_text[4][4]; 43 | uint8_t (*recordIV)[4]; 44 | uint8_t (*IV)[4]; 45 | uint8_t *prevoius_cipher; 46 | uint8_t (*roundkeys[14])[4]; 47 | }; 48 | 49 | struct dtls_ctx { 50 | struct DtlsEncryptionCtx *client; 51 | struct DtlsEncryptionCtx *server; 52 | uint32_t (*encrypt_func)(void *encryption_ctx, uint8_t *block_data, 53 | uint16_t block_encrypt_offset, 54 | uint32_t total_packet_len); 55 | uint32_t (*decrypt_func)(void *encryption_ctx, uint8_t *block_data, 56 | uint16_t block_encrypt_offset, 57 | uint32_t total_packet_len); 58 | }; 59 | 60 | struct srtp_ctx { 61 | struct SrtpEncryptionCtx *client; 62 | struct SrtpEncryptionCtx *server; 63 | uint32_t (*encrypt_func)(void *encryption_ctx, uint8_t *block_data, 64 | uint16_t block_encrypt_offset, 65 | uint32_t total_packet_len); 66 | uint32_t (*decrypt_func)(void *encryption_ctx, uint8_t *block_data, 67 | uint16_t block_encrypt_offset, 68 | uint32_t total_packet_len); 69 | }; 70 | 71 | struct cipher_suite_info { 72 | uint16_t selected_cipher_suite; 73 | enum symitric_encrypt_algo symitric_algo; 74 | enum mode mode; 75 | GChecksumType hmac_algo; 76 | gsize hmac_key_len; 77 | gsize hmac_len; 78 | gsize key_size; 79 | gsize iv_size; 80 | gsize salt_key_len; 81 | gsize tag_size; 82 | }; 83 | 84 | struct encryption_keys { 85 | BIGNUM *master_secret; 86 | guchar *my_private_key; 87 | guchar *client_write_mac_key; 88 | guchar *server_write_mac_key; 89 | guchar *client_write_key; 90 | guchar *server_write_key; 91 | guchar *client_write_IV; 92 | guchar *server_write_IV; 93 | guchar *client_write_SRTP_salt; 94 | guchar *server_write_SRTP_salt; 95 | struct cipher_suite_info *cipher_suite_info; 96 | }; 97 | 98 | #define MASTER_SECRET_LEN 48.0 99 | 100 | uint16_t encrypt_rsa(guchar **encrypted_data, EVP_PKEY *pub_key, guchar *data, 101 | uint16_t data_len, GChecksumType hash); 102 | 103 | BIGNUM *calcualte_master_secret(BIGNUM *premaster_secret); 104 | 105 | BIGNUM *get_dtls_rand_appended(BIGNUM *r1, BIGNUM *r2); 106 | 107 | guchar *PRF(BIGNUM *secret, guchar *label, BIGNUM *seed, 108 | GChecksumType checksum_type, uint16_t num_bytes); 109 | 110 | BIGNUM *generate_master_key(guchar *premaster_key, BIGNUM *seed); 111 | gchar *generate_encryption_key_block(BIGNUM *master_secret, BIGNUM *seed, 112 | guint16 selected_cipher_suite); 113 | bool parse_encryption_key_block(struct RTCDtlsTransport *transport, 114 | gchar *key_block); 115 | 116 | bool init_symitric_encryption(struct RTCDtlsTransport *transport); 117 | 118 | struct AesEnryptionCtx *init_aes(struct AesEnryptionCtx **encryption_ctx, 119 | guchar *write_key, uint16_t write_key_size, 120 | guchar *write_mac_key, uint16_t mac_key_size, 121 | guchar *write_IV, enum mode mode); 122 | bool aes_expand_key(struct AesEnryptionCtx *ctx); 123 | 124 | void sub_bytes(uint8_t (*block)[4]); 125 | 126 | void shift_rows(uint8_t (*block)[4]); 127 | 128 | void mix_columns(uint8_t (*matrix)[4], uint8_t (*galois_fild)[4]); 129 | 130 | uint32_t encrypt_aes(struct AesEnryptionCtx *ctx, uint8_t *block_data, 131 | uint16_t block_encrypt_offset, uint32_t data_len); 132 | 133 | uint32_t decrypt_aes(struct AesEnryptionCtx *ctx, uint8_t *block_data, 134 | uint16_t block_decryption_offset, uint32_t data_len); 135 | 136 | void transpose_matrix(uint8_t (*round_key)[4]); 137 | 138 | bool init_dtls_ctx(struct dtls_ctx *dtls_ctx, 139 | struct encryption_keys *encryption_keys, 140 | struct cipher_suite_info *cipher_info); 141 | 142 | bool set_cipher_suite_info(struct cipher_suite_info **pp_cipher_suite_info, 143 | uint16_t selected_cipher_suite); 144 | uint32_t decrypt_dtls(struct RTCDtlsTransport *dtls_transport, guchar **block, 145 | uint32_t length); 146 | uint32_t encrypt_dtls(struct RTCDtlsTransport *dtls_transport, guchar *block, 147 | uint32_t length); 148 | #endif // !_ENRYPTIONH_ 149 | -------------------------------------------------------------------------------- /DTLS/Encryptions/rsa.c: -------------------------------------------------------------------------------- 1 | #include "../../Utils/utils.h" 2 | #include "../dtls.h" 3 | #include "./encryption.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | uint8_t sha256_representation[] = {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 24 | 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 25 | 0x01, 0x05, 0x00, 0x04, 0x20}; 26 | 27 | uint8_t get_hash_representation(uint8_t **hash_representation, 28 | int16_t checksum_type) { 29 | switch (checksum_type) { 30 | case G_CHECKSUM_SHA256: 31 | *hash_representation = sha256_representation; 32 | return 19; 33 | default: 34 | return NULL; 35 | } 36 | } 37 | guchar *get_padded_message(guchar *message, uint16_t message_len, 38 | uint32_t key_size, int16_t hash_name) { 39 | 40 | guchar *padded_message = malloc(key_size); 41 | gchar *random_padding; 42 | uint16_t pad; 43 | uint16_t padding_len; 44 | printf("key %d", key_size); 45 | 46 | if (hash_name == -1) { 47 | padding_len = key_size - message_len - 3; 48 | pad = htons(0x0002); 49 | get_random_string(&random_padding, padding_len, RANDOM_CHAR_STRING); 50 | } else { 51 | 52 | uint8_t *hash_representation; 53 | uint8_t hash_representation_len = 54 | get_hash_representation(&hash_representation, hash_name); 55 | padding_len = key_size - hash_representation_len - message_len - 3; 56 | random_padding = malloc(padding_len); 57 | for (int i = 0; i < padding_len; i++) { 58 | random_padding[i] = 0xFF; 59 | } 60 | pad = htons(0x0001); 61 | guchar *hashrep_message_concat = 62 | malloc(message_len + hash_representation_len); 63 | memcpy(hashrep_message_concat, hash_representation, 64 | hash_representation_len); 65 | memcpy(hashrep_message_concat + hash_representation_len, message, 66 | message_len); 67 | 68 | message = hashrep_message_concat; 69 | message_len = message_len + hash_representation_len; 70 | } 71 | 72 | guchar *ptr = padded_message; 73 | 74 | memcpy(ptr, &pad, sizeof(uint16_t)); 75 | ptr += sizeof(uint16_t); 76 | 77 | memcpy(ptr, random_padding, padding_len); 78 | 79 | ptr += padding_len; 80 | 81 | memcpy(ptr, &pad, sizeof(uint8_t)); 82 | 83 | ptr += sizeof(uint8_t); 84 | 85 | memcpy(ptr, message, message_len); 86 | 87 | ptr += message_len; 88 | 89 | printf("%s", padded_message); 90 | free(random_padding); 91 | 92 | return padded_message; 93 | } 94 | 95 | uint16_t encrypt_rsa(guchar **p_enrypted_data, EVP_PKEY *pub_key, guchar *data, 96 | uint16_t data_len, GChecksumType hash) { 97 | // for signing pass private key for encrypting pass public key 98 | if (!pub_key) { 99 | printf(" key null \n"); 100 | exit(0); 101 | } 102 | 103 | RSA *rsa = EVP_PKEY_get1_RSA(pub_key); 104 | if (!rsa) { 105 | printf("cannot get public key from rsa certificate \n"); 106 | exit(0); 107 | } 108 | 109 | const BIGNUM *xponent; 110 | const BIGNUM *modulus; 111 | guchar *paddedmsg; 112 | 113 | uint32_t key_size = RSA_size(rsa); 114 | 115 | if (RSA_get0_d(rsa)) { 116 | xponent = RSA_get0_d(rsa); 117 | printf("using private key for signing \n"); 118 | paddedmsg = get_padded_message(data, data_len, key_size, hash); 119 | } else if (RSA_get0_e(rsa)) { 120 | xponent = RSA_get0_e(rsa); 121 | printf("using public key for encryption \n"); 122 | paddedmsg = get_padded_message(data, data_len, key_size, -1); 123 | } 124 | modulus = RSA_get0_n(rsa); 125 | 126 | printf("\nexponent %s\n\n", BN_bn2hex(xponent)); 127 | printf("modulus %s\n", BN_bn2hex(modulus)); 128 | printf("key_size %d\n", key_size); 129 | 130 | BIGNUM *paddedmsg_bn = BN_new(); 131 | BN_bin2bn(paddedmsg, key_size, paddedmsg_bn); 132 | 133 | BN_CTX *ctx = BN_CTX_new(); 134 | BIGNUM *encrypted_premaster_secret = BN_new(); 135 | BN_mod_exp(encrypted_premaster_secret, paddedmsg_bn, xponent, modulus, ctx); 136 | 137 | uint16_t encrypted_premaster_secret_bin_len = 138 | BN_num_bytes(encrypted_premaster_secret); 139 | 140 | guchar *encrypted_premaster_secret_bin = 141 | malloc(encrypted_premaster_secret_bin_len); 142 | 143 | printf("unencrypted padded data %s\n\n", BN_bn2hex(paddedmsg_bn)); 144 | print_hex(paddedmsg, BN_num_bytes(paddedmsg_bn)); 145 | printf("encrypted data %s\n", BN_bn2hex(encrypted_premaster_secret)); 146 | BN_bn2bin(encrypted_premaster_secret, encrypted_premaster_secret_bin); 147 | 148 | print_hex(encrypted_premaster_secret_bin, encrypted_premaster_secret_bin_len); 149 | 150 | *p_enrypted_data = encrypted_premaster_secret_bin; 151 | 152 | return encrypted_premaster_secret_bin_len; 153 | } 154 | 155 | BIGNUM *generate_master_key(guchar *premaster_secret, BIGNUM *seed) { 156 | BIGNUM *unpadded_premaster_secret_bn = BN_new(); 157 | BN_bin2bn(premaster_secret, 48, unpadded_premaster_secret_bn); 158 | 159 | printf("unpadded premaster key %s\n", 160 | BN_bn2hex(unpadded_premaster_secret_bn)); 161 | 162 | gchar *master_secret = PRF(unpadded_premaster_secret_bn, "master secret", 163 | seed, G_CHECKSUM_SHA256, MASTER_SECRET_LEN); 164 | 165 | BIGNUM *master_secret_bn = BN_new(); 166 | BN_bin2bn(master_secret, 48, master_secret_bn); 167 | free(master_secret); 168 | return master_secret_bn; 169 | } 170 | 171 | BIGNUM *get_dtls_rand_appended(BIGNUM *r1, BIGNUM *r2) { 172 | gchar *appended = g_strdup_printf("%s%s", BN_bn2hex(r1), BN_bn2hex(r2)); 173 | BIGNUM *r = BN_new(); 174 | 175 | BN_hex2bn(&r, appended); 176 | 177 | g_debug("apppended random %s\n", BN_bn2hex(r)); 178 | return r; 179 | } 180 | -------------------------------------------------------------------------------- /DTLS/dtls.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef _DTLSH_ 4 | #define _DTLSH_ 5 | 6 | #include "../WebRTC/webrtc.h" 7 | #include "Encryptions/encryption.h" 8 | #include "json-glib/json-glib.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define DTLS_1_2 0xfefd 18 | #define DTLS_1_0 0xfeff 19 | 20 | #define CIPHER_SUITE_LEN 1 21 | // #define TLS_RSA_WITH_AES_128_CBC_SHA 0x2f00 // big endian 22 | 23 | enum dtls_extentions { 24 | SRTP_EXT = 0x000e, 25 | SIGN_ALGO_EXT = 0x000d, 26 | SESS_TICKET_EXT = 0x0023, 27 | EXTEND_MASTER_SEC_EXT = 0x0017 28 | }; 29 | 30 | enum key_exchange { RSA_KEY_EXCHANGE }; 31 | enum cipher { AES_128_CBC = 128 }; 32 | 33 | struct NetworkPacket; 34 | struct RTCPeerConnection; 35 | 36 | enum DtlsState { 37 | DTLS_CONNECTION_STATE_NEW, 38 | DTLS_CONNECTION_STATE_CONNECTING, 39 | DTLS_CONNETION_STATE_CONNECTED, 40 | DTLS_CONNECTION_STATE_FAILED, 41 | DTLS_CONNECTION_STATE_CLOSED 42 | }; 43 | enum DTLS_MODE { 44 | DTLS_ACTIVE, // only client is supported 45 | DTLS_ACTPASS 46 | }; 47 | enum HandshakeType { 48 | handshake_type_hello_request = 0, 49 | handshake_type_client_hello, 50 | handshake_type_server_hello, 51 | handshake_type_hello_verify_request, // New field 52 | handshake_type_certificate = 11, 53 | handshake_type_server_key_exchange, 54 | handshake_type_certificate_request, 55 | handshake_type_server_hello_done, 56 | handshake_type_certificate_verify, 57 | handshake_type_client_key_exchange, 58 | handshake_type_finished = 20, 59 | handshake_type_change_cipher_spec = 233, 60 | }; 61 | enum ContentType { 62 | content_type_change_cipher_spec = 20, 63 | content_type_alert, 64 | content_type_handshake, 65 | content_type_application_data 66 | }; 67 | struct Negosiated {}; 68 | 69 | struct RTCDtlsTransport { 70 | enum DTLS_MODE mode; 71 | enum DtlsState state; 72 | struct CandidataPair *pair; 73 | struct DtlsParsedPacket *last_dtl_packet; 74 | JsonObject *dtls_flights; 75 | char *fingerprint; 76 | uint16_t current_seq_no; 77 | uint16_t current_flight_no; 78 | uint16_t epoch; 79 | int cookie; 80 | int cookie_len; 81 | BIGNUM *my_random; 82 | BIGNUM *peer_random; 83 | uint16_t selected_cipher_suite; 84 | uint16_t selected_signatuire_hash_algo; 85 | X509 *server_certificate; 86 | X509 *client_certificate; 87 | struct ALLDtlsMessages *all_previous_handshake_msgs; 88 | EVP_PKEY *pub_key; 89 | EVP_PKEY *my_private_key; 90 | EVP_PKEY *my_public_key; 91 | 92 | struct encryption_keys *encryption_keys; 93 | 94 | struct cipher_suite_info *dtls_cipher_suite; 95 | struct cipher_suite_info *srtp_cipher_suite; 96 | 97 | struct dtls_ctx *dtls_ctx; 98 | struct srtp_ctx *srtp_ctx; 99 | }; 100 | 101 | struct DtlsEncryptionCtx { 102 | void *encryption_ctx; 103 | }; 104 | struct __attribute__((packed)) DtlsHeader { 105 | uint8_t type; 106 | uint16_t version; 107 | uint16_t epoch; 108 | uint64_t sequence_number : 48; 109 | uint16_t length; 110 | }; 111 | 112 | struct __attribute__((packed)) HandshakeHeader { 113 | uint8_t type : 8; 114 | uint32_t length : 24; 115 | uint16_t message_seq; 116 | uint32_t fragment_offset : 24; 117 | uint32_t fragment_length : 24; 118 | }; 119 | 120 | struct __attribute__((packed)) DtlsClientHello { 121 | uint16_t client_version; 122 | gchar random[32]; 123 | uint8_t session_id; 124 | uint8_t cookie_len; 125 | uint16_t cipher_suite_len; 126 | uint16_t cipher_suite[CIPHER_SUITE_LEN]; 127 | uint8_t compression_method_len; 128 | uint8_t compression_method; 129 | uint16_t extention_len; 130 | uint16_t extentions[]; 131 | }; 132 | struct __attribute__((packed)) DtlsServerHello { 133 | uint16_t client_version; 134 | guchar random[32]; 135 | uint8_t session_id_len; 136 | gchar *session_id; 137 | uint16_t cipher_suite; 138 | uint8_t compression_method; 139 | uint16_t extention_len; 140 | uint16_t *extentions; 141 | }; 142 | struct __attribute__((packed)) Certificate { 143 | uint32_t certificate_len : 24; 144 | guchar certificate[]; 145 | }; 146 | 147 | struct __attribute__((packed)) CertificateRequest { 148 | uint8_t certificate_types_count; 149 | uint8_t *certificate_types; 150 | uint16_t signature_hash_algo_len; 151 | uint16_t *signature_hash_algo; 152 | uint16_t distiguished_name_len; 153 | }; 154 | 155 | struct __attribute__((packed)) CertificateVerify { 156 | uint16_t signature_algorithms; 157 | uint16_t signature_len; 158 | guchar signature[]; 159 | }; 160 | 161 | struct __attribute__((packed)) HelloVerifyRequest { 162 | uint16_t server_version; 163 | uint16_t cookie_len; 164 | }; 165 | 166 | struct __attribute__((packed)) dtls_ext { 167 | uint16_t type; 168 | uint16_t ext_length; 169 | guchar value[]; 170 | }; 171 | 172 | union ParsedHandshakePayload { 173 | struct DtlsServerHello *hello; 174 | struct Certificate *certificate; 175 | }; 176 | 177 | struct DtlsParsedPacket { 178 | bool isfragmented; 179 | bool islastfragment; 180 | bool isencrypted; 181 | uint8_t handshake_type; 182 | struct DtlsHeader *dtls_header; 183 | struct HandshakeHeader *handshake_header; 184 | guchar *handshake_payload; 185 | guchar *all_fragmented_payload; 186 | union ParsedHandshakePayload parsed_handshake_payload; 187 | guchar *payload; 188 | struct DtlsParsedPacket *next_record; 189 | }; 190 | 191 | struct ServerHelloFlight { 192 | struct DtlsServerHello *server_hello; 193 | struct Certificate *certificate; 194 | struct CertificateRequest *certificate_request; 195 | }; 196 | 197 | struct ClientKeyExchange { 198 | uint16_t key_len; 199 | gchar encrypted_premaster_key[]; 200 | }; 201 | 202 | struct ALLDtlsMessages { 203 | bool isfragmented; 204 | struct ALLDtlsMessages *next_message; 205 | struct HandshakeHeader *handshake_header; 206 | uint32_t payload_len; 207 | guchar *payload; 208 | }; 209 | struct __attribute__((packed)) llTVL { 210 | uint16_t type; 211 | uint16_t len; 212 | guchar *value; 213 | struct llTVL *next_tvl; 214 | }; 215 | 216 | struct RTCDtlsTransport *create_dtls_transport(); 217 | void start_dtls_negosiation(struct RTCPeerConnection *peer); 218 | 219 | void send_dtls_client_hello(struct RTCPeerConnection *peer, bool with_cookie); 220 | bool check_if_dtls(uint8_t); 221 | uint8_t make_dtls_packet(struct RTCDtlsTransport *transport, 222 | struct iovec *dtls_packet, 223 | struct DtlsHeader *dtls_header, 224 | struct HandshakeHeader *handshake, 225 | guchar *dtls_payload, uint32_t payload_len); 226 | bool send_dtls_packet(struct RTCDtlsTransport *dtls_transport, 227 | uint8_t handshake_type, guchar *dtls_payload, 228 | uint32_t dtls_payload_len); 229 | uint16_t add_dtls_extention(struct DtlsClientHello **dtls_packet, 230 | struct dtls_ext *extention, uint16_t extention_len); 231 | 232 | uint16_t make_extentention(struct dtls_ext **ext, uint16_t extention_type, 233 | guchar *data, uint16_t data_len, guchar *extradata, 234 | uint16_t extra_data_len); 235 | void on_dtls_packet(struct NetworkPacket *dtls_packet, 236 | struct RTCPeerConnection *peer); 237 | void handle_server_hello(struct RTCDtlsTransport *transport, 238 | struct DtlsServerHello *hello, struct llTVL *tvl); 239 | void handle_certificate(struct RTCDtlsTransport *transport, 240 | struct Certificate *certificate, gchar *expected_hash, 241 | gchar *fingerprint_type); 242 | void handle_certificate_request(struct RTCDtlsTransport *transport, 243 | struct CertificateRequest *certificate_request); 244 | 245 | struct DtlsServerHello *parse_server_hello(guchar *handshake_payload, 246 | uint32_t length, struct llTVL **tvl); 247 | 248 | uint32_t get_client_certificate(guchar **certificate, 249 | struct CertificateRequest *certificate_request); 250 | 251 | bool do_client_key_exchange(struct RTCDtlsTransport *transport); 252 | bool do_change_cipher_spec(struct RTCDtlsTransport *transport); 253 | bool do_client_finished(struct RTCDtlsTransport *transport); 254 | bool send_certificate(struct RTCDtlsTransport *transport); 255 | bool do_certificate_verify(struct RTCDtlsTransport *transport); 256 | void store_concated_handshake_msgs(struct RTCDtlsTransport *transport, 257 | struct HandshakeHeader *handshake_header, 258 | guchar *payload, uint32_t payload_len, 259 | bool isfragmented); 260 | #endif 261 | -------------------------------------------------------------------------------- /Documentation/RTP_PACKET.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/USAMAWIZARD/webrtc-from-scratch/c427f0ec643f6504d5bdbdb02924de68b3bd404d/Documentation/RTP_PACKET.png -------------------------------------------------------------------------------- /Documentation/aes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/USAMAWIZARD/webrtc-from-scratch/c427f0ec643f6504d5bdbdb02924de68b3bd404d/Documentation/aes -------------------------------------------------------------------------------- /Documentation/h264: -------------------------------------------------------------------------------- 1 | H264 Docs 2 | Credits 3 | https://web.archive.org/web/20141016205250/http://www.szatmary.org:80/blog/25 4 | 5 | h264 file is divided into nal units 6 | A Video frame can be sliced into several NALU 7 | one or more NALU grouped togethehr called AU that contains a single frame 8 | 9 | nal units are of diffrent catagories vcl non vcl 10 | 11 | vcl - contians frame data 12 | non vlc - contains meta data that may be used for setting decoders 13 | bins stored right left 14 | there 18 diffrent type of nal unitys 15 | first byte of each NALU contains its type specifcally bits 3 through 7. (bit 0 is always off, and bits 1-2 indicate weather is NALU is referenced by another NALU) 16 | Each NALU start with 0 17 | 18 | important NALU types 19 | **sps** non-vcl configure decoder profile level res / fps (imporant for decoders) 20 | **pps** non-vcl motioin predection and filter (importatant for decoders) 21 | **IDR** VCL contains key frame 22 | 23 | 24 | 100 100 100 100 100 100 AU 25 | first byte after start code 26 | +---------------+ 27 | |0|1|2|3|4|5|6|7| 28 | +-+-+-+-+-+-+-+-+ 29 | |F|NRI| Type | 30 | +---------------+ 31 | 32 | 0 Unspecified non-VCL 33 | 1 Coded slice of a non-IDR picture VCL 34 | 2 Coded slice data partition A VCL 35 | 3 Coded slice data partition B VCL 36 | 4 Coded slice data partition C VCL 37 | 5 Coded slice of an IDR picture VCL 38 | 6 Supplemental enhancement information (SEI) non-VCL 39 | 7 Sequence parameter set non-VCL 40 | 8 Picture parameter set non-VCL 41 | 9 Access unit delimiter non-VCL 42 | 10 End of sequence non-VCL 43 | 11 End of stream non-VCL 44 | 12 Filler data non-VCL 45 | 13 Sequence parameter set extension non-VCL 46 | 14 Prefix NAL unit non-VCL 47 | 15 Subset sequence parameter set non-VCL 48 | 16..18 Reserved non-VCL 49 | 19 Coded slice of an auxiliary coded picture without partitioning non-VCL 50 | 20 Coded slice extension non-VCL 51 | 21 Coded slice extension for depth view components non-VCL 52 | 22..23 Reserved non-VCL 53 | 24..31 Unspecified non-VCL 54 | 55 | NALU does not contains its size 56 | therefore concatinating NALUs will not work 57 | How to know where each one starts and ends 58 | 59 | Therefore 60 | we use Statcode before each NALU 61 | Start Code :- 2 or 3 byte 0x00 followed by 0x01 byte 00 00 00 01 OR 00 00 01 62 | 4 byte version is used for SPS PPS AUD and IDR 63 | 0x000000, 0x000001 and 0x000002 are illegal within a NALU 64 | encoder escape these values that could otherwise be confused with a start code 65 | Each NALU start with 0 (BIT) 66 | Emulation Prevention’ byte 0x03, so that 0x000001 becomes 0x00000301 67 | 68 | Common H264 NALU Formating 69 | Annex B (used in live streaming) 70 | SPS and PPS periodically repeted 71 | usually proceeding every IDR 72 | This enables the ability to join a stream already in progress 73 | 74 | AVCC (used in local storing ) 75 | each nalu is stored preceeding witth its leangth 76 | Easy to store & parse 77 | -------------------------------------------------------------------------------- /Documentation/ice: -------------------------------------------------------------------------------- 1 | https://datatracker.ietf.org/doc/html/rfc8445#page-5 2 | 3 | 4 | +---------+ 5 | +--------+ |Signaling| +--------+ 6 | | STUN | |Server | | STUN | 7 | | Server | +---------+ | Server | 8 | +--------+ / \ +--------+ 9 | / \ 10 | / \ 11 | / <- Signaling -> \ 12 | / \ 13 | +--------+ +--------+ 14 | | NAT | | NAT | 15 | +--------+ +--------+ 16 | / \ 17 | / \ 18 | +-------+ +-------+ 19 | | Agent | | Agent | 20 | | L | | R | 21 | +-------+ +-------+ 22 | 23 | Figure 1: ICE Deployment Scenario 24 | 25 | 26 | 27 | 28 | Keranen, et al. Standards Track [Page 7] 29 | 30 | RFC 8445 ICE July 2018 31 | 32 | 33 | The basic idea behind ICE is as follows: each agent has a variety of 34 | candidate transport addresses (combination of IP address and port for 35 | a particular transport protocol, which is always UDP in this 36 | specification) it could use to communicate with the other agent. 37 | These might include: 38 | 39 | o A transport address on a directly attached network interface 40 | 41 | o A translated transport address on the public side of a NAT (a 42 | "server-reflexive" address) 43 | 44 | o A transport address allocated from a TURN server (a "relayed 45 | address") 46 | 47 | Potentially, any of L's candidate transport addresses can be used to 48 | communicate with any of R's candidate transport addresses. In 49 | practice, however, many combinations will not work. For instance, if 50 | L and R are both behind NATs, their directly attached interface 51 | addresses are unlikely to be able to communicate directly (this is 52 | why ICE is needed, after all!). The purpose of ICE is to discover 53 | which pairs of addresses will work. The way that ICE does this is to 54 | systematically try all possible pairs (in a carefully sorted order) 55 | until it finds one or more that work. address") 56 | 57 | 58 | With both agents performing a check on a candidate pair, the result 59 | is a 4-way handshake: 60 | 61 | L R 62 | - - 63 | STUN request -> \ L's 64 | <- STUN response / check 65 | 66 | <- STUN request \ R's 67 | STUN response -> / check 68 | 69 | Figure 3: Basic Connectivity Check 70 | With both agents performing a check on a candidate pair, the result 71 | is a 4-way handshake: 72 | 73 | L R 74 | - - 75 | STUN request -> \ L's 76 | <- STUN response / check 77 | 78 | <- STUN request \ R's 79 | STUN response -> / check 80 | 81 | Figure 3: Basic Connectivity Check 82 | 83 | 84 | STUN RTP RTCP SAME PORT 85 | he initiating agent that started the ICE 86 | processing MUST take the controlling role, and the other MUST take 87 | the controlled role. Both agents will form checklists, run the 88 | ICE state machines, and generate connectivity checks. The 89 | controlling agent will execute the logic in Section 8.1 to 90 | nominate pairs that will become (if the connectivity checks 91 | associated with the nominations succeed) the selected pairs, and 92 | then both agents end ICE as described in Section 8.1.2. 93 | 94 | 95 | 96 | 97 | 98 | tickel ICE 99 | 100 | 101 | an endpoint using ICE needs to gather candidates, prioritize them, choose default ones, exchange them with the remote party, pair them and order into check lists. Once all this have been completed, and only then, the endpoints can begin a phase of connectivity checks and eventually select the pair of address candidates that will be used in the session 102 | 103 | 104 | 105 | hypotisis to confirm 106 | if one client is behind nat and another directly have a public ip then when 107 | 108 | 109 | natted client -------binding req------>stun server 110 | natted client <-------binding res-----stun server 111 | 112 | 113 | natted client ---------stun req-------->public client 114 | natted client <---------stun res--------public client 115 | 116 | we discover a new candidate here which is not known to us yet its a peer peer reflexive candidate 117 | 118 | 119 | IF MAX BUNDLE THEN one the ice candidate with mid 0 will be descovered 120 | 121 | 122 | balanced Gather ICE candidates for each media type in use (audio, video, and data). If the remote endpoint is not bundle-aware, negotiate only one audio and video track on separate transports. 123 | max-compat Gather ICE candidates for each track. If the remote endpoint is not bundle-aware, negotiate all media tracks on separate transports. 124 | max-bundle Gather ICE candidates for only one track. If the remote endpoint is not bundle-aware, negotiate only one media track. 125 | -------------------------------------------------------------------------------- /Documentation/rsa: -------------------------------------------------------------------------------- 1 | credits https://www.youtube.com/watch?v=oOcTVTpUsPQ&t=64s 2 | 3 | Encryption 4 | 5 | RSA public key (5,14) 6 | Private Key (11,14) 7 | 8 | Text B=2 9 | 10 | 2^5 % 14 = 4(D) Encrpyted 11 | 12 | 13 | 4(D) 14 | Alice ----------------------> BOB 15 | 16 | 17 | 18 | 4^11 % 14 = ( 4194304 % 14 ) = 2 (B) 19 | 20 | 21 | Deciding public and priveate keys 22 | 23 | 24 | 1: Pick two very large prime number 25 | p=2 q=7 26 | 27 | 2: product of those 28 | 29 | product = 2*7 = 14 (becames modulus) 30 | 31 | 3: Calculate a phi function 32 | 33 | modulus =14 (public key modulus) 34 | 35 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 36 | 37 | cross out the number which shares a common factor with 14 38 | 39 | 40 | co-prime with 14 41 | 1 3 5 9 11 13 42 | 43 | total numbers co pime = 6 44 | 45 | short cut formula for this calculation for total co prime 46 | 47 | phi(N) = (p-1) x (q-1) = 6 48 | 49 | 50 | 4: Choseing E Rule (public key Encryption) = { 1 < e < phi(N) && doens not have common factor with N && phi(N) } 51 | 52 | new list 53 | 5 54 | 55 | E=5 (public key number) 56 | 57 | 58 | 5: Choese Private key (private x e ) % phi(N) = 1 59 | (private x 5 ) % 6 = 1 60 | 61 | -------------------------------------------------------------------------------- /Documentation/rtp: -------------------------------------------------------------------------------- 1 | https://datatracker.ietf.org/doc/html/rfc6184 2 | 3 | RTP PAYLOAD SPECS FOR H264 4 | first byte of a nal unit contials f NRI and type 5 | its treated as a payload header 6 | and then nal unit starts 7 | 8 | first byte of each NALU contains its type specifcally bits 3 through 7. (bit 0 is always off, and bits 1-2 indicate weather is NALU is referenced by another NALU) 9 | 10 | 11 | RTP PAYLOAD paketizastion mode in RTP H264 12 | 13 | The payload format defines three different basic payload structures. 14 | A receiver can identify the payload structure by the first byte of 15 | the RTP packet payload, which co-serves as the RTP payload header 16 | and, in some cases, as the first byte of the payload. This byte is 17 | always structured as a NAL unit header. The NAL unit type field 18 | indicates which structure is present. The possible structures are as 19 | follows. 20 | 21 | Single NAL Unit Packet: Contains only a single NAL unit in the 22 | payload. The NAL header type field is equal to the original NAL unit 23 | type, i.e., in the range of 1 to 23, inclusive. Specified in Section 24 | 5.6. 25 | 26 | Aggregation Packet: Packet type used to aggregate multiple NAL units 27 | into a single RTP payload. This packet exists in four versions, the 28 | Single-Time Aggregation Packet type A (STAP-A), the Single-Time 29 | Aggregation Packet type B (STAP-B), Multi-Time Aggregation Packet 30 | (MTAP) with 16-bit offset (MTAP16), and Multi-Time Aggregation Packet 31 | (MTAP) with 24-bit offset (MTAP24). The NAL unit type numbers 32 | assigned for STAP-A, STAP-B, MTAP16, and MTAP24 are 24, 25, 26, and 33 | 27, respectively. Specified in Section 5.7. 34 | 35 | Fragmentation Unit: Used to fragment a single NAL unit over multiple 36 | RTP packets. Exists with two versions, FU-A and FU-B, identified 37 | with the NAL unit type numbers 28 and 29, respectively. Specified in 38 | Section 5.8. 39 | 40 | Table 1. Summary of NAL unit types and the corresponding packet 41 | types 42 | 43 | NAL Unit Packet Packet Type Name Section 44 | Type Type 45 | ------------------------------------------------------------- 46 | 0 reserved - 47 | 1-23 NAL unit Single NAL unit packet 5.6 48 | 24 STAP-A Single-time aggregation packet 5.7.1 49 | 25 STAP-B Single-time aggregation packet 5.7.1 50 | 26 MTAP16 Multi-time aggregation packet 5.7.2 51 | 27 MTAP24 Multi-time aggregation packet 5.7.2 52 | 28 FU-A Fragmentation unit 5.8 53 | 29 FU-B Fragmentation unit 5.8 54 | 30-31 reserved - 55 | -------------------------------------------------------------------------------- /Documentation/sdp: -------------------------------------------------------------------------------- 1 | every line in sdp is a keyvalue pair 2 | https://datatracker.ietf.org/doc/html/rfc8866 3 | 4 | 5 | 6 | key=value 7 | key=value 8 | ........ 9 | .... 10 | a single letter is used as key 11 | all the valid keys are defined in rfc8866 12 | can contain 0 or more media description 13 | 14 | Not all key values defined by the Session Description Protocol are used by WebRTC. Only keys used in the JavaScript Session Establishment Protocol (JSEP), defined in RFC 8829, are important. 15 | 16 | 17 | v - Version, should be equal to 0. 18 | o - Origin, contains a unique ID useful for renegotiations. 19 | s - Session Name, should be equal to -. 20 | t - Timing, should be equal to 0 0. 21 | m - Media Description (m= ...), described in detail below. 22 | a - Attribute, a free text field. This is the most common line in WebRTC. 23 | c - Connection Data, should be equal to IN IP4 0.0.0.0. 24 | 25 | 26 | transriver have a sender and revier and its defined in sdp as 27 | a=mid:0 28 | 29 | 30 | -------------------------------------------------------------------------------- /Documentation/stun: -------------------------------------------------------------------------------- 1 | The most significant 2 bits of every STUN message MUST be zeroes. 2 | This can be used to differentiate STUN packets from other protocols 3 | when STUN is multiplexed with other protocols on the same port. 4 | 5 | a STUN server on the public Internet supporting ICE would 6 | have no authentication, whereas the STUN server functionality in an 7 | agent supporting connectivity checks would utilize short-term 8 | credentials. An overview of these two mechanisms is given in 9 | -------------------------------------------------------------------------------- /Documentation/webrtc: -------------------------------------------------------------------------------- 1 | w xebrtc is nothing but collection of these protocols working togheter hand in hand. 2 | 3 | rtp 4 | 5 | ice 6 | 7 | dtls 8 | 9 | rtcp 10 | 11 | stun 12 | 13 | turn 14 | 15 | send the sdp to each other with the informationj 16 | i will do stun to find out the public ip and port that i am connecting to 17 | with Ice i will try to punch a hole in the NAT 18 | once ice is finished i will have a port to communicate with 19 | i will start by negosiation of dtls over the opened communication channel 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /GstreamerClient/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS= 3 | LIBS= 4 | PKG_CONFIG=`pkg-config --cflags --libs libsoup-2.4 gstreamer-1.0 json-glib-1.0 gstreamer-webrtc-1.0 gstreamer-sdp-1.0 ` 5 | 6 | 7 | all:webrtc 8 | 9 | 10 | webrtc: 11 | $(CC) ./webrtc_recv.c ../SignallingClient/signalling_client.c -o ./webrtc_recv $(LIBS) $(PKG_CONFIG) 12 | 13 | clean: 14 | rm -rf ./webrtc_recv 15 | 16 | run: 17 | make 18 | ./webrtc_recv 19 | 20 | -------------------------------------------------------------------------------- /GstreamerClient/compile_commands.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "arguments": [ 4 | "/usr/bin/gcc", 5 | "-c", 6 | "-pthread", 7 | "-I/usr/include/libsoup-2.4", 8 | "-I/usr/include/libxml2", 9 | "-I/usr/include/json-glib-1.0", 10 | "-I/usr/include/gstreamer-1.0", 11 | "-I/usr/include/orc-0.4", 12 | "-I/usr/include/gstreamer-1.0", 13 | "-I/usr/include/x86_64-linux-gnu", 14 | "-I/usr/include/libmount", 15 | "-I/usr/include/blkid", 16 | "-I/usr/include/glib-2.0", 17 | "-I/usr/lib/x86_64-linux-gnu/glib-2.0/include", 18 | "-Wl,--export-dynamic", 19 | "-pthread", 20 | "-o", 21 | "./webrtc_recv", 22 | "./webrtc_recv.c" 23 | ], 24 | "directory": "/home/usama/learn/webrtc-from-scrach/GstreamerClient", 25 | "file": "/home/usama/learn/webrtc-from-scrach/GstreamerClient/webrtc_recv.c", 26 | "output": "/home/usama/learn/webrtc-from-scrach/GstreamerClient/webrtc_recv" 27 | } 28 | ] 29 | -------------------------------------------------------------------------------- /GstreamerClient/webrtc_recv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/USAMAWIZARD/webrtc-from-scratch/c427f0ec643f6504d5bdbdb02924de68b3bd404d/GstreamerClient/webrtc_recv -------------------------------------------------------------------------------- /ICE/ice.c: -------------------------------------------------------------------------------- 1 | #include "ice.h" 2 | #include "../Network/network.h" 3 | #include "../STUN/stun.h" 4 | #include "../Utils/utils.h" 5 | #include "../WebRTC/webrtc.h" 6 | #include "glib.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | // candidate-attribute = "candidate" ":" foundation SP component-id SP 22 | // transport SP 23 | // priority SP 24 | // connection-address SP ;from RFC 4566 25 | // port ;port from RFC 4566 26 | // SP cand-type 27 | // [SP rel-addr] 28 | // [SP rel-port] 29 | // *(SP extension-att-name SP 30 | // extension-att-value) 31 | // candidate:2764676115 1 udp 2122194687 192.168.0.110 37515 typ host generation 32 | // 0 ufrag 0KCc network-id 2 network-cost 10 33 | 34 | bool parse_ice_candidate(struct RTCIecCandidates *candidate) { 35 | 36 | if (candidate == NULL) { 37 | return false; 38 | } 39 | 40 | candidate->id = rand(); 41 | 42 | if (candidate->candidate == NULL || 43 | g_strcmp0(candidate->candidate, "") == 0) { 44 | char *candidate_str; 45 | 46 | candidate_str = g_strdup_printf( 47 | "candidate:%d %d %s %d %s %d typ %s generation 0 ufrag %s", 48 | candidate->foundation, candidate->component_id, "udp", 49 | candidate->priority, candidate->address, candidate->port, 50 | candidate->type, "H0Tz"); 51 | candidate->candidate = candidate_str; 52 | return true; 53 | } 54 | 55 | char *candidate_cpy = strdup(candidate->candidate); 56 | char *candidate_colon = strtok(candidate_cpy, ":"); 57 | if (candidate_colon == NULL || 58 | strncmp(candidate_colon, "candidate:", 10) == 0) 59 | return false; 60 | 61 | char *foundation = strtok(0, " "); 62 | if (foundation == NULL) 63 | return false; 64 | candidate->foundation = atoi(foundation); 65 | 66 | char *component_id = strtok(0, " "); 67 | if (component_id == NULL) 68 | return false; 69 | candidate->component_id = atoi(component_id); 70 | 71 | char *transport = strtok(0, " "); 72 | if (transport == NULL) 73 | return false; 74 | candidate->transport = transport; 75 | 76 | char *priority = strtok(0, " "); 77 | if (priority == NULL) 78 | return false; 79 | candidate->priority = atoi(priority); 80 | 81 | char *address = strtok(0, " "); 82 | if (address == NULL) 83 | return false; 84 | candidate->address = address; 85 | 86 | char *port = strtok(0, " "); 87 | if (port == NULL) 88 | return false; 89 | candidate->port = atoi(port); 90 | 91 | char *type = strtok(0, " "); 92 | type = strtok(0, " "); 93 | if (type == NULL) 94 | return false; 95 | candidate->type = type; 96 | 97 | if (strncmp(type, "srflx", 5) == 0) { 98 | char *raddr = strtok(0, " "); 99 | raddr = strtok(0, " "); 100 | if (raddr == NULL) 101 | return true; 102 | candidate->raddr = raddr; 103 | 104 | char *rport = strtok(0, " "); 105 | rport = strtok(0, " "); 106 | if (rport == NULL) 107 | return true; 108 | candidate->rport = atoi(rport); 109 | } 110 | candidate->ufrag = NULL; 111 | 112 | char *ufrag = strtok(0, " "); 113 | while (ufrag != NULL) { 114 | if (g_strcmp0(ufrag, "ufrag") == 0) { 115 | ufrag = strtok(0, " "); 116 | candidate->ufrag = ufrag; 117 | return true; 118 | } 119 | ufrag = strtok(0, " "); 120 | } 121 | return true; 122 | } 123 | 124 | char *get_candidate_string(int foundation, int component_id, int priority, 125 | char *ip, int port, char *candidate_type) { 126 | 127 | char *candidate; 128 | candidate = g_strdup_printf( 129 | "candidate:%d %d %s %d %s %d typ %s generation 0 ufrag %s", foundation, 130 | component_id, "udp", priority, ip, port, candidate_type, "H0Tz"); 131 | 132 | return candidate; 133 | } 134 | 135 | // not posix complient support ipv4 136 | char *get_running_NIC_IP(struct ifaddrs **network_interface) { 137 | 138 | while (*network_interface != NULL) { 139 | char *ip = malloc(16); 140 | 141 | ip = get_ip_str((*network_interface)->ifa_addr, ip, NULL, 142 | sizeof(struct sockaddr)); 143 | unsigned int nic_status = (*network_interface)->ifa_flags; 144 | 145 | bool is_running = ((nic_status & IFF_RUNNING) == IFF_RUNNING) && 146 | ((nic_status & IFF_LOOPBACK) != IFF_LOOPBACK); 147 | if ((*network_interface)->ifa_addr->sa_family == AF_INET6 || ip == NULL || 148 | !is_running) { 149 | 150 | *network_interface = (*network_interface)->ifa_next; 151 | continue; 152 | } 153 | 154 | *network_interface = (*network_interface)->ifa_next; 155 | return ip; 156 | } 157 | 158 | return NULL; 159 | } 160 | struct RTCRtpTransceivers *get_transceiver(struct RTCRtpTransceivers *trans, 161 | int mid) { 162 | for (; trans != NULL && trans->mid != mid; trans = trans->next_trans) { 163 | 164 | printf("---------------------------------------\n"); 165 | } 166 | 167 | return trans; 168 | } 169 | void add_local_icecandidate(struct RTCPeerConnection *peer, 170 | struct RTCIecCandidates *candidate) { 171 | void (*on_ice_candidate_callback)(struct RTCPeerConnection *, 172 | struct RTCIecCandidates *) = 173 | peer->on_ice_candidate; 174 | if (candidate == NULL) 175 | goto nullcandidate; 176 | 177 | struct RTCRtpTransceivers *transceiver = peer->transceiver; 178 | 179 | transceiver = get_transceiver(transceiver, candidate->sdpMid); 180 | if (transceiver == NULL) { 181 | return; 182 | } 183 | 184 | transceiver->local_ice_password = "HXeKrqNxtoH7MLYV/gQXytWJ"; 185 | transceiver->local_ice_ufrag = candidate->ufrag; 186 | 187 | if (transceiver->local_ice_candidate == NULL) { 188 | transceiver->local_ice_candidate = candidate; 189 | transceiver->local_ice_candidate->next_candidate = NULL; 190 | } else { 191 | struct RTCIecCandidates *last_candidate; 192 | for (last_candidate = transceiver->local_ice_candidate; 193 | last_candidate->next_candidate != NULL; 194 | last_candidate = last_candidate->next_candidate) { 195 | } 196 | candidate->next_candidate = NULL; 197 | last_candidate->next_candidate = candidate; 198 | } 199 | 200 | printf("---------added local candidate added %s://%s:%d----------\n", 201 | candidate->transport, candidate->address, candidate->port); 202 | nullcandidate: 203 | if (on_ice_candidate_callback != NULL) 204 | on_ice_candidate_callback(peer, candidate); 205 | } 206 | // can have seprate ports to support diffrent bundle policies 207 | // eatch stream should have its own ice candidate 208 | void gather_ice_candidate(struct RTCPeerConnection *peer) { 209 | 210 | peer->ice_connection_state = ICE_GATHRING; 211 | struct ifaddrs *all_network_interface; 212 | 213 | getifaddrs(&all_network_interface); 214 | 215 | if (all_network_interface < 0) { 216 | printf("something went wrong when gathring candidates"); 217 | exit(0); 218 | } 219 | 220 | char *local_ip; 221 | int priority = 0xFFFF; 222 | int foundation = 42322; 223 | int component_id = 1; // rtp 1 rtcp 2 both muxed 1 224 | int port = 5020; 225 | char *candidate_type = "host"; 226 | char *candidate; 227 | char *ufrag = "H0Tz"; 228 | 229 | struct RTCIecCandidates *local_ice_candidate; 230 | 231 | // host candidates 232 | while ((local_ip = get_running_NIC_IP(&all_network_interface)) != NULL) { 233 | local_ice_candidate = calloc(1, sizeof(struct RTCIecCandidates)); 234 | 235 | local_ice_candidate->foundation = foundation; 236 | local_ice_candidate->port = port; 237 | local_ice_candidate->address = local_ip; 238 | local_ice_candidate->type = candidate_type; 239 | local_ice_candidate->component_id = 1; 240 | local_ice_candidate->sdpMid = 0; 241 | local_ice_candidate->candidate = ""; 242 | local_ice_candidate->transport = "udp"; 243 | local_ice_candidate->sock_desc = get_udp_sock_desc(); 244 | local_ice_candidate->src_socket = get_network_socket(local_ip, port); 245 | local_ice_candidate->ufrag = ufrag; 246 | local_ice_candidate->password = "HXeKrqNxtoH7MLYV/gQXytWJ"; 247 | local_ice_candidate->priority = 248 | (int)pow(2, 24) * (get_type_pref(candidate_type)) + 249 | (int)pow(2, 8) * 250 | (1) // can add option to give more pref to wired set 1 for now 251 | + (int)pow(2, 0) * (256 - component_id); 252 | 253 | if (bind(local_ice_candidate->sock_desc, 254 | (struct sockaddr *)local_ice_candidate->src_socket, 255 | sizeof(*local_ice_candidate->src_socket)) < 0) { 256 | perror("binding ip for stun failed"); 257 | } 258 | 259 | if (parse_ice_candidate(local_ice_candidate)) 260 | add_local_icecandidate(peer, local_ice_candidate); 261 | else 262 | printf("failed to parse ice candidate"); 263 | 264 | // listen_for_handshake(local_ip, port); 265 | priority--; 266 | } 267 | 268 | pthread_t *pkt_listener_t; 269 | pkt_listener_t = malloc(sizeof(pthread_t)); 270 | peer->listener_thread_id = pkt_listener_t; 271 | 272 | pthread_create(pkt_listener_t, NULL, &packet_listner_thread, (void *)peer); 273 | 274 | // Empty candidate to signal ICE gathring completion 275 | add_local_icecandidate(peer, NULL); 276 | 277 | return; 278 | } 279 | // incomplete 280 | void add_candidate_for_each_transiver( 281 | struct RTCPeerConnection *peer, struct RTCIecCandidates *local_candidate) { 282 | for (struct RTCRtpTransceivers *transceiver = peer->transceiver; 283 | transceiver != NULL; transceiver = transceiver->next_trans) { 284 | 285 | add_local_icecandidate(peer, local_candidate); 286 | } 287 | } 288 | 289 | // void listen_for_ice_handshake(struct RTCRtpTransceivers *transceiver ,struct 290 | // RTCIecCandidates *local_candidate,struct RTCIecCandidates *remote_candidate) 291 | // { 292 | // listen_for_ice_handshake() { 293 | // if (stun_request) 294 | // sendresponse() if (response) {} 295 | // } 296 | // } 297 | bool check_pair_compatiblity(struct RTCRtpTransceivers *transceiver, 298 | struct RTCIecCandidates *local_candidate, 299 | struct RTCIecCandidates *remote_candidate) { 300 | 301 | if (transceiver == NULL || local_candidate == NULL || 302 | remote_candidate == NULL) 303 | return false; 304 | 305 | // check if already exist 306 | for (struct CandidataPair *checklist = transceiver->pair_checklist; 307 | checklist != NULL; checklist = checklist->next_pair) { 308 | if ((local_candidate->id ^ remote_candidate->id) == checklist->xored_id) { 309 | // printf(" already exist candidate pair \n"); 310 | return false; 311 | } 312 | } 313 | 314 | if (strcicmp(local_candidate->transport, remote_candidate->transport) == 0) { 315 | return true; 316 | } 317 | return false; 318 | } 319 | // return true if new pair made 320 | bool make_pair(struct RTCRtpTransceivers *transceiver, 321 | struct RTCIecCandidates *rcandidate) { 322 | bool newpairmade = false; 323 | 324 | for (struct RTCIecCandidates *lcandidate = transceiver->local_ice_candidate; 325 | lcandidate != NULL; lcandidate = lcandidate->next_candidate) { 326 | // printf("try to pair candidate %s://%s:%d %s://%s:%d \n", 327 | // lcandidate->transport, lcandidate->address, lcandidate->port, 328 | // rcandidate->transport, rcandidate->address, rcandidate->port); 329 | if (check_pair_compatiblity(transceiver, lcandidate, rcandidate)) { 330 | struct CandidataPair *candidate_pair = 331 | calloc(1, sizeof(struct CandidataPair)); 332 | candidate_pair->p0 = lcandidate; 333 | candidate_pair->p1 = rcandidate; 334 | candidate_pair->isvalid = false; 335 | candidate_pair->state = ICE_PAIR_WAITING; 336 | candidate_pair->xored_id = lcandidate->id ^ rcandidate->id; 337 | 338 | strncpy(candidate_pair->transaction_id, g_uuid_string_random(), 12); 339 | 340 | printf("---------\n new candidate pair made for trans%d %s://%s:%d " 341 | "%s://%s:%d ----------\n", 342 | transceiver->mid, candidate_pair->p0->transport, 343 | candidate_pair->p0->address, candidate_pair->p0->port, 344 | candidate_pair->p1->transport, candidate_pair->p1->address, 345 | candidate_pair->p1->port); 346 | 347 | if (transceiver->pair_checklist == NULL) { 348 | transceiver->pair_checklist = candidate_pair; 349 | } else { 350 | struct CandidataPair *endlist = transceiver->pair_checklist; 351 | for (; endlist->next_pair != NULL; endlist = endlist->next_pair) 352 | ; 353 | endlist->next_pair = candidate_pair; 354 | } 355 | newpairmade = true; 356 | } 357 | } 358 | return newpairmade; 359 | } 360 | guint make_candidate_pair(struct args *arg) { 361 | struct RTCIecCandidates *candidate = arg->candidate; 362 | struct RTCRtpTransceivers *transceiver = arg->transceiver; 363 | if (candidate == NULL || transceiver == NULL) { 364 | return false; 365 | } 366 | make_pair(transceiver, candidate); 367 | return true; 368 | } 369 | // todo make this rfc complient by incorporating proper timer and priority 370 | // mechenism 371 | guint do_ice_handshake(struct RTCPeerConnection *peer) { 372 | 373 | for (struct RTCRtpTransceivers *transceiver = peer->transceiver; 374 | transceiver != NULL; transceiver = transceiver->next_trans) 375 | for (struct CandidataPair *pair = transceiver->pair_checklist; pair != NULL; 376 | pair = pair->next_pair) { 377 | pair->p1->password = transceiver->remote_ice_password; 378 | pair->p1->ufrag = transceiver->remote_ice_ufrag; 379 | 380 | send_stun_bind(pair, STUN_REQUEST_CLASS, NULL, NULL); 381 | 382 | printf("\n ice handshake request sent form %s://%s:%d to %s://%s:%d\n", 383 | pair->p0->transport, pair->p0->address, pair->p0->port, 384 | pair->p1->transport, pair->p1->address, pair->p1->port); 385 | 386 | if (pair->state == ICE_PAIR_WAITING) { 387 | pair->state = ICE_PAIR_INPROGRESS; 388 | return 0; 389 | } 390 | } 391 | return true; 392 | } 393 | void ice_handshake_ended(struct RTCIecCandidates *local_candidate, 394 | struct RTCIecCandidates *remote_candidate) { 395 | 396 | printf("\nice handchake ended for candididate pair %s:%d \n", "asf", 213); 397 | } 398 | int get_type_pref(char *candidate_type) { 399 | if (g_strcmp0(candidate_type, HOST_CANDIDATE) == 0) { 400 | return 126; 401 | } 402 | if (g_strcmp0(candidate_type, PRFLX_CANDIDATE) == 0) { 403 | return 93; 404 | } 405 | if (g_strcmp0(candidate_type, SRFLX_CANDIDATE) == 0) { 406 | return 62; 407 | } 408 | if (g_strcmp0(candidate_type, RELAY_CANDIDATE) == 0) { 409 | return 31; 410 | } 411 | return 0; 412 | } 413 | -------------------------------------------------------------------------------- /ICE/ice.h: -------------------------------------------------------------------------------- 1 | #ifndef _ICEH_ 2 | #define _ICEH_ 3 | 4 | #include "../WebRTC/webrtc.h" 5 | #include "stdbool.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define SDP_TYPE_OFFER "offer" 12 | #define SDP_TYPE_ANSWER "answer" 13 | #define TRANSPORT_STATE_NEW "new" 14 | #define TRANSPORT_STATE_CONNECTING "connecting" 15 | #define TRANSPORT_STATE_CONNECTED "connected" 16 | #define TRANSPORT_STATE_CLOSED "closed" 17 | #define TRANSPORT_STATE_FAILED "failed" 18 | 19 | #define ICE_NEW "new" 20 | #define ICE_GATHRING "gathring" 21 | #define ICE_COMPLEATE "complete" 22 | 23 | enum pair_state { 24 | ICE_PAIR_WAITING, // check not sent 25 | ICE_PAIR_INPROGRESS, // check sent response not recived 26 | ICE_PAIR_SUCCEEDED, // response recived 27 | ICE_PAIR_FAILED, // check sent no respose or unfavorable response 28 | ICE_PAIR_FROZEN 29 | }; 30 | 31 | #define ICE_AGENT_CONTROLLING "controlling" 32 | #define ICE_AGENT_CONROLLED "controlled" 33 | 34 | #define HOST_CANDIDATE "host" 35 | #define SRFLX_CANDIDATE "srflx" 36 | #define PRFLX_CANDIDATE "prflx" 37 | #define RELAY_CANDIDATE "relay" 38 | struct RTCIecCandidates { 39 | char *address; 40 | char *candidate; 41 | int component_id; 42 | int foundation; 43 | uint16_t port; 44 | uint32_t priority; 45 | char *transport; 46 | int sdpMid; 47 | char *type; 48 | char *raddr; 49 | int rport; 50 | uint32_t id; 51 | int sock_desc; 52 | char *ufrag; 53 | char *password; 54 | struct sockaddr_in *src_socket; 55 | struct RTCIecCandidates *next_candidate; 56 | }; 57 | 58 | struct CandidataPair { 59 | struct RTCIecCandidates *p0; 60 | struct RTCIecCandidates *p1; 61 | uint32_t xored_id; 62 | enum pair_state state; 63 | bool isvalid; 64 | uint32_t request_sent_count; 65 | uint32_t priority; 66 | struct CandidataPair *next_pair; 67 | char transaction_id[12]; 68 | }; 69 | 70 | void gather_ice_candidate(struct RTCPeerConnection *peer); 71 | bool parse_ice_candidate(struct RTCIecCandidates *candidate); 72 | void listen_for_ice_handshake(struct RTCIecCandidates *local_candidate); 73 | guint make_candidate_pair(struct args *arg); 74 | void add_candidate_for_each_transiver(struct RTCPeerConnection *peer, 75 | struct RTCIecCandidates *candidate); 76 | 77 | guint do_ice_handshake(struct RTCPeerConnection *peer); 78 | void ice_handshake_ended(struct RTCIecCandidates *local_candidate, 79 | struct RTCIecCandidates *remote_candidate); 80 | struct RTCRtpTransceivers *get_transceiver(struct RTCRtpTransceivers *trans, 81 | int mid); 82 | void add_local_icecandidate(struct RTCPeerConnection *peer, 83 | struct RTCIecCandidates *candidate); 84 | int get_type_pref(char *candidate_type); 85 | #endif // !_ICEH_ 86 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=ccache gcc 2 | CFLAGS=-ggdb -flto 3 | LIBS=-lavutil -lavcodec -lavformat -lgsasl -lz -lgmp -lm 4 | PKG_CONFIG=`pkg-config --cflags --libs libsoup-2.4 json-glib-1.0 openssl ` 5 | 6 | 7 | ifeq ($(MAKECMDGOALS),test) 8 | EXCLUDE=-not -name "webrtc_app.c" -not -path "./SignallingClient/*" 9 | else 10 | EXCLUDE=-not -name "test.c" -not -path "./test/*" 11 | endif 12 | 13 | 14 | SRC=$(shell find . $(EXCLUDE) -name "*.c" -not -path "./SignallingServer/*" -not -path "./GstreamerClient/*") 15 | 16 | OBJECTS=$(SRC:.c=.o) 17 | 18 | $(info src files $(SRC)) 19 | $(info obj files $(OBJECTS)) 20 | 21 | all:webrtc 22 | 23 | 24 | webrtc:$(OBJECTS) 25 | $(CC) $(CFLAGS) -o $@ $(addprefix ./build/,$(^F)) $(LIBS) $(PKG_CONFIG) 26 | 27 | %.o:%.c 28 | $(CC) $(CFLAGS) -c -o $(addprefix ./build/,$(@F)) $^ $(PKG_CONFIG) 29 | 30 | clean: 31 | rm -rf ./build/* 32 | 33 | run: 34 | make 35 | ./webrtc 36 | 37 | test:webrtc 38 | ./webrtc 39 | 40 | startservers: 41 | nohup npm start --prefix ./WebRTC_Browser_APP/ & 42 | npm start --prefix ./SignallingServer/ 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Network/network.c: -------------------------------------------------------------------------------- 1 | #include "network.h" 2 | #include "../DTLS/dtls.h" 3 | #include "../STUN/stun.h" 4 | #include "../Utils/utils.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #pragma pack(1) 25 | struct sockaddr_in *get_network_socket(char *ip, int port) { 26 | 27 | struct sockaddr_in *socket_address; 28 | socket_address = malloc(sizeof(struct sockaddr_in)); 29 | socket_address->sin_family = AF_INET; // ipv4 by defalult 30 | socket_address->sin_port = htons(port); 31 | socket_address->sin_addr.s_addr = 32 | ip != NULL ? inet_addr(ip) : htonl(INADDR_ANY); 33 | 34 | return socket_address; 35 | } 36 | 37 | int get_udp_sock_desc() { 38 | int socket_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 39 | if (socket_desc < 0) { 40 | printf("Error while creating socket\n"); 41 | return -1; 42 | } 43 | return socket_desc; 44 | } 45 | 46 | char *get_ip_str(const struct sockaddr *sa, char *s_ip, uint16_t *port, 47 | size_t maxlen) { 48 | switch (sa->sa_family) { 49 | case AF_INET: 50 | struct sockaddr_in *sin = (struct sockaddr_in *)sa; 51 | if (s_ip != NULL) { 52 | inet_ntop(AF_INET, &sin->sin_addr, s_ip, maxlen); 53 | } 54 | if (port != NULL) 55 | *port = htons(sin->sin_port); 56 | break; 57 | 58 | case AF_INET6: 59 | inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), s_ip, 60 | maxlen); 61 | break; 62 | 63 | default: 64 | strncpy(s_ip, "Unknown AF", maxlen); 65 | return NULL; 66 | } 67 | 68 | return s_ip; 69 | } 70 | 71 | // todo: change here to support diffrent bundle policy make thread argument more 72 | // robust 73 | void *packet_listner_thread(void *peer_v) { 74 | struct RTCPeerConnection *peer = (struct RTCPeerConnection *)peer_v; 75 | uint16_t sport; 76 | uint16_t rport; 77 | char sender_ip[20]; 78 | char recv_ip[20]; 79 | guchar udp_packet[1000]; 80 | socklen_t socklen = sizeof(struct sockaddr_in); 81 | 82 | struct sockaddr *sender_addr = malloc(sizeof(struct sockaddr)); 83 | struct sockaddr *receiver_addr = malloc(sizeof(struct sockaddr)); 84 | 85 | if (peer->transceiver == NULL && 86 | peer->transceiver->local_ice_candidate == NULL) { 87 | printf("something went wrong null"); 88 | exit(0); 89 | return 0; 90 | } 91 | struct pollfd *candidates_fds; 92 | int candidate_list_size = get_candidates_fd_array(peer, &candidates_fds); 93 | 94 | send_stun_bind(NULL, STUN_REQUEST_CLASS, 95 | peer->transceiver->local_ice_candidate, NULL); 96 | 97 | while (poll(candidates_fds, candidate_list_size, -1) != -1) { 98 | for (int poll_index = 0; poll_index < candidate_list_size; poll_index++) { 99 | 100 | if (!((candidates_fds + poll_index)->revents & POLL_IN)) { 101 | continue; 102 | } 103 | 104 | int sock_desc = (candidates_fds + poll_index)->fd; 105 | uint32_t bytes = 106 | recvfrom(sock_desc, udp_packet, 1000, 0, sender_addr, &socklen); 107 | 108 | if (bytes == -1) 109 | printf("error something went wrong when reciving stun response %d", 110 | errno); 111 | 112 | struct NetworkPacket *packet = 113 | get_parsed_packet(peer->dtls_transport, udp_packet, bytes); 114 | 115 | if (!packet) { 116 | printf("packet detected a NULL\n"); 117 | continue; 118 | } 119 | getsockname(sock_desc, receiver_addr, &socklen); 120 | packet->receiver_sock = receiver_addr; 121 | 122 | get_ip_str(sender_addr, sender_ip, &sport, socklen); 123 | get_ip_str((struct sockaddr *)receiver_addr, recv_ip, &rport, socklen); 124 | 125 | packet->sender_ip = sender_ip; 126 | packet->receiver_ip = recv_ip; 127 | packet->sender_port = &sport; 128 | packet->receiver_port = &rport; 129 | packet->sock_desc = sock_desc; 130 | packet->sock_len = socklen; 131 | 132 | packet->sender_sock = sender_addr; 133 | packet->receiver_sock = receiver_addr; 134 | packet->total_bytes_recvied = bytes; 135 | 136 | if (packet->protocol == STUN) { 137 | printf("recived stun packet \n"); 138 | on_stun_packet(packet, peer); 139 | } else if (packet->protocol == DTLS) { 140 | 141 | // printf("%d aa\n", packet->total_bytes_recvied); 142 | // print_hex(packet, packet->total_bytes_recvied); 143 | on_dtls_packet(packet, peer); 144 | } else if (packet->protocol == RTP) { 145 | // parse RTP packet 146 | } else if (packet->protocol == RTCP) { 147 | // parse RTCP packet 148 | } 149 | } 150 | } 151 | return 0; 152 | } 153 | struct NetworkPacket *get_parsed_packet(struct RTCDtlsTransport *dtls_transport, 154 | guchar *packet, uint32_t bytes) { 155 | 156 | // check if its a STUN 157 | struct NetworkPacket *network_packet = malloc(sizeof(struct NetworkPacket)); 158 | struct Stun *stun = (struct Stun *)malloc(sizeof(struct Stun)); 159 | memcpy(stun, packet, sizeof(struct Stun)); 160 | network_packet->total_bytes_recvied = bytes; 161 | 162 | if (check_if_stun(stun)) { 163 | network_packet->protocol = STUN; 164 | network_packet->header.stun_header = stun; 165 | // class request 00 indication 01 success response 10 error 11 166 | // method binding 01 response 10 167 | int class = stun->msg_type & 0x110; 168 | int method = stun->msg_type & 0x3EEF; 169 | 170 | if (class == STUN_RESPONSE_CLASS && method == STUN_BINDING_METHOD) { 171 | printf("recived stun binding response \n"); 172 | network_packet->subtype = BINDING_RESPONSE; 173 | 174 | struct StunPayload *stun_respose_payload = 175 | malloc(sizeof(struct StunPayload)); 176 | int stun_header_size = sizeof(struct Stun); 177 | 178 | memcpy(stun_respose_payload, 179 | packet + stun_header_size + sizeof(struct TVL), 180 | sizeof(struct StunPayload)); 181 | 182 | network_packet->payload.stun_payload = stun_respose_payload; 183 | 184 | uint32_t magic = STUN_MAGIC_COOKIE; 185 | 186 | uint16_t mapped_port = 187 | (ntohs(stun_respose_payload->x_port) ^ 188 | ((uint16_t)(ntohs(stun->magic_cookie)))); // port and ip is sotred 189 | // xored with the cookie 190 | uint32_t mapped_ip = ntohl(ntohl(stun_respose_payload->x_ip) ^ (magic)); 191 | 192 | stun_respose_payload->x_ip = mapped_ip; 193 | } 194 | 195 | if (class == STUN_REQUEST_CLASS && method == STUN_BINDING_METHOD) { 196 | printf("\n received stun binding request"); 197 | network_packet->subtype = BINDING_REQUEST; 198 | } 199 | 200 | // if (class == method ==) { 201 | // } 202 | 203 | return network_packet; 204 | } 205 | 206 | uint8_t first_byte = packet[0]; 207 | 208 | if (check_if_dtls(first_byte)) { 209 | printf("dtls packet \n"); 210 | network_packet->protocol = DTLS; 211 | 212 | struct DtlsParsedPacket *dtls_packet = 213 | calloc(1, sizeof(struct DtlsParsedPacket)); 214 | network_packet->payload.dtls_parsed = dtls_packet; 215 | 216 | uint32_t remaining_bytes = bytes; 217 | 218 | uint16_t dtls_header_size = sizeof(struct DtlsHeader); 219 | while (remaining_bytes > 0) { 220 | 221 | if (remaining_bytes < dtls_header_size) { 222 | printf("%d rem\n", remaining_bytes); 223 | exit(0); 224 | return NULL; 225 | } 226 | struct DtlsHeader *dtls_header = malloc(dtls_header_size); 227 | dtls_packet->dtls_header = dtls_header; 228 | memcpy(dtls_header, packet, dtls_header_size); 229 | dtls_header->length = ntohs(dtls_header->length); 230 | dtls_header->epoch = htons(dtls_header->epoch); 231 | 232 | remaining_bytes = remaining_bytes - dtls_header_size; 233 | packet = packet + dtls_header_size; 234 | 235 | if (dtls_header->epoch) { 236 | if (dtls_transport->dtls_ctx != NULL) { 237 | 238 | dtls_header->length = 239 | decrypt_dtls(dtls_transport, &packet, dtls_header->length); 240 | remaining_bytes = dtls_header->length; // fix here 241 | 242 | } else 243 | g_error("recived encrypted packet but dtls context is null"); 244 | } 245 | 246 | if (dtls_header->type != 22) { 247 | 248 | uint16_t header_paylod_size = dtls_header->length; 249 | 250 | if (remaining_bytes < header_paylod_size) { 251 | return NULL; 252 | } 253 | remaining_bytes = remaining_bytes - header_paylod_size; 254 | dtls_packet->payload = malloc(header_paylod_size); 255 | memcpy(dtls_packet->payload, packet, header_paylod_size); 256 | packet = packet + header_paylod_size; 257 | 258 | goto next_record; 259 | } 260 | 261 | struct HandshakeHeader *handshake_header = 262 | malloc(sizeof(struct HandshakeHeader)); 263 | 264 | uint16_t handshake_header_size = sizeof(struct HandshakeHeader); 265 | if (remaining_bytes < handshake_header_size) 266 | return NULL; 267 | 268 | memcpy(handshake_header, packet, handshake_header_size); 269 | remaining_bytes = remaining_bytes - handshake_header_size; 270 | dtls_packet->handshake_header = handshake_header; 271 | dtls_packet->handshake_type = handshake_header->type; 272 | 273 | uint32_t fragment_len = 274 | ntohl((uint32_t)handshake_header->fragment_length) >> 8; 275 | uint32_t length = ntohl((uint32_t)handshake_header->length) >> 8; 276 | uint32_t fragment_offset = 277 | ntohl((uint32_t)handshake_header->fragment_offset) >> 8; 278 | 279 | if (fragment_len != length) { 280 | dtls_packet->isfragmented = true; 281 | uint16_t total_recvied_len = fragment_offset + fragment_len; 282 | if (total_recvied_len == length) 283 | dtls_packet->islastfragment = true; 284 | else 285 | dtls_packet->islastfragment = false; 286 | } else { 287 | dtls_packet->isfragmented = false; 288 | dtls_packet->islastfragment = false; 289 | } 290 | 291 | packet = packet + handshake_header_size; 292 | 293 | if (remaining_bytes != 0 && remaining_bytes >= fragment_len) { 294 | 295 | if (length < fragment_offset + fragment_len) { 296 | 297 | return NULL; 298 | } 299 | 300 | dtls_packet->handshake_payload = malloc(length); 301 | 302 | memcpy(dtls_packet->handshake_payload, packet, fragment_len); 303 | 304 | packet = packet + fragment_len; 305 | remaining_bytes = remaining_bytes - fragment_len; 306 | } 307 | next_record: 308 | 309 | if (remaining_bytes >= dtls_header_size) { 310 | dtls_packet->next_record = calloc(1, sizeof(struct DtlsParsedPacket)); 311 | dtls_packet = dtls_packet->next_record; 312 | } 313 | if (remaining_bytes == 0) { 314 | return network_packet; 315 | } 316 | } 317 | 318 | return NULL; 319 | } 320 | 321 | if (false) { // check if rtp or rtcp 322 | } 323 | // check if RTP RTCP 324 | return NULL; 325 | } 326 | 327 | int get_candidates_fd_array(struct RTCPeerConnection *peer, 328 | struct pollfd **candidate_fd) { 329 | if (peer == NULL || peer->transceiver == NULL) 330 | return 0; 331 | struct pollfd *fd_array = malloc(sizeof(struct pollfd) * 10); 332 | struct pollfd *i = fd_array; 333 | int size = 10; 334 | 335 | for (struct RTCRtpTransceivers *transceiver = peer->transceiver; 336 | transceiver != NULL; transceiver = transceiver->next_trans) { 337 | for (struct RTCIecCandidates *candidate = transceiver->local_ice_candidate; 338 | candidate != NULL; candidate = candidate->next_candidate) { 339 | if ((fd_array + size) == i) { 340 | fd_array = realloc(fd_array, sizeof(struct pollfd) * size + 341 | sizeof(struct pollfd) * 10); 342 | size = size + 10; 343 | } 344 | struct pollfd *fd = malloc(sizeof(struct pollfd)); 345 | fd->fd = candidate->sock_desc; 346 | fd->events = POLL_IN; 347 | 348 | *i = *fd; 349 | i++; 350 | } 351 | if (BUNDLE_MAX_BUNDLE) { // compare webrtc config param todo 352 | break; 353 | } 354 | } 355 | *candidate_fd = fd_array; 356 | 357 | return i - fd_array; 358 | } 359 | 360 | uint32_t hton24(uint32_t host24) { 361 | host24 &= 0xFFFFFF; 362 | 363 | uint8_t byte1 = (host24 >> 16) & 0xFF; 364 | uint8_t byte2 = (host24 >> 8) & 0xFF; 365 | uint8_t byte3 = host24 & 0xFF; 366 | 367 | return (byte1 << 16) | (byte2 << 8) | byte3; 368 | } 369 | -------------------------------------------------------------------------------- /Network/network.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | #include 4 | #ifndef _NETWORKH_ 5 | #define _NETWORKH_ 6 | 7 | #include "../RTP/rtp.h" 8 | #include "../STUN/stun.h" 9 | #include "../WebRTC/webrtc.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | enum packet_protocol { STUN, DTLS, RTP, RTCP }; 17 | enum subtype { BINDING_REQUEST, BINDING_RESPONSE }; 18 | 19 | struct sockaddr_in *get_network_socket(char *ip, int port); 20 | union header { 21 | struct Stun *stun_header; 22 | struct DtlsHeader *dtls_header; 23 | struct Rtp *rtp_header; 24 | }; 25 | union payload { 26 | struct StunPayload *stun_payload; 27 | struct DtlsParsedPacket *dtls_parsed; 28 | }; 29 | 30 | struct NetworkPacket { 31 | char *sender_ip; 32 | char *receiver_ip; 33 | uint16_t *sender_port; 34 | uint16_t *receiver_port; 35 | union header header; 36 | union payload payload; 37 | enum packet_protocol protocol; 38 | enum subtype subtype; 39 | int sock_desc; 40 | size_t sock_len; 41 | struct sockaddr *sender_sock; 42 | struct sockaddr *receiver_sock; 43 | uint16_t total_bytes_recvied; 44 | }; 45 | char *get_ip_str(const struct sockaddr *sa, char *s_ip, uint16_t *port, 46 | size_t maxlen); 47 | int get_udp_sock_desc(); 48 | void *packet_listner_thread(void *peer_v); 49 | 50 | bool check_if_stun(struct Stun *stun_header); 51 | struct NetworkPacket *get_parsed_packet(struct RTCDtlsTransport *dtls_transport, 52 | guchar *packet, uint32_t bytes); 53 | int get_candidates_fd_array(struct RTCPeerConnection *peer, 54 | struct pollfd **candidate_fd); 55 | uint32_t hton24(uint32_t host24); 56 | #endif // !_NETWORKH_ 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ** still under development 2 | # TODO List 3 | 4 | - [ ] Signal passing for callbacks 5 | - [ ] make it browser compatible 6 | - [ ] add basic security checks 7 | - [ ] refactor encryption and decryption logic 8 | - [ ] SRTP DTLS decryption ( IN PROGRESS) 9 | - [ ] Implement state changes for ICE, DTLS, and WebRTC 10 | - [ ] refactor implementation 11 | - [ ] Complete DTLS finish message verification 12 | - [ ] Threading 13 | 14 | 15 | ** 16 | This project tries to implement a very minamal webrtc implementation without considering much about to learn and understand in depth how WebRTC works
17 | 18 | It will make a WebRTC connection from another peer and send a stream in the simplest way possible
19 | 20 | https://github.com/user-attachments/assets/f8e3003f-2fb2-470a-aa16-a6fb0e0c798b 21 | 22 | 23 | # WebRTC Streaming from Scrach implementtion to Gstreamer Client 24 | sending a basic video from webrtc scrach implementation to a Gstreamer WebRTC Client. 25 | 26 | ## Build the Program 27 | 28 | 1. git clone https://github.com/USAMAWIZARD/webrtc-from-scrach.git 29 | 2. Run the following command to build the program: 30 | 31 | Build Scrach WebRTC implementation
32 | ``` 33 | make 34 | ``` 35 | 36 | Build Gstreamer Client WebRTC
37 | 38 | ``` 39 | cd GstreamerClient 40 | make 41 | ``` 42 | 43 | 44 | ## Start Signalling Server 45 | 46 | ``` 47 | cd SignallingServer/ 48 | npm i 49 | npm start 50 | ``` 51 | 52 | 53 | ## Start Scrach implementation (sender) 54 | 55 | 56 | ```sh 57 | ./webrtc 58 | ``` 59 | 60 | ## Start Gstreamer Client (receiver) 61 | 62 | Once the receiver is started, run your program with the following command: 63 | 64 | ```sh 65 | cd ./GstreamerClient 66 | ./webrtc_recv 67 | ``` 68 | 69 | now WebRTC Scrach implementation Will send a video to Gstreamer Client. 70 | 71 | 72 | -------------------------------------------------------------------------------- /RTP/rtp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../SRTP/srtp.h" 3 | #include 4 | #include 5 | #include 6 | 7 | #ifndef _RTPH_ 8 | #define _RTPH_ 9 | 10 | struct RtpStream { 11 | void (*media_data_callback)(void *, 12 | void (*parsed_data_callback)(struct RtpStream *, 13 | char *, uint32_t), 14 | struct RtpStream *); 15 | struct Rtp *rtp_packet; 16 | void *callback_data; 17 | struct CandidataPair *pair; 18 | char *streamState; 19 | int socket_len; 20 | uint8_t payload_type : 7; 21 | int clock_rate; 22 | uint16_t seq_no; 23 | uint32_t ssrc; 24 | uint32_t timestamp; 25 | uint8_t marker : 1; 26 | struct SrtpEncryptionCtx *srtp_encryption_ctx; 27 | struct MediaStreamTrack *track; 28 | }; 29 | 30 | struct RtpSession { 31 | struct RtpStream *streams[10]; 32 | int totalStreams; 33 | }; 34 | struct __attribute__((packed)) Rtp { 35 | #if G_BYTE_ORDER == G_LITTLE_ENDIAN 36 | unsigned int csrc_count : 4; 37 | unsigned int ext : 1; 38 | unsigned int padding : 1; 39 | unsigned int v : 2; 40 | #elif G_BYTE_ORDER == G_BIG_ENDIAN 41 | unsigned int v : 2; 42 | unsigned int padding : 1; 43 | unsigned int ext : 1; 44 | unsigned int csrc_count : 4; 45 | #else 46 | #error "Byte order is not recognized it should either be big or little endian" 47 | #endif 48 | 49 | #if G_BYTE_ORDER == G_LITTLE_ENDIAN 50 | unsigned int pt : 7; 51 | unsigned int marker : 1; 52 | 53 | #elif G_BYTE_ORDER == G_BIG_ENDIAN 54 | unsigned int marker : 1; 55 | unsigned int pt : 7; 56 | #error "Byte order is not recognized it should either be big or little endian" 57 | #endif 58 | unsigned int seq_no : 16; 59 | unsigned int timestamp : 32; 60 | unsigned int ssrc : 32; 61 | unsigned int csrc : 32; 62 | guchar payload[]; 63 | }; 64 | struct RtpSession *create_rtp_session(); 65 | void init_rtp_stream(struct RtpStream *stream, struct CandidataPair *pair, 66 | struct SrtpEncryptionCtx *srtp_encryption_ctx); 67 | struct RtpStream *create_rtp_stream(struct RtpSession *rtp_session, 68 | struct MediaStreamTrack *track, 69 | uint32_t ssrc, uint8_t payload_type); 70 | 71 | bool start_rtp_session(struct RtpSession *rtpSession); 72 | bool start_rtp_stream(struct RtpStream *rtpStream); 73 | int get_udp_sock_desc(); 74 | // void send_rtp_packet(struct RtpStream *rtpStream, char *payload, int 75 | // payload_size); 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /RTP/rtp_session.c: -------------------------------------------------------------------------------- 1 | #include "rtp.h" 2 | #include 3 | #include 4 | #include 5 | struct RtpSession *create_rtp_session() { 6 | struct RtpSession *newRtpSession; 7 | newRtpSession = malloc(sizeof(struct RtpSession)); 8 | newRtpSession->totalStreams = -1; 9 | return newRtpSession; 10 | } 11 | // number of streams started 12 | bool start_rtp_session(struct RtpSession *rtpSession) { 13 | if (rtpSession->totalStreams < 0) { 14 | printf("\n No RTP Stream in Session\n"); 15 | return false; 16 | } 17 | for (int i = rtpSession->totalStreams; i >= 0; i--) { 18 | if (!start_rtp_stream(rtpSession->streams[i])) { 19 | printf("failed to start RTP Session"); 20 | return false; 21 | } else { 22 | printf("rtp stream started for session %d ", i); 23 | } 24 | } 25 | return true; 26 | } 27 | -------------------------------------------------------------------------------- /RTP/rtp_stream.c: -------------------------------------------------------------------------------- 1 | // https://datatracker.ietf.org/doc/html/rfc3550 2 | /* 3 | RTP Header 4 | 5 | 0 1 2 3 6 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 7 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 8 | |V=2|P|X| CC |M| PT | sequence number | 9 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 10 | | timestamp | 11 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 12 | | synchronization source (SSRC) identifier | 13 | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | contributing source 14 | (CSRC) identifiers | | .... | 15 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 16 | 17 | RTP payload header. 18 | 19 | 0 1 2 3 20 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 21 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 22 | |F|NRI| Type | | 23 | +-+-+-+-+-+-+-+-+ | 24 | | | 25 | | Bytes 2..n of a single NAL unit | 26 | | | 27 | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 28 | | :...OPTIONAL RTP padding | 29 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 30 | */ 31 | #include "../Network/network.h" 32 | #include "../SRTP/srtp.h" 33 | #include "../Utils/utils.h" 34 | #include "../WebRTC/webrtc.h" 35 | #include "rtp.h" 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | void send_rtp_packet(struct RtpStream *rtpStream, char *payload, 48 | uint32_t payload_size); 49 | 50 | struct Rtp *init_rtp_packet(struct RtpStream *rtpStream) { 51 | struct Rtp *rtp_packet_packet; 52 | rtp_packet_packet = (struct Rtp *)malloc(sizeof(*rtp_packet_packet) + 50000); 53 | rtp_packet_packet->v = 2; 54 | rtp_packet_packet->pt = rtpStream->payload_type; 55 | rtp_packet_packet->ext = 0; 56 | rtp_packet_packet->marker = rtpStream->marker; 57 | rtp_packet_packet->padding = 0; 58 | rtp_packet_packet->seq_no = htons(rtpStream->seq_no); // htons(rand()); 59 | rtp_packet_packet->csrc_count = 1; 60 | rtp_packet_packet->ssrc = htonl(rtpStream->ssrc); 61 | rtp_packet_packet->csrc = 0xffffffff; 62 | rtp_packet_packet->timestamp = 0; 63 | 64 | return rtp_packet_packet; 65 | } 66 | 67 | struct RtpStream *create_rtp_stream(struct RtpSession *rtp_session, 68 | struct MediaStreamTrack *track, 69 | uint32_t ssrc, uint8_t payload_type) { 70 | // set src and remote ip port 71 | struct RtpStream *newRtpStream; 72 | newRtpStream = malloc(sizeof(struct RtpStream)); 73 | if (track) { 74 | newRtpStream->media_data_callback = track->get_data_callback; 75 | newRtpStream->callback_data = track->userdata; 76 | } 77 | 78 | newRtpStream->ssrc = ssrc; 79 | newRtpStream->payload_type = payload_type; 80 | newRtpStream->seq_no = 100; 81 | newRtpStream->timestamp = 100; 82 | 83 | return newRtpStream; 84 | } 85 | void init_rtp_stream(struct RtpStream *stream, struct CandidataPair *pair, 86 | struct SrtpEncryptionCtx *srtp_encryption_ctx) { 87 | 88 | stream->socket_len = sizeof(struct sockaddr_in); 89 | stream->pair = pair; 90 | stream->rtp_packet = init_rtp_packet(stream); 91 | stream->srtp_encryption_ctx = srtp_encryption_ctx; 92 | } 93 | 94 | void send_rtp_packet(struct RtpStream *rtpStream, char *payload, 95 | uint32_t payload_size) { 96 | static uint16_t rtp_mtu_size = 1400; 97 | 98 | int socket_len = rtpStream->socket_len; 99 | 100 | rtpStream->rtp_packet->seq_no = htons(rtpStream->seq_no++); 101 | rtpStream->rtp_packet->timestamp = htonl(rtpStream->timestamp); 102 | 103 | memcpy(rtpStream->rtp_packet->payload, payload, payload_size); 104 | 105 | if (true) { // padding in case of block cipher 106 | uint8_t padding_size = 16 - (payload_size % 16); 107 | if (padding_size != 16) { 108 | rtpStream->rtp_packet->padding = 1; 109 | rtpStream->rtp_packet->payload[payload_size + padding_size - 1] = 110 | padding_size; 111 | payload_size += padding_size; 112 | } else 113 | rtpStream->rtp_packet->padding = 0; 114 | } 115 | 116 | if (rtpStream->srtp_encryption_ctx) { 117 | encrypt_srtp(rtpStream->srtp_encryption_ctx, rtpStream->rtp_packet, 118 | &payload_size); 119 | } else { 120 | printf("no srtp context found"); 121 | } 122 | 123 | int bytes = 124 | sendto(rtpStream->pair->p0->sock_desc, rtpStream->rtp_packet, 125 | sizeof(*rtpStream->rtp_packet) + payload_size, 0, 126 | (struct sockaddr *)(rtpStream->pair->p1->src_socket), socket_len); 127 | 128 | usleep(15000); 129 | 130 | if (bytes == -1) { 131 | printf("\n failed to send the data %s %d socket_len %d desc %d\n", 132 | strerror(errno), payload_size, socket_len, 133 | rtpStream->pair->p0->sock_desc); 134 | 135 | } else { 136 | // printf("\n sent data %d %d socket_len %d desc %d\n", errno, 137 | // payload_size, socket_len , rtpStream->sockdesc); 138 | } 139 | } 140 | 141 | // create a new thread and start sending rtp totalStreams 142 | bool start_rtp_stream(struct RtpStream *rtpStream) { 143 | 144 | (*rtpStream->media_data_callback)(rtpStream->callback_data, &send_rtp_packet, 145 | rtpStream); 146 | return true; 147 | } 148 | bool stop_rtp_stream(struct RtpStream *rtpStream) { 149 | if (close(rtpStream->pair->p0->sock_desc) < 0) { 150 | printf("failed to close the RTP"); 151 | return false; 152 | } 153 | return true; 154 | } 155 | -------------------------------------------------------------------------------- /SDP/sdp.c: -------------------------------------------------------------------------------- 1 | 2 | #include "./sdp.h" 3 | #include "../WebRTC/webrtc.h" 4 | #include "glib.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | char *get_sdp_constants() { 10 | char *sdp_header = g_strdup_printf("v=0\n" 11 | "o=- %d 2 IN IP4 %s\ns=-\nt= 0 0\n" 12 | "a=group:BUNDLE 0\n" 13 | "a=msid-semantic: WMS\n", 14 | rand(), "127.0.0.1"); 15 | return sdp_header; 16 | } 17 | 18 | char *get_ice_auth(struct RTCRtpTransceivers *transceiver) { 19 | char *ice_auth = g_strdup_printf("a=ice-ufrag:%s\n" 20 | "a=ice-pwd:%s\n" 21 | "a=ice_option:trickle\n", 22 | transceiver->local_ice_ufrag, 23 | transceiver->local_ice_password); 24 | return ice_auth; 25 | } 26 | 27 | char *get_dtls_sdp_param(struct RTCRtpTransceivers *transceiver) { 28 | char *dtls_auth_param = g_strdup_printf("a=fingerprint:sha-256 %s\n" 29 | "a=setup:actpass\n", 30 | "fingerprint"); 31 | return dtls_auth_param; 32 | } 33 | char *get_transceiver_info(struct RTCRtpTransceivers *transceiver) { 34 | 35 | char *transceiver_info = g_strdup_printf("a=mid:%d\n" 36 | "a=%s\n" 37 | "a=msid:- %s\n" 38 | "a=rtcp-mux\n" 39 | "a=rtcp-rsize\n", 40 | transceiver->mid, "sendrecv", 41 | transceiver->sender->track->id); 42 | 43 | return transceiver_info; 44 | } 45 | char *get_media_line(struct RTCRtpTransceivers *transceiver) {} 46 | char *get_encoding_info(struct RTCRtpTransceivers *transceiver) { 47 | char *encoding_info = g_strdup_printf( 48 | "a=rtpmap:102 H264/90000\n" 49 | "a=fmtp:102 " 50 | "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=" 51 | "42001f\n" 52 | "a=rtpmap:103 rtx/90000\n" 53 | "a=fmtp:103 apt=102\n" 54 | "a=ssrc:0 cname:Dp9Bc6LU+k7YLLrs\n" 55 | "a=ssrc:0 msid:- %s\n", 56 | transceiver->sender->track->id); 57 | return encoding_info; 58 | } 59 | 60 | char *generate_unmached_desc(struct RTCRtpTransceivers *transceiver) { 61 | char *media_descriptions = ""; 62 | while (transceiver != NULL) { 63 | if (transceiver->sender != NULL) { 64 | get_media_line(transceiver); 65 | get_ice_auth(transceiver); 66 | get_dtls_sdp_param(transceiver); 67 | get_encoding_info(transceiver); 68 | } 69 | transceiver = transceiver->next_trans; 70 | } 71 | 72 | return NULL; 73 | } 74 | 75 | JsonObject *get_test_ofer() { 76 | char *sdp = "v=0\n" 77 | "o=- 4395291772417888753 2 IN IP4 127.0.0.1\n" 78 | "s=-\n" 79 | "t=0 0\n" 80 | "a=group:BUNDLE 0\n" 81 | "a=msid-semantic: WMS\n" 82 | 83 | "m=video 9 UDP/TLS/RTP/SAVPF 102 103\n" 84 | "c=IN IP4 0.0.0.0\n" 85 | "a=rtcp:9 IN IP4 0.0.0.0\n" 86 | 87 | "a=ice-ufrag:H0Tz\n" 88 | "a=ice-pwd:HXeKrqNxtoH7MLYV/gQXytWJ\n" // this is used 89 | "a=ice-options:trickle\n" 90 | 91 | "a=fingerprint:sha-256 " 92 | "83:FA:64:DE:BE:89:4A:0F:D6:28:74:A0:BA:AD:2A:33:87:62:FB:84:39:" 93 | "B0:DE:4C:AE:68:AA:F9:79:92:40:FC\n" 94 | "a=setup:active\n" 95 | 96 | "a=mid:0\n" 97 | "a=sendonly\n" 98 | "a=msid:- 665d1bfb-1759-44c8-92d4-c1b6aaad5892\n" 99 | "a=rtcp-mux\n" 100 | "a=rtcp-rsize\n" 101 | 102 | "a=rtpmap:102 H264/90000\n" 103 | "a=fmtp:102 " 104 | "level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=" 105 | "42001f\n" 106 | "a=rtpmap:103 rtx/90000\n" 107 | "a=fmtp:103 apt=102\n" 108 | "a=ssrc:3735928559 cname:Dp9Bc6LU+k7YLLrs\n" 109 | "a=ssrc:3735928559 msid:- 665d1bfb-1759-44c8-92d4-c1b6aaad5892\n"; 110 | 111 | JsonObject *sdp_object = json_object_new(); 112 | 113 | json_object_set_string_member(sdp_object, "sdp", sdp); 114 | json_object_set_string_member(sdp_object, "type", "offer"); 115 | return sdp_object; 116 | } 117 | bool parse_sdp_string(struct RTCPeerConnection *peer, 118 | struct RTCSessionDescription *sdp) { 119 | // only getting ice-pwd for now will implement this funciton latter 120 | // 121 | // peer->transceiver 122 | char *rest_lines; 123 | char *sdp_line; 124 | char level = 's'; // s or m sesison level or media level 125 | rest_lines = sdp->sdp; 126 | char *mid = NULL; 127 | // todo also accept only \n to be rfc complient 128 | peer->parsed_remote_desc = calloc(1, sizeof(struct ParsedRemoteDescription)); 129 | while ((sdp_line = strtok_r(rest_lines, "\r\n", &rest_lines))) { 130 | char *rem = sdp_line; 131 | char *attribute = strtok_r(rem, "=", &rem); 132 | printf("%s %s\n", attribute, rem); 133 | 134 | switch (*attribute) { 135 | case 'v': 136 | if (strncmp(rem, "0", 1) != 0) 137 | return false; 138 | break; 139 | case 'o': 140 | break; 141 | case 's': 142 | break; 143 | case 't': 144 | break; 145 | case 'a': 146 | if (strncmp(rem, "ice-pwd", 7) == 0) { 147 | char *ice_password = rem; 148 | strtok_r(ice_password, ":", &ice_password); 149 | peer->transceiver->remote_ice_password = ice_password; 150 | printf("\n %s aa \n", ice_password); 151 | } else if (strncmp(rem, "ice-ufrag", 9) == 0) { 152 | char *ice_ufrag = rem; 153 | strtok_r(ice_ufrag, ":", &ice_ufrag); 154 | peer->transceiver->remote_ice_ufrag = ice_ufrag; 155 | printf(" %s \n", ice_ufrag); 156 | } else if (strncmp(rem, "fingerprint", 10) == 0) { 157 | char *fingerprint = rem; 158 | strtok_r(fingerprint, ":", &fingerprint); 159 | char *type; 160 | type = strtok_r(fingerprint, " ", &fingerprint); 161 | peer->parsed_remote_desc->fingerprint = fingerprint; 162 | peer->parsed_remote_desc->fingerprint_type = type; 163 | } 164 | 165 | break; 166 | case 'm': 167 | level = 'm'; 168 | 169 | break; 170 | default: 171 | break; 172 | } 173 | } 174 | 175 | return true; 176 | } 177 | 178 | void create_offer_sdp() {} 179 | 180 | void create_answer_sdp() {} 181 | JsonObject *sdp_to_json_object(struct RTCSessionDescription *sdp) {} 182 | 183 | struct RTCSessionDescription *json_object_to_sdp(JsonObject *sdp_json) { 184 | 185 | if (!json_object_has_member(sdp_json, "type") || 186 | !json_object_has_member(sdp_json, "sdp")) { 187 | return NULL; 188 | } 189 | struct RTCSessionDescription *session_desc = 190 | malloc(sizeof(struct RTCSessionDescription)); 191 | 192 | session_desc->type = (char *)json_object_get_string_member(sdp_json, "type"); 193 | session_desc->sdp = (char *)json_object_get_string_member(sdp_json, "sdp"); 194 | return session_desc; 195 | } 196 | -------------------------------------------------------------------------------- /SDP/sdp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../WebRTC/webrtc.h" 3 | #include 4 | #include 5 | #ifndef _SDPH_ 6 | #define _SDPH_ 7 | 8 | struct RTCSessionDescription { 9 | char *type; 10 | char *sdp; 11 | }; 12 | struct ParsedRemoteDescription { 13 | gchar *fingerprint; 14 | gchar *fingerprint_type; 15 | }; 16 | JsonObject *get_test_ofer(); 17 | char *get_sdp_constants(); 18 | char *generate_unmached_desc(struct RTCRtpTransceivers *transceiver); 19 | bool parse_sdp_string(struct RTCPeerConnection *peer, 20 | struct RTCSessionDescription *sdp); 21 | JsonObject *sdp_to_json_object(struct RTCSessionDescription *sdp); 22 | struct RTCSessionDescription *json_object_to_sdp(JsonObject *sdp_json); 23 | #endif // !_SDPH_ 24 | -------------------------------------------------------------------------------- /SRTP/srtp.c: -------------------------------------------------------------------------------- 1 | #include "./srtp.h" 2 | #include "../DTLS/Encryptions/encryption.h" 3 | #include "../RTP/rtp.h" 4 | #include "../Utils/utils.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | struct srtp_ext parse_srtp_ext(guchar *value, uint16_t len) { 16 | struct srtp_ext ext; 17 | memcpy(&ext, value, sizeof(struct srtp_ext)); 18 | ext.profile_len = ntohs(ext.profile_len); 19 | ext.encryption_profile = ntohs(ext.encryption_profile); 20 | printf("%x\n", ext.encryption_profile); 21 | 22 | return ext; 23 | } 24 | void compute_srtp_iv(guchar *all_xored_iv, guchar *salting_key, 25 | uint32_t salting_key_len, guchar *ssrc, 26 | guchar *packet_index) { 27 | // IV = (k_s * 2 ^ 16) XOR(SSRC * 2 ^ 64) XOR(i * 2 ^ 16) 28 | 29 | memset(all_xored_iv + 14, 0, 2); 30 | int pos = 16 - 2 - salting_key_len; // 16 shifted 31 | memcpy(all_xored_iv - pos, salting_key, salting_key_len); 32 | 33 | pos = 16 - 8 - 4; // 64 shifted 34 | for (int i = 3; i >= 0; i--) { 35 | all_xored_iv[pos] = all_xored_iv[pos] ^ ssrc[i]; 36 | pos++; 37 | } 38 | 39 | pos = 16 - 2 - 6; // 16 shifted 40 | for (int i = 5; i >= 0; i--) { 41 | all_xored_iv[pos] = all_xored_iv[pos] ^ packet_index[i]; 42 | pos++; 43 | } 44 | } 45 | 46 | void calculate_x_and_to_encrypt(struct SrtpEncryptionCtx *srtp_encrption_ctx, 47 | guchar *x, guchar *toencrypt, uint8_t lable) { 48 | // uint64_t key_id = 0; 49 | memset(x, 0, 16); 50 | memset(toencrypt, 0, 16); 51 | 52 | // uint64_t r = 0; 53 | // if (srtp_encrption_ctx->kdr) 54 | // r = srtp_encrption_ctx->index / srtp_encrption_ctx->kdr; 55 | // 56 | // memcpy(((guchar *)&key_id), (guchar *)&r, 48 / 8); 57 | 58 | memcpy(x, srtp_encrption_ctx->master_salt_key, 59 | srtp_encrption_ctx->cipher_suite_info->salt_key_len); 60 | 61 | x[7] ^= lable; 62 | 63 | // for (int i = 0; i <= 6; i++) 64 | // x[i + 8] = 65 | // ((guchar *)&key_id)[i] ^ srtp_encrption_ctx->master_salt_key[i + 8]; 66 | } 67 | 68 | struct AesEnryptionCtx *srtp_prf(struct SrtpEncryptionCtx *srtp_encrption_ctx, 69 | uint8_t lable, guchar **pp_data, 70 | uint32_t data_len) { 71 | 72 | struct AesEnryptionCtx *aes; 73 | guchar x[16]; 74 | guchar toencrypt[16] = {0}; 75 | guchar iv[16]; 76 | 77 | *pp_data = malloc(data_len + 16); 78 | guchar *i_data = *pp_data; 79 | int32_t i = data_len; 80 | if (data_len > 40) 81 | exit(0); 82 | 83 | calculate_x_and_to_encrypt(srtp_encrption_ctx, x, toencrypt, lable); 84 | memcpy(iv, x, 16); 85 | 86 | init_aes(&aes, srtp_encrption_ctx->master_write_key, 87 | srtp_encrption_ctx->cipher_suite_info->key_size, x, 88 | srtp_encrption_ctx->cipher_suite_info->hmac_key_len, iv, CM); 89 | 90 | while (i > 0) { 91 | calculate_x_and_to_encrypt(srtp_encrption_ctx, x, toencrypt, lable); 92 | encrypt_aes(aes, toencrypt, 0, 16); 93 | memcpy(i_data, toencrypt, 16); 94 | i -= 16; 95 | i_data += 16; 96 | transpose_matrix(aes->IV); 97 | } 98 | 99 | return aes; 100 | } 101 | 102 | void srtp_key_derivation(struct SrtpEncryptionCtx *srtp_encrption_ctx, 103 | struct cipher_suite_info *cipher_suite_info) { 104 | srtp_encrption_ctx->cipher_suite_info = cipher_suite_info; 105 | 106 | srtp_prf(srtp_encrption_ctx, lable_k_e, &srtp_encrption_ctx->k_e, 107 | cipher_suite_info->key_size); 108 | 109 | srtp_prf(srtp_encrption_ctx, lable_k_a, &srtp_encrption_ctx->k_a, 110 | srtp_encrption_ctx->cipher_suite_info->hmac_key_len); 111 | 112 | srtp_prf(srtp_encrption_ctx, lable_k_s, &srtp_encrption_ctx->k_s, 113 | cipher_suite_info->salt_key_len); 114 | 115 | printf("----- SRTP KEY DERIVATION ------ \n"); 116 | 117 | printf("authentication key\n"); 118 | print_hex(srtp_encrption_ctx->k_a, 119 | srtp_encrption_ctx->cipher_suite_info->hmac_key_len); 120 | printf("salt key\n"); 121 | print_hex(srtp_encrption_ctx->k_s, 122 | srtp_encrption_ctx->cipher_suite_info->salt_key_len); 123 | printf("encryption key\n"); 124 | print_hex(srtp_encrption_ctx->k_e, 125 | srtp_encrption_ctx->cipher_suite_info->key_size); 126 | 127 | struct AesEnryptionCtx *aes; 128 | init_aes(&aes, srtp_encrption_ctx->k_e, cipher_suite_info->key_size, NULL, 0, 129 | NULL, CM); 130 | 131 | srtp_encrption_ctx->aes = aes; 132 | } 133 | 134 | void init_srtp(struct srtp_ctx **pp_srtp_ctx, 135 | struct encryption_keys *encryption_keys) { 136 | 137 | struct srtp_ctx *srtp_ctx = malloc(sizeof(struct srtp_ctx)); 138 | srtp_ctx->client = calloc(1, sizeof(struct SrtpEncryptionCtx)); 139 | srtp_ctx->server = calloc(1, sizeof(struct SrtpEncryptionCtx)); 140 | 141 | if (encryption_keys->client_write_key) { 142 | srtp_ctx->client->master_salt_key = encryption_keys->client_write_SRTP_salt; 143 | srtp_ctx->client->master_write_key = encryption_keys->client_write_key; 144 | srtp_key_derivation(srtp_ctx->client, encryption_keys->cipher_suite_info); 145 | } 146 | 147 | if (encryption_keys->server_write_key) { 148 | srtp_ctx->server->master_write_key = encryption_keys->server_write_key; 149 | srtp_ctx->server->master_salt_key = encryption_keys->server_write_SRTP_salt; 150 | srtp_key_derivation(srtp_ctx->server, encryption_keys->cipher_suite_info); 151 | } 152 | 153 | srtp_ctx->encrypt_func = &encrypt_aes; 154 | srtp_ctx->decrypt_func = &decrypt_aes; 155 | 156 | *pp_srtp_ctx = srtp_ctx; 157 | } 158 | 159 | void encrypt_srtp(struct SrtpEncryptionCtx *srtp_context, 160 | struct Rtp *rtp_packet, uint32_t *payloadlen) { 161 | 162 | uint64_t index = (0) + ntohs(rtp_packet->seq_no); 163 | 164 | guchar iv[16]; 165 | uint32_t ssrc = ntohl(rtp_packet->ssrc); 166 | 167 | compute_srtp_iv(iv, srtp_context->k_s, 168 | srtp_context->cipher_suite_info->salt_key_len, 169 | (guchar *)&ssrc, (guchar *)&index); 170 | g_debug("iv for encyrption\n"); 171 | srtp_context->aes->IV = iv; 172 | print_hex(iv, 16); 173 | g_debug("salt key \n"); 174 | print_hex(srtp_context->k_s, 14); 175 | g_debug("encypt key \n"); 176 | print_hex(srtp_context->k_e, 16); 177 | 178 | gsize hmac_len = 20; 179 | 180 | guchar computed_mac[hmac_len]; 181 | 182 | g_debug("to ebncrypt\n"); 183 | print_hex(rtp_packet->payload, *payloadlen); 184 | 185 | encrypt_aes(srtp_context->aes, rtp_packet->payload, 0, *payloadlen); 186 | 187 | g_debug("encrypted\n"); 188 | print_hex(rtp_packet->payload, *payloadlen); 189 | 190 | GHmac *srtp_hmac = g_hmac_new(G_CHECKSUM_SHA1, srtp_context->k_a, 191 | srtp_context->cipher_suite_info->hmac_key_len); 192 | g_hmac_update(srtp_hmac, (guchar *)rtp_packet, sizeof(struct Rtp)); 193 | g_hmac_update(srtp_hmac, rtp_packet->payload, *payloadlen); 194 | g_hmac_update(srtp_hmac, (guchar *)&srtp_context->roc, 4); 195 | g_hmac_get_digest(srtp_hmac, computed_mac, &hmac_len); 196 | 197 | g_debug("computed mac\n"); 198 | print_hex(computed_mac, 10); 199 | 200 | memcpy(rtp_packet->payload + (*payloadlen), computed_mac, 201 | srtp_context->cipher_suite_info->hmac_len); 202 | 203 | *payloadlen = srtp_context->cipher_suite_info->hmac_len + (*payloadlen); 204 | 205 | g_hmac_unref(srtp_hmac); 206 | } 207 | -------------------------------------------------------------------------------- /SRTP/srtp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../DTLS/Encryptions/encryption.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define lable_k_e 0x00 9 | #define lable_k_a 0x01 10 | #define lable_k_s 0x02 11 | 12 | struct Rtp; 13 | 14 | struct __attribute__((packed)) srtp_ext { 15 | uint16_t profile_len; 16 | uint16_t encryption_profile; 17 | uint8_t mki_len; 18 | }; 19 | 20 | struct SrtpEncryptionCtx { 21 | uint32_t roc; 22 | uint16_t mki; 23 | guchar *master_salt_key; 24 | guchar *master_write_key; 25 | guchar *k_e; 26 | guchar *k_s; 27 | guchar *k_a; 28 | uint16_t ssrc; 29 | uint64_t index : 48; 30 | uint32_t kdr; 31 | 32 | struct cipher_suite_info *cipher_suite_info; 33 | struct AesEnryptionCtx *aes; 34 | }; 35 | 36 | struct srtp_ext parse_srtp_ext(guchar *value, uint16_t len); 37 | void compute_srtp_iv(guchar *pp_iv, guchar *salting_key, 38 | uint32_t salting_key_len, guchar *ssrc, 39 | guchar *packet_index); 40 | 41 | void srtp_key_derivation(struct SrtpEncryptionCtx *srtp_encrption_ctx, 42 | struct cipher_suite_info *cipher_suite_info); 43 | void init_srtp(struct srtp_ctx **pp_srtp_ctx, 44 | struct encryption_keys *encryption_keys); 45 | 46 | void encrypt_srtp(struct SrtpEncryptionCtx *srtp_context, 47 | struct Rtp *rtp_packet, uint32_t *payloadlen); 48 | -------------------------------------------------------------------------------- /STUN/stun.c: -------------------------------------------------------------------------------- 1 | /* 2 | 0 1 2 3 3 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 4 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 5 | |0 0| STUN Message Type | Message Length | 6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 7 | | Magic Cookie | 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 9 | | | 10 | | Transaction ID (96 bits) | 11 | | | 12 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 13 | | Data | 14 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 15 | */ 16 | #include "./stun.h" 17 | #include "../ICE/ice.h" 18 | #include "../Network/network.h" 19 | #include "glib.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #define STUN_IP "74.125.250.129" 33 | #define STUN_PORT 19302 34 | 35 | #pragma pack(1) 36 | 37 | bool send_stun_bind(struct CandidataPair *pair, int message_class, 38 | struct RTCIecCandidates *sender_candidate, void *data) { 39 | 40 | if (pair != NULL) { 41 | 42 | if (pair->p0 == NULL || pair->p1 == NULL) 43 | return 0; 44 | } 45 | if (pair == NULL && sender_candidate != NULL) { 46 | pair = malloc(sizeof(struct CandidataPair)); 47 | pair->p0 = sender_candidate; 48 | pair->p1 = malloc(sizeof(struct RTCIecCandidates)); 49 | pair->p1->address = STUN_IP; 50 | pair->p1->port = STUN_PORT; 51 | } 52 | 53 | // bind request contains only header for stun server 54 | char *stun_server_ip = STUN_IP; 55 | int stun_server_port = STUN_PORT; 56 | 57 | struct Stun *stun_message = malloc(sizeof(struct Stun) + 200); 58 | stun_message->msg_len = 0; 59 | stun_message->msg_type = htons((STUN_BINDING_METHOD | message_class)); 60 | 61 | stun_message->magic_cookie = htonl(STUN_MAGIC_COOKIE); 62 | socklen_t socklen = sizeof(struct sockaddr_in); 63 | 64 | int sock_desc = pair->p0->sock_desc; 65 | 66 | struct sockaddr_in *srcaddr = pair->p0->src_socket; 67 | 68 | struct sockaddr_in *dest_addr = 69 | get_network_socket(pair->p1->address, pair->p1->port); 70 | char *ice_password; 71 | 72 | if (sender_candidate == NULL && message_class == STUN_REQUEST_CLASS) { 73 | // username:username 74 | ice_password = pair->p1->password; 75 | 76 | char *usernamekeys = 77 | g_strdup_printf("%s:%s", pair->p1->ufrag, pair->p0->ufrag); 78 | strncpy(stun_message->transaction_id, pair->transaction_id, 12); 79 | 80 | add_stun_attribute(stun_message, STUN_ATTRIBUTE_USERNAME, usernamekeys, -1); 81 | 82 | add_stun_attribute(stun_message, STUN_ATTRIBUTE_ICE_CONTROLLING, "adcdfdsa", 83 | -1); 84 | 85 | if (true) { 86 | add_stun_attribute(stun_message, STUN_ATTRIBUTE_USE_CANDIDATE, "", -1); 87 | } 88 | // check here 89 | add_stun_attribute(stun_message, STUN_ATTRIBUTE_PRIORITY, 90 | (guchar *)&pair->p0->priority, sizeof(uint32_t)); 91 | } 92 | 93 | if (message_class == STUN_RESPONSE_CLASS) { 94 | 95 | ice_password = pair->p0->password; 96 | if (data == NULL) { 97 | printf("cannot send binding rsponse data is null\n"); 98 | return false; 99 | } 100 | struct stun_binding *binding = (struct stun_binding *)data; 101 | struct StunPayload *payload = malloc(sizeof(struct StunPayload)); 102 | 103 | strncpy(stun_message->transaction_id, binding->transaction_id, 104 | sizeof(stun_message->transaction_id)); 105 | guchar *payload_str = malloc(sizeof(struct StunPayload)); 106 | 107 | uint16_t mapped_port = htons( 108 | binding->bound_port ^ STUN_MAGIC_COOKIE_MSB); // port and ip is sotred 109 | // xored with the cookie 110 | uint32_t mapped_ip = 111 | htonl(htonl(inet_addr(binding->bound_ip)) ^ STUN_MAGIC_COOKIE); 112 | payload->x_ip = mapped_ip; 113 | payload->reserved = 0x00; 114 | payload->x_port = mapped_port; 115 | payload->family = FAMILY_IPV4; 116 | 117 | memcpy(payload_str, payload, sizeof(struct StunPayload)); 118 | 119 | add_stun_attribute(stun_message, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, 120 | payload_str, sizeof(struct StunPayload)); 121 | } 122 | if (sender_candidate == NULL && (message_class == STUN_RESPONSE_CLASS || 123 | message_class == STUN_REQUEST_CLASS)) { 124 | guchar *stun_message_hmac = generate_HMAC(ice_password, stun_message); 125 | 126 | add_stun_attribute(stun_message, STUN_ATTRIBUTE_MESSAGE_INTIGRITY, 127 | stun_message_hmac, 20); 128 | 129 | uint32_t stun_message_crc32 = 130 | htonl(calculate_crc32(stun_message) ^ 0x5354554e); 131 | add_stun_attribute(stun_message, STUN_ATTRIBUTE_FINGERPRINT, 132 | (guchar *)&stun_message_crc32, 4); 133 | 134 | // exit(0); 135 | } 136 | 137 | int bytes = sendto(sock_desc, stun_message, 138 | sizeof(struct Stun) + ntohs(stun_message->msg_len), 0, 139 | (struct sockaddr *)dest_addr, sizeof(struct sockaddr_in)); 140 | 141 | if (sender_candidate == NULL && (message_class == STUN_RESPONSE_CLASS)) 142 | if (bytes != -1 && bytes != 0) 143 | printf("\nstun Packet sent client : stun://%s:%d with C/S : " 144 | "%s:%d \n", 145 | pair->p0->address, pair->p0->port, pair->p1->address, 146 | pair->p1->port); 147 | else 148 | printf("something went wrong while sending stun \n "); 149 | 150 | free(stun_message); 151 | return true; 152 | } 153 | 154 | guchar *generate_HMAC(const gchar *key, struct Stun *stun_message) { 155 | char *sasl; 156 | int actual_len = ntohs(stun_message->msg_len); 157 | int presumed_len = ntohs(stun_message->msg_len) + 20 + 4; 158 | 159 | // gsasl_saslprep(key, GSASL_ALLOW_UNASSIGNED, &sasl, NULL); 160 | 161 | stun_message->msg_len = htons(presumed_len); 162 | 163 | char *stun_hmac = g_compute_hmac_for_data(G_CHECKSUM_SHA1, (guchar *)key, 164 | strlen(key), (guchar *)stun_message, 165 | actual_len + sizeof(struct Stun)); 166 | 167 | // printf("HMAC HASH ---%s\n", stun_hmac); 168 | // printf("HMAC KEY %s --\n", sasl); 169 | // print_hex(sasl, strlen(sasl)); 170 | // printf("stunmsage len %d --\n", actual_len + sizeof(struct Stun)); 171 | // 172 | // print_hex(stun_message, sizeof(struct Stun) + actual_len); 173 | // 174 | stun_message->msg_len = htons(actual_len); 175 | 176 | guchar *binhmac = hexstr_to_char(stun_hmac); 177 | 178 | // free(sasl); 179 | return binhmac; 180 | } 181 | uint32_t calculate_crc32(struct Stun *stun_message) { 182 | 183 | uLong crc = crc32(0L, Z_NULL, 0); 184 | int actual_len = ntohs(stun_message->msg_len); 185 | int presumed_len = ntohs(stun_message->msg_len) + 4 + 4; 186 | 187 | stun_message->msg_len = htons(presumed_len); 188 | uint32_t stun_message_crc32 = (crc32(crc, (const Bytef *)stun_message, 189 | actual_len + sizeof(struct Stun))); 190 | // printf("\n crc32 %x ", stun_message_crc32); 191 | // print_hex(stun_message, actual_len + sizeof(struct Stun)); 192 | 193 | stun_message->msg_len = htons(actual_len); 194 | return stun_message_crc32; 195 | } 196 | struct TVL *add_stun_attribute(struct Stun *stun, uint16_t type, char *value, 197 | int size) { 198 | uint16_t len = size >= 1 ? size : strlen(value); 199 | int rem = len % 4; 200 | int padding_bytes = rem != 0 ? 4 - rem : 0; 201 | int total_attribute_size = sizeof(struct TVL) + len + padding_bytes; 202 | 203 | struct TVL *tvl_attribute = calloc(1, total_attribute_size); 204 | tvl_attribute->type = htons(type); 205 | tvl_attribute->len = htons(len); 206 | 207 | memcpy(tvl_attribute->value, value, len); 208 | 209 | if (stun != NULL) { 210 | memcpy(stun->data + ntohs(stun->msg_len), tvl_attribute, 211 | total_attribute_size); 212 | } 213 | 214 | stun->msg_len = htons(ntohs(stun->msg_len) + total_attribute_size); 215 | return tvl_attribute; 216 | } 217 | void on_reflexive_candidates(struct RTCPeerConnection *peer, 218 | struct stun_binding *rflx) { 219 | struct RTCIecCandidates *local_ice_candidate = 220 | calloc(1, sizeof(struct RTCIecCandidates)); 221 | 222 | if (rflx != NULL) { 223 | local_ice_candidate->priority = 9; 224 | local_ice_candidate->foundation = 19; 225 | local_ice_candidate->port = rflx->bound_port; 226 | local_ice_candidate->address = rflx->bound_ip; 227 | local_ice_candidate->raddr = rflx->local_ip; 228 | local_ice_candidate->rport = rflx->bound_port; 229 | local_ice_candidate->type = rflx->candidate_type; 230 | local_ice_candidate->component_id = 1; 231 | local_ice_candidate->sdpMid = 0; 232 | local_ice_candidate->transport = "udp"; 233 | 234 | parse_ice_candidate(local_ice_candidate); 235 | add_local_icecandidate(peer, local_ice_candidate); 236 | } 237 | } 238 | 239 | void on_stun_packet(struct NetworkPacket *packet, 240 | struct RTCPeerConnection *peer) { 241 | if (peer == NULL || packet == NULL) 242 | return; 243 | 244 | struct Stun *stun_header = packet->header.stun_header; 245 | struct StunPayload *stun_respose = packet->payload.stun_payload; 246 | 247 | if (packet->subtype == BINDING_RESPONSE) { 248 | struct in_addr ip_add; 249 | ip_add.s_addr = stun_respose->x_ip; 250 | struct stun_binding *stun_binding = malloc(sizeof(struct stun_binding)); 251 | stun_binding->bound_ip = inet_ntoa(ip_add); 252 | stun_binding->bound_port = stun_respose->x_port; 253 | 254 | // on_reflexive_candidates(peer, stun_binding); 255 | if (strcmp(packet->sender_ip, STUN_IP) == 0) { 256 | stun_binding->candidate_type = "srflx"; 257 | printf("\n-----public NAT Mapping is : PORT %d IP , %s %s-----\n", 258 | stun_binding->bound_port, stun_binding->bound_ip, 259 | stun_binding->candidate_type); 260 | // on_reflexive_candidates(peer, stun_binding); 261 | stun_binding->candidate_type = "prflx"; 262 | } else { 263 | for (struct RTCRtpTransceivers *transceiver = peer->transceiver; 264 | transceiver != NULL; transceiver = transceiver->next_trans) { 265 | for (struct CandidataPair *pair = transceiver->pair_checklist; 266 | pair != NULL; pair = pair->next_pair) { 267 | 268 | if (strncmp(pair->transaction_id, stun_header->transaction_id, 12) == 269 | 0) { 270 | printf("ice pair succeeded %s:%d %s:%d \n", pair->p0->address, 271 | pair->p0->port, pair->p1->address, pair->p1->port); 272 | if (peer->dtls_transport->pair == NULL) { 273 | peer->dtls_transport->pair = pair; 274 | start_dtls_negosiation(peer); 275 | } 276 | pair->state = ICE_PAIR_SUCCEEDED; 277 | } 278 | } 279 | } 280 | } 281 | } 282 | 283 | if (packet->subtype == BINDING_REQUEST) { 284 | 285 | if (packet->sender_ip != NULL) { 286 | // checking on only first trans candidate pair for max bundle 287 | struct stun_binding *binding = malloc(sizeof(struct stun_binding)); 288 | binding->bound_port = *packet->sender_port; 289 | binding->bound_ip = packet->sender_ip; 290 | 291 | memcpy(binding->transaction_id, stun_header->transaction_id, 292 | sizeof(stun_header->transaction_id)); 293 | 294 | struct CandidataPair *pair = malloc(sizeof(struct CandidataPair)); 295 | 296 | for (struct RTCIecCandidates *candidate = 297 | peer->transceiver->local_ice_candidate; 298 | candidate != NULL; candidate = candidate->next_candidate) { 299 | if (strcmp(candidate->address, packet->receiver_ip) == 0 && 300 | candidate->port == *packet->receiver_port) { 301 | pair->p0 = candidate; 302 | pair->p1 = malloc(sizeof(struct RTCIecCandidates)); 303 | pair->p1->address = packet->sender_ip; 304 | pair->p1->port = *packet->sender_port; 305 | 306 | send_stun_bind(pair, STUN_RESPONSE_CLASS, NULL, binding); 307 | 308 | free(pair->p1); 309 | free(pair); 310 | break; 311 | } 312 | } 313 | } 314 | } 315 | } 316 | bool check_if_stun(struct Stun *stun_header) { 317 | 318 | stun_header->msg_type = ntohs(stun_header->msg_type); 319 | int zerobits = stun_header->msg_type & 0xC000; // 1100000 320 | 321 | if (zerobits != 0) { 322 | return false; 323 | } 324 | 325 | uint32_t magic_cookie = ntohl(stun_header->magic_cookie); 326 | 327 | if (magic_cookie != STUN_MAGIC_COOKIE) { 328 | return false; 329 | } 330 | 331 | return true; 332 | } 333 | char *get_stun_attributes(struct RTCIecCandidates *local_candidate, 334 | struct RTCIecCandidates *remote_candidate) { 335 | 336 | // struct stun_attribute *username= mall; 337 | // username->type = 0x0006; 338 | // username->length = htons(9); 339 | // strcpy(username.value,"usama:usam1"); 340 | return NULL; 341 | } 342 | -------------------------------------------------------------------------------- /STUN/stun.h: -------------------------------------------------------------------------------- 1 | /* 2 | 0 1 2 3 3 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 4 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 5 | |0 0| STUN Message Type | Message Length | 6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 7 | | Magic Cookie | 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 9 | | | 10 | | Transaction ID (96 bits) | 11 | | | 12 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 13 | | Data | 14 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 15 | */ 16 | /* 17 | 0 1 2 3 18 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 19 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 20 | | Type | Length | 21 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 22 | | Value (variable) .... 23 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 24 | 25 | Figure 4: Format of STUN Attributes 26 | 27 | 28 | 0 1 29 | 2 3 4 5 6 7 8 9 0 1 2 3 4 5 30 | 31 | +--+--+-+-+-+-+-+-+-+-+-+-+-+-+ 32 | |M |M |M|M|M|C|M|M|M|C|M|M|M|M| 33 | |11|10|9|8|7|1|6|5|4|0|3|2|1|0| 34 | +--+--+-+-+-+-+-+-+-+-+-+-+-+-+ 35 | 36 | Figure 3: Format of STUN Message Type Field 37 | 38 | */ 39 | #pragma once 40 | #ifndef _STUNH_ 41 | #define _STUNH_ 42 | 43 | #include "../ICE/ice.h" 44 | #include "glib.h" 45 | #include 46 | #include 47 | struct NetworkPacket; 48 | 49 | #define STUN_MAGIC_COOKIE 0x2112A442 50 | #define STUN_MAGIC_COOKIE_MSB 0x2112 51 | #define STUN_ATTRIBUTE_USERNAME 0x0006 52 | #define STUN_ATTRIBUTE_ICE_CONTROLLING 0x802a 53 | #define STUN_ATTRIBUTE_ICE_CONTROLLED 0x8029 54 | #define STUN_ATTRIBUTE_USE_CANDIDATE 0x0025 55 | #define STUN_ATTRIBUTE_PRIORITY 0x0024 56 | #define STUN_ATTRIBUTE_MESSAGE_INTIGRITY 0x0008 57 | #define STUN_ATTRIBUTE_FINGERPRINT 0x8028 58 | #define STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS 0x0020 59 | 60 | // class request 00 indication 01 success response 10 error 11 61 | // method binding 01 62 | #define STUN_REQUEST_CLASS 0x00 63 | #define STUN_RESPONSE_CLASS 0x100 64 | 65 | #define STUN_BINDING_METHOD 0x001 66 | 67 | #define FAMILY_IPV4 0x01 68 | 69 | struct __attribute__((packed)) Stun { 70 | uint16_t msg_type : 16; 71 | uint16_t msg_len : 16; 72 | uint32_t magic_cookie : 32; 73 | char transaction_id[12]; 74 | // data 75 | char data[]; 76 | }; 77 | 78 | // client binding request 79 | // server icecandidate 80 | 81 | struct __attribute__((packed)) StunPayload { 82 | uint8_t reserved; 83 | uint8_t family; 84 | uint16_t x_port; // ip and are xor mapped with Transaction id 85 | uint32_t x_ip; 86 | }; 87 | struct __attribute__((packed)) TVL { 88 | uint16_t type; 89 | uint16_t len; 90 | char value[]; 91 | }; 92 | struct stun_binding { 93 | char *local_ip; 94 | char *bound_ip; 95 | uint16_t bound_port; 96 | bool is_stun_server; 97 | char *candidate_type; 98 | char transaction_id[12]; 99 | }; 100 | bool send_stun_bind(struct CandidataPair *pair, int message_class, 101 | struct RTCIecCandidates *sender_candidate, void *data); 102 | 103 | struct TVL *add_stun_attribute(struct Stun *stun, uint16_t type, char *value, 104 | int size); 105 | 106 | guchar *generate_HMAC(const gchar *key, struct Stun *message); 107 | void on_reflexive_candidates(struct RTCPeerConnection *peer, 108 | struct stun_binding *rflx); 109 | 110 | guchar *hexstr_to_char(const char *hexstr); 111 | 112 | void on_stun_packet(struct NetworkPacket *packet, 113 | struct RTCPeerConnection *peer); 114 | 115 | uint32_t calculate_crc32(struct Stun *stun_message); 116 | 117 | bool check_if_stun(struct Stun *stun_header); 118 | #endif // !_STUNH_ 119 | -------------------------------------------------------------------------------- /SignallingClient/signalling_client.c: -------------------------------------------------------------------------------- 1 | #include "signalling_client.h" 2 | #include "libsoup/soup-types.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | extern void on_websocket_connected(SoupWebsocketConnection *conn); 12 | extern void on_websocket_disconnected(SoupWebsocketConnection *conn); 13 | extern void on_start(JsonObject *object); 14 | extern void on_remote_ice_candidate(JsonObject *object, 15 | const gchar *webrtcbin_id); 16 | extern void on_remote_description(JsonObject *jsonobject, const gchar *type, 17 | const gchar *webrtcbin_id); 18 | 19 | static void on_message(SoupWebsocketConnection *conn, gint type, 20 | GBytes *message, gpointer data) { 21 | printf("message\n"); 22 | if (type == SOUP_WEBSOCKET_DATA_TEXT) { 23 | gsize sz; 24 | const gchar *ptr; 25 | ptr = g_bytes_get_data(message, &sz); 26 | 27 | g_print("Received : %s\n", ptr); 28 | 29 | JsonParser *json_parser = json_parser_new(); 30 | JsonNode *root; 31 | JsonObject *object; 32 | gboolean is_parsed = json_parser_load_from_data(json_parser, ptr, -1, NULL); 33 | if (!is_parsed) 34 | return; 35 | 36 | root = json_parser_get_root(json_parser); 37 | object = json_node_get_object(root); 38 | const char *peerid = json_object_get_string_member(object, "peer"); 39 | const gchar *command = json_object_get_string_member(object, "command"); 40 | 41 | if (strcmp(command, "start") == 0) { 42 | on_start(object); 43 | } else if (strcmp(command, "answer") == 0 || 44 | strcmp(command, "offer") == 0) { 45 | on_remote_description(json_object_get_object_member(object, command), 46 | command, peerid); 47 | } else if (strcmp(command, "candidate") == 0) { 48 | on_remote_ice_candidate( 49 | json_object_get_object_member(object, "candidate"), peerid); 50 | } 51 | } 52 | } 53 | 54 | static void on_close(SoupWebsocketConnection *conn, gpointer data) { 55 | soup_websocket_connection_close(conn, SOUP_WEBSOCKET_CLOSE_NORMAL, NULL); 56 | on_websocket_disconnected(conn); 57 | g_print("WebSocket connection closed\n"); 58 | } 59 | 60 | static void on_connection(SoupSession *session, GAsyncResult *res, 61 | gpointer data) { 62 | 63 | SoupWebsocketConnection *conn; 64 | GError *error = NULL; 65 | 66 | conn = soup_session_websocket_connect_finish(session, res, &error); 67 | if (error) { 68 | g_print("Error: %s\n", error->message); 69 | g_error_free(error); 70 | return; 71 | } 72 | g_signal_connect(conn, "message", G_CALLBACK(on_message), NULL); 73 | g_signal_connect(conn, "closed", G_CALLBACK(on_close), NULL); 74 | on_websocket_connected(conn); 75 | printf("websocket connectet\n"); 76 | } 77 | 78 | void websocket_connect(char *ip, int port) { 79 | 80 | gchar *uri = NULL; 81 | SoupMessage *msg; 82 | SoupSession *session; 83 | session = soup_session_new(); 84 | uri = g_strdup_printf("%s://%s:%d", "ws", ip, port); 85 | msg = soup_message_new(SOUP_METHOD_GET, uri); 86 | g_free(uri); 87 | 88 | soup_session_websocket_connect_async( 89 | session, msg, NULL, NULL, NULL, (GAsyncReadyCallback)on_connection, NULL); 90 | } 91 | -------------------------------------------------------------------------------- /SignallingClient/signalling_client.h: -------------------------------------------------------------------------------- 1 | void websocket_connect(char *ip, int port); 2 | -------------------------------------------------------------------------------- /SignallingServer/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "signallingserver", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "signallingserver", 9 | "version": "1.0.0", 10 | "license": "GPL-3.0", 11 | "dependencies": { 12 | "websocket": "^1.0.35" 13 | } 14 | }, 15 | "node_modules/bufferutil": { 16 | "version": "4.0.8", 17 | "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", 18 | "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", 19 | "hasInstallScript": true, 20 | "dependencies": { 21 | "node-gyp-build": "^4.3.0" 22 | }, 23 | "engines": { 24 | "node": ">=6.14.2" 25 | } 26 | }, 27 | "node_modules/d": { 28 | "version": "1.0.2", 29 | "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", 30 | "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", 31 | "dependencies": { 32 | "es5-ext": "^0.10.64", 33 | "type": "^2.7.2" 34 | }, 35 | "engines": { 36 | "node": ">=0.12" 37 | } 38 | }, 39 | "node_modules/debug": { 40 | "version": "2.6.9", 41 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 42 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 43 | "dependencies": { 44 | "ms": "2.0.0" 45 | } 46 | }, 47 | "node_modules/es5-ext": { 48 | "version": "0.10.64", 49 | "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", 50 | "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", 51 | "hasInstallScript": true, 52 | "dependencies": { 53 | "es6-iterator": "^2.0.3", 54 | "es6-symbol": "^3.1.3", 55 | "esniff": "^2.0.1", 56 | "next-tick": "^1.1.0" 57 | }, 58 | "engines": { 59 | "node": ">=0.10" 60 | } 61 | }, 62 | "node_modules/es6-iterator": { 63 | "version": "2.0.3", 64 | "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", 65 | "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", 66 | "dependencies": { 67 | "d": "1", 68 | "es5-ext": "^0.10.35", 69 | "es6-symbol": "^3.1.1" 70 | } 71 | }, 72 | "node_modules/es6-symbol": { 73 | "version": "3.1.4", 74 | "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", 75 | "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", 76 | "dependencies": { 77 | "d": "^1.0.2", 78 | "ext": "^1.7.0" 79 | }, 80 | "engines": { 81 | "node": ">=0.12" 82 | } 83 | }, 84 | "node_modules/esniff": { 85 | "version": "2.0.1", 86 | "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", 87 | "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", 88 | "dependencies": { 89 | "d": "^1.0.1", 90 | "es5-ext": "^0.10.62", 91 | "event-emitter": "^0.3.5", 92 | "type": "^2.7.2" 93 | }, 94 | "engines": { 95 | "node": ">=0.10" 96 | } 97 | }, 98 | "node_modules/event-emitter": { 99 | "version": "0.3.5", 100 | "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", 101 | "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", 102 | "dependencies": { 103 | "d": "1", 104 | "es5-ext": "~0.10.14" 105 | } 106 | }, 107 | "node_modules/ext": { 108 | "version": "1.7.0", 109 | "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", 110 | "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", 111 | "dependencies": { 112 | "type": "^2.7.2" 113 | } 114 | }, 115 | "node_modules/is-typedarray": { 116 | "version": "1.0.0", 117 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 118 | "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" 119 | }, 120 | "node_modules/ms": { 121 | "version": "2.0.0", 122 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 123 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 124 | }, 125 | "node_modules/next-tick": { 126 | "version": "1.1.0", 127 | "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", 128 | "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" 129 | }, 130 | "node_modules/node-gyp-build": { 131 | "version": "4.8.1", 132 | "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", 133 | "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", 134 | "bin": { 135 | "node-gyp-build": "bin.js", 136 | "node-gyp-build-optional": "optional.js", 137 | "node-gyp-build-test": "build-test.js" 138 | } 139 | }, 140 | "node_modules/type": { 141 | "version": "2.7.3", 142 | "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", 143 | "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==" 144 | }, 145 | "node_modules/typedarray-to-buffer": { 146 | "version": "3.1.5", 147 | "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", 148 | "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", 149 | "dependencies": { 150 | "is-typedarray": "^1.0.0" 151 | } 152 | }, 153 | "node_modules/utf-8-validate": { 154 | "version": "5.0.10", 155 | "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", 156 | "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", 157 | "hasInstallScript": true, 158 | "dependencies": { 159 | "node-gyp-build": "^4.3.0" 160 | }, 161 | "engines": { 162 | "node": ">=6.14.2" 163 | } 164 | }, 165 | "node_modules/websocket": { 166 | "version": "1.0.35", 167 | "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.35.tgz", 168 | "integrity": "sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q==", 169 | "dependencies": { 170 | "bufferutil": "^4.0.1", 171 | "debug": "^2.2.0", 172 | "es5-ext": "^0.10.63", 173 | "typedarray-to-buffer": "^3.1.5", 174 | "utf-8-validate": "^5.0.2", 175 | "yaeti": "^0.0.6" 176 | }, 177 | "engines": { 178 | "node": ">=4.0.0" 179 | } 180 | }, 181 | "node_modules/yaeti": { 182 | "version": "0.0.6", 183 | "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", 184 | "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", 185 | "engines": { 186 | "node": ">=0.10.32" 187 | } 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /SignallingServer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "signallingserver", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "signallingServer.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "npx nodemon ./signallingServer.js" 9 | }, 10 | "author": "usamawizard", 11 | "license": "GPL-3.0", 12 | "dependencies": { 13 | "websocket": "^1.0.35" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /SignallingServer/signallingServer.js: -------------------------------------------------------------------------------- 1 | var WebSocketServer = require('websocket').server; 2 | var http = require('http'); 3 | 4 | var socket_id_map = new Map(); 5 | 6 | var last_joined_id = null; 7 | var server = http.createServer(function(request, response) { 8 | response.writeHead(404); 9 | response.end(); 10 | }); 11 | 12 | server.listen(3001, function() { 13 | console.log('Signalling Server is listening on port 3001'); 14 | }); 15 | 16 | wsServer = new WebSocketServer({ 17 | httpServer: server, 18 | }); 19 | 20 | wsServer.getUniqueID = function() { 21 | function s4() { 22 | return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); 23 | } 24 | return s4() + s4() + '-' + s4(); 25 | }; 26 | 27 | wsServer.on('request', function(wsrequest) { 28 | // console.log(wsrequest); 29 | var connection = wsrequest.accept("",wsrequest.origin); 30 | 31 | var socket_id = wsServer.getUniqueID(); 32 | connection.id = socket_id; 33 | socket_id_map.set(socket_id, connection); 34 | 35 | console.log(connection.id); 36 | if (last_joined_id != null) { 37 | last_ws_connection = socket_id_map.get(last_joined_id); 38 | if (last_ws_connection != null && last_ws_connection) { 39 | connection.send(JSON.stringify({ "command": "start", "peer": last_joined_id })); 40 | last_ws_connection.send(JSON.stringify({ "command": "start", "peer": socket_id })); 41 | } 42 | last_joined_id = null; 43 | } 44 | else { 45 | last_joined_id = socket_id; 46 | } 47 | 48 | connection.on('message', function(message) { 49 | if (message.type != 'utf8') 50 | return; 51 | 52 | var message = JSON.parse(message.utf8Data); 53 | peer_pair = socket_id_map.get(message.peer); 54 | if (peer_pair != undefined) { 55 | console.log("send to ", message.peer,message); 56 | peer_pair.send(JSON.stringify(message)); 57 | } 58 | else { 59 | console.log("peer no longer active"); 60 | } 61 | }); 62 | 63 | connection.on('close', function(reasonCode, description) { 64 | console.log( ' Peer ' + connection.remoteAddress + ' disconnected.'); 65 | if (connection.id == last_joined_id) { 66 | last_joined_id = null; 67 | } 68 | 69 | socket_id_map.delete(connection.id) 70 | }); 71 | 72 | }); 73 | -------------------------------------------------------------------------------- /Utils/utils.c: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | static gchar *get_string_from_json_object(JsonObject *object) { 15 | JsonNode *root; 16 | JsonGenerator *generator; 17 | gchar *text; 18 | /* Make it the root node */ 19 | root = json_node_init_object(json_node_alloc(), object); 20 | generator = json_generator_new(); 21 | json_generator_set_root(generator, root); 22 | text = json_generator_to_data(generator, NULL); 23 | 24 | /* Release everything */ 25 | g_object_unref(generator); 26 | json_node_free(root); 27 | return text; 28 | } 29 | int strcicmp(char const *a, char const *b) { 30 | for (;; a++, b++) { 31 | int d = tolower((unsigned char)*a) - tolower((unsigned char)*b); 32 | if (d != 0 || !*a) 33 | return d; 34 | } 35 | } 36 | 37 | void get_random_string(gchar **data_pointer, uint32_t length, uint8_t type) { 38 | guchar *random_data; 39 | 40 | random_data = malloc(length); 41 | 42 | int f_random = open("/dev/random", O_RDONLY); 43 | 44 | read(f_random, random_data, length); 45 | 46 | for (int i = 0; i < length; i++) { 47 | int temp = random_data[i]; 48 | if (type == RANDOM_NUMBER_STRING) 49 | random_data[i] = random_data[i] % (57 - 48 + 1) + 48; 50 | 51 | else if (type == RANDOM_CHAR_STRING) { 52 | if (random_data[i] == 0) 53 | random_data[i] = random_data[i] + 10; 54 | } 55 | } 56 | 57 | *data_pointer = (gchar *)random_data; 58 | 59 | close(f_random); 60 | } 61 | guchar *hexstr_to_char(const char *hexstr) { 62 | size_t len = strlen(hexstr); 63 | if (len % 2 != 0) 64 | return NULL; 65 | size_t final_len = len / 2; 66 | guchar *chrs = (unsigned char *)malloc((final_len + 1) * sizeof(*chrs)); 67 | for (size_t i = 0, j = 0; j < final_len; i += 2, j++) 68 | chrs[j] = (hexstr[i] % 32 + 9) % 25 * 16 + (hexstr[i + 1] % 32 + 9) % 25; 69 | 70 | chrs[final_len] = '\0'; 71 | return chrs; 72 | } 73 | void print_aes_matrix2(uint8_t (*ptr)[4], uint8_t numrow) { 74 | printf("\n\n"); 75 | 76 | for (int i = 0; i < numrow; i++) { 77 | for (int j = 0; j < numrow; j++) { 78 | printf(" %x ", ptr[i][j]); 79 | } 80 | printf("\n"); 81 | } 82 | } 83 | void print_aes_matrix(uint8_t (*ptr)[4], uint8_t numrow) { 84 | return; 85 | printf("\n\n"); 86 | 87 | for (int i = 0; i < numrow; i++) { 88 | for (int j = 0; j < numrow; j++) { 89 | printf(" %x ", ptr[i][j]); 90 | } 91 | printf("\n"); 92 | } 93 | } 94 | void increment_binary_number(unsigned char *number, size_t length) { 95 | int carry = 1; 96 | 97 | for (int i = length - 1; i >= 0; i--) { 98 | unsigned int result = number[i] + carry; 99 | 100 | if (result > 0xFF) { 101 | number[i] = 0x00; 102 | } else { 103 | number[i] = (unsigned char)result; 104 | carry = 0; 105 | break; 106 | } 107 | } 108 | 109 | print_aes_matrix2(number, 4); 110 | } 111 | 112 | void print_hex(const unsigned char *data, size_t length) { 113 | for (size_t i = 0; i < length; i++) { 114 | printf("%02x ", data[i]); 115 | } 116 | printf("\n"); 117 | } 118 | 119 | uint32_t hexstr_to_char_2(guchar **p_str, gchar *str) { 120 | BIGNUM *bignum = BN_new(); 121 | BN_hex2bn(&bignum, str); 122 | uint32_t byte_required = BN_num_bytes(bignum); 123 | guchar *converted_str = malloc(byte_required); 124 | BN_bn2bin(bignum, converted_str); 125 | *p_str = converted_str; 126 | 127 | return byte_required; 128 | } 129 | 130 | bool copy_key_block(guchar *key_block, ...) { 131 | 132 | va_list arg_list; 133 | va_start(arg_list, key_block); 134 | 135 | guchar **data_ptr; 136 | 137 | while ((data_ptr = va_arg(arg_list, guchar **)) != NULL) { 138 | 139 | int size = va_arg(arg_list, int); 140 | memcpy(*data_ptr, key_block, size); 141 | key_block += size; 142 | } 143 | va_end(arg_list); 144 | return true; 145 | } 146 | 147 | void increment_counter(unsigned char (*number)[4]) { 148 | 149 | guchar char_num[2]; 150 | char_num[0] = number[2][3]; 151 | char_num[1] = number[3][3]; 152 | 153 | int carry = 1; 154 | 155 | for (int i = 2 - 1; i >= 0; i--) { 156 | unsigned int result = char_num[i] + carry; 157 | 158 | if (result > 0xFF) { 159 | char_num[i] = 0x00; 160 | } else { 161 | char_num[i] = (unsigned char)result; 162 | carry = 0; 163 | break; 164 | } 165 | } 166 | 167 | number[2][3] = char_num[0]; 168 | number[3][3] = char_num[1]; 169 | } 170 | -------------------------------------------------------------------------------- /Utils/utils.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | enum random { 6 | RANDOM_NUMBER_STRING, 7 | RANDOM_CHAR_STRING, 8 | RANDOM_BIN, 9 | }; 10 | 11 | static gchar *get_string_from_json_object(JsonObject *object); 12 | int strcicmp(char const *a, char const *b); 13 | void get_random_string(gchar **data_pointer, uint32_t length, uint8_t type); 14 | 15 | guchar *hexstr_to_char(const char *hexstr); 16 | void print_hex(const unsigned char *data, size_t length); 17 | uint32_t hexstr_to_char_2(guchar **p_str, gchar *str); 18 | void print_aes_matrix(uint8_t (*ptr)[4], uint8_t numrow); 19 | 20 | bool copy_key_block(guchar *key_block, ...); 21 | void increment_binary_number(unsigned char *number, size_t length); 22 | 23 | void increment_counter(unsigned char (*number)[4]); 24 | void print_aes_matrix2(uint8_t (*ptr)[4], uint8_t numrow); 25 | -------------------------------------------------------------------------------- /WebRTC/webrtc.c: -------------------------------------------------------------------------------- 1 | #include "./webrtc.h" 2 | #include "../DTLS/dtls.h" 3 | #include "../ICE/ice.h" 4 | #include "../Network/network.h" 5 | #include "../SDP/sdp.h" 6 | #include "glib-object.h" 7 | #include "glib.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | struct RTCPeerConnection *NEW_RTCPeerConnection() { 15 | struct RTCPeerConnection *peer = 16 | (struct RTCPeerConnection *)calloc(1, sizeof(struct RTCPeerConnection)); 17 | peer->signalling_state = STABLE; 18 | peer->dtls_transport = create_dtls_transport(); 19 | if (peer == NULL) { 20 | perror("Failed to allocate memory for RTCPeerConnection"); 21 | return NULL; 22 | } 23 | return peer; 24 | } 25 | 26 | struct MediaStreamTrack *NEW_MediaTrack(char *kind, char *label, 27 | void *get_data_callback, 28 | void *userdata) { 29 | struct MediaStreamTrack *track = 30 | (struct MediaStreamTrack *)malloc(sizeof(struct MediaStreamTrack)); 31 | track->get_data_callback = get_data_callback; 32 | track->kind = kind; 33 | track->label = label; 34 | track->next_track = NULL; 35 | track->id = "random trackid"; 36 | track->userdata = userdata; 37 | return track; 38 | } 39 | 40 | bool add_track(struct RTCPeerConnection *peer, struct MediaStreamTrack *track) { 41 | if (peer->media_tracks == NULL) { 42 | peer->media_tracks = track; 43 | printf("New Track Added to WebRTC Session id:%s Kind: %s Label: %s\n", 44 | track->id, track->kind, track->label); 45 | track->rtp_stream = create_rtp_stream(NULL, track, 0xdeadbeef, 102); 46 | 47 | add_transceivers(peer, peer->media_tracks); 48 | } else { 49 | peer->media_tracks->next_track = track; 50 | } 51 | return true; 52 | } 53 | 54 | struct RTCRtpTransceivers *add_transceivers(struct RTCPeerConnection *peer, 55 | struct MediaStreamTrack *track) { 56 | struct RTCRtpTransceivers *transceiver = peer->transceiver; 57 | if (transceiver != NULL) 58 | for (; transceiver->next_trans != NULL; 59 | transceiver = transceiver->next_trans) 60 | ; 61 | 62 | struct RTCRtpTransceivers *new_transceiver = 63 | calloc(1, sizeof(struct RTCRtpTransceivers)); 64 | new_transceiver->mid = transceiver != NULL ? transceiver->mid + 1 : 0; 65 | new_transceiver->direction = SEND_RECV; 66 | new_transceiver->next_trans = NULL; 67 | 68 | struct Transport *sender = calloc(1, sizeof(struct Transport)); 69 | sender->track = track; 70 | sender->state = TRANSPORT_STATE_NEW; 71 | new_transceiver->sender = sender; 72 | 73 | if (peer->transceiver == NULL) { 74 | peer->transceiver = new_transceiver; 75 | } else { 76 | transceiver->next_trans = new_transceiver; 77 | } 78 | 79 | return transceiver; 80 | } 81 | 82 | struct RTCSessionDescription *create_offer(struct RTCPeerConnection *peer) { 83 | struct RTCRtpTransceivers *transceiver = peer->transceiver; 84 | peer->ice_role = ICE_AGENT_CONTROLLING; 85 | 86 | char *offer_constants = get_sdp_constants(); 87 | printf("%s", offer_constants); 88 | char *transceiver_sdp = ""; 89 | if (peer->current_remote_desc != NULL) { 90 | // generate a maching description 91 | // 92 | } else { 93 | if (peer->transceiver != NULL) { 94 | transceiver_sdp = generate_unmached_desc(peer->transceiver); 95 | } 96 | } 97 | 98 | return NULL; 99 | } 100 | 101 | struct RTCSessionDescription * 102 | create_answer(struct RTCSessionDescription *peer) { 103 | 104 | return NULL; 105 | } 106 | void set_local_description(struct RTCPeerConnection *peer, 107 | struct RTCSessionDescription *sdp) { 108 | // icreated the offer 109 | // imporove spegetti 110 | if (peer == NULL || sdp == NULL) 111 | return; 112 | 113 | bool is_offer = strncmp(sdp->type, SDP_TYPE_OFFER, 4) == 0; 114 | bool is_answer = strncmp(sdp->type, SDP_TYPE_ANSWER, 5) == 0; 115 | if ((is_offer && peer->signalling_state == HAVE_REMOTE_OFFER) || 116 | (is_answer && peer->signalling_state == HAVE_REMOTE_ANSWER)) { 117 | printf("set local desc called in wrong state"); 118 | return; 119 | } 120 | 121 | if (is_offer) { 122 | peer->signalling_state = HAVE_LOCAL_OFFER; 123 | } else if (is_answer) { 124 | peer->signalling_state = HAVE_LOCAL_ANSWER; 125 | } 126 | peer->current_local_desc = sdp; 127 | 128 | gather_ice_candidate(peer); 129 | } 130 | bool set_remote_discription(struct RTCPeerConnection *peer, 131 | struct RTCSessionDescription *sdp) { 132 | 133 | if (peer == NULL || peer->transceiver == NULL) { 134 | printf("set remote description failed not a valid state :\n"); 135 | return false; 136 | } 137 | // if its answer then I should be in have local offer state 138 | // imporve this spegetti 139 | // 140 | if ((strncmp(sdp->type, SDP_TYPE_ANSWER, 6) == 0 && 141 | peer->signalling_state == HAVE_LOCAL_OFFER) || 142 | (strncmp(sdp->type, SDP_TYPE_OFFER, 4) == 0 && 143 | (peer->signalling_state == STABLE || 144 | peer->signalling_state == HAVE_LOCAL_OFFER))) { 145 | 146 | parse_sdp_string(peer, sdp); 147 | } else { 148 | printf("set remote description called in wrong state: %d\n", 149 | peer->signalling_state); 150 | return false; 151 | } 152 | peer->current_remote_desc = sdp; 153 | g_timeout_add_full(G_PRIORITY_HIGH, 499, (GSourceFunc)do_ice_handshake, peer, 154 | (GDestroyNotify)ice_handshake_ended); 155 | return true; 156 | } 157 | // remote ice 158 | void add_ice_candidate(struct RTCPeerConnection *peer, 159 | struct RTCIecCandidates *candidate) { 160 | 161 | if (candidate == NULL) { 162 | // signal remote ice gathering compleated 163 | return; 164 | } 165 | 166 | if (!parse_ice_candidate(candidate)) { 167 | printf("failed to parse remote ice "); 168 | return; 169 | } 170 | 171 | candidate->src_socket = 172 | get_network_socket(candidate->address, candidate->port); 173 | struct RTCRtpTransceivers *transceiver = 174 | get_transceiver(peer->transceiver, candidate->sdpMid); 175 | 176 | printf("\n----------added remote candidate %s://%s:%d-------------\n", 177 | candidate->transport, candidate->address, candidate->port); 178 | if (transceiver == NULL) 179 | return; 180 | 181 | if (transceiver->remote_ice_candidate == NULL) { 182 | transceiver->remote_ice_candidate = candidate; 183 | } else { 184 | struct RTCIecCandidates *lastcandidate = transceiver->remote_ice_candidate; 185 | 186 | for (; lastcandidate->next_candidate != NULL; 187 | lastcandidate = lastcandidate->next_candidate) 188 | ; 189 | lastcandidate->next_candidate = candidate; 190 | } 191 | struct args *arg = malloc(sizeof(struct args)); 192 | arg->transceiver = transceiver; 193 | arg->candidate = candidate; 194 | 195 | g_timeout_add_full(G_PRIORITY_HIGH, 499, (GSourceFunc)make_candidate_pair, 196 | arg, (GDestroyNotify)ice_handshake_ended); 197 | } 198 | -------------------------------------------------------------------------------- /WebRTC/webrtc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef _WEBRTCH_ 3 | #define _WEBRTCH_ 4 | 5 | #include "../DTLS/dtls.h" 6 | #include "../SDP/sdp.h" 7 | #include 8 | #include 9 | #include 10 | 11 | #define SEND_ONLY "sendonly" 12 | #define RECV_ONLY "recvonly" 13 | #define SEND_RECV "sendrecv" 14 | 15 | #define BUNDLE_MAX_BUNDLE 1 16 | #define BUNDLE_MAC_COMPAT 2 17 | #define BUNDEL_BALANCED 3 18 | 19 | enum RTC_CONNECTION_STATE { 20 | PEER_CONNECTION_NEW, 21 | PEER_CONNECTION_CONNECTING, 22 | PEER_CONNECTED, 23 | PEER_DISCONNECTED, 24 | PEER_CLOSED 25 | }; 26 | enum RTC_SIGNALLING_STATE { 27 | STABLE, 28 | HAVE_LOCAL_OFFER, 29 | HAVE_LOCAL_ANSWER, 30 | HAVE_REMOTE_OFFER, 31 | HAVE_REMOTE_ANSWER 32 | }; 33 | 34 | struct RTCPeerConnection { 35 | char *connection_state; 36 | pthread_t *listener_thread_id; 37 | struct RTCSessionDescription *current_local_desc; 38 | struct RTCSessionDescription *current_remote_desc; 39 | struct ParsedRemoteDescription *parsed_remote_desc; 40 | char *ice_connection_state; 41 | enum RTC_SIGNALLING_STATE signalling_state; 42 | struct MediaStreamTrack *media_tracks; 43 | struct RTCRtpTransceivers *transceiver; 44 | void *on_ice_candidate; 45 | char *ice_role; 46 | bool local_gathering_compleated; 47 | bool remote_gathering_compleated; 48 | int bundle_policy; 49 | struct RTCDtlsTransport *dtls_transport; 50 | }; 51 | 52 | struct MediaStreamTrack { 53 | char *kind; 54 | char *label; 55 | bool muted; 56 | void *get_data_callback; 57 | void *userdata; 58 | char *id; 59 | char *file_name; 60 | char *msid; 61 | struct MediaStreamTrack *next_track; 62 | struct RtpStream *rtp_stream; 63 | }; 64 | 65 | struct Transport { 66 | struct MediaStreamTrack *track; 67 | char *state; 68 | }; 69 | 70 | struct RTCRtpTransceivers { 71 | struct RTCIecCandidates *local_ice_candidate; 72 | struct RTCIecCandidates *remote_ice_candidate; 73 | struct CandidataPair *pair_checklist; 74 | char *currentDirection; 75 | char *direction; 76 | int mid; 77 | struct Transport *sender; 78 | struct Transport *recvier; 79 | char *local_ice_ufrag; 80 | char *remote_ice_ufrag; 81 | char *local_ice_password; 82 | char *remote_ice_password; 83 | bool stoped; 84 | bool handshake_sending_started; 85 | struct RTCRtpTransceivers *next_trans; 86 | }; 87 | 88 | struct args { 89 | struct RTCRtpTransceivers *transceiver; 90 | struct RTCIecCandidates *candidate; 91 | }; 92 | 93 | struct RTCPeerConnection *NEW_RTCPeerConnection(); 94 | 95 | bool add_track(struct RTCPeerConnection *peer, struct MediaStreamTrack *track); 96 | 97 | struct RTCSessionDescription *create_offer(struct RTCPeerConnection *peer); 98 | struct MediaStreamTrack *NEW_MediaTrack(char *kind, char *label, 99 | void *get_data_callback, 100 | void *userdata); 101 | struct RTCRtpTransceivers *add_transceivers(struct RTCPeerConnection *peer, 102 | struct MediaStreamTrack *track); 103 | 104 | void set_local_description(struct RTCPeerConnection *peer, 105 | struct RTCSessionDescription *sdp); 106 | bool set_remote_discription(struct RTCPeerConnection *peer, 107 | struct RTCSessionDescription *sdp); 108 | 109 | void add_ice_candidate(struct RTCPeerConnection *peer, 110 | struct RTCIecCandidates *candidate); 111 | struct MediaStreamTrack *NEW_MediaTrack(char *kind, char *label, 112 | void *get_data_callback, 113 | void *userdata); 114 | #endif 115 | -------------------------------------------------------------------------------- /WebRTC_Browser_APP/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webrtc_browser_app", 3 | "version": "1.0.0", 4 | "description": "a basic application to make a peer to peer webrtc session", 5 | "main": "serv.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node ./serv.js" 9 | }, 10 | "keywords": [ 11 | "webrtc", 12 | "p2p", 13 | "minimal" 14 | ], 15 | "author": "usamawizard", 16 | "license": "GPL-3.0", 17 | "dependencies": { 18 | "express": "^4.19.2" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /WebRTC_Browser_APP/public/peer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | peer 9 | 10 | 11 |

WEBRTC PEER TO PEER

12 |

13 | this is a basic test page which only supports two peers a time for qucikly testing the webrtc library 14 | 15 | simply open the page on two diffrent browser pages or run the native client and browser page and webrtc connection will be establisished between both the client 16 | 17 | one way communication one client will send and other will recive 18 | 19 |

20 |

21 |

22 | 24 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /WebRTC_Browser_APP/public/signalling_client.js: -------------------------------------------------------------------------------- 1 | var websocket = new WebSocket("ws://192.168.0.115:3001"); 2 | var myid = null; 3 | var peer; 4 | websocket.onopen = () => { 5 | console.log("websocket connection open "); 6 | } 7 | websocket.onclose = () => { 8 | console.log("websocket connection close "); 9 | } 10 | function is_sender_mode(mode) { 11 | return mode.includes("send") 12 | } 13 | websocket.onmessage = async (message) => { 14 | message = JSON.parse(message.data); 15 | switch (message.command) { 16 | case "start": 17 | console.log("start") 18 | myid = message.peer; 19 | if (is_sender_mode(mode)) { 20 | await add_media(); 21 | //await add_media(); 22 | send_offer(); 23 | } 24 | //else 25 | // await add_media(); 26 | //await add_media("audio"); 27 | break; 28 | case "offer": 29 | console.log("recived offer +", message.offer); 30 | peer.setRemoteDescription(message.offer).then(() => { 31 | send_answer(); 32 | }); 33 | break; 34 | case "answer": 35 | console.log("recived answer :" + message.answer.sdp); 36 | await peer.setRemoteDescription(message.answer); 37 | break; 38 | case "candidate": 39 | if (message.candidate != null) 40 | console.log("recived ice candidate \n"); 41 | console.log(message.candidate); 42 | await peer.addIceCandidate(message.candidate); 43 | } 44 | } 45 | 46 | (async () => { 47 | 48 | peer = new RTCPeerConnection({ 49 | bundlePolicy: "max-bundle", 50 | iceServers: [ 51 | { 52 | urls: "stun:stun.l.google.com:19302" 53 | } 54 | ] 55 | } 56 | ); 57 | peer.onsignalingstatechange = (e) => { 58 | //console.log(e); 59 | } 60 | peer.onicecandidate = (({ candidate }) => { 61 | if (candidate != null) 62 | console.log(candidate); 63 | websocket.send(JSON.stringify({ "command": "candidate", "candidate": candidate, "peer": myid })); 64 | }); 65 | peer.ontrack = (media_track) => { 66 | let track = media_track.track; 67 | console.log("new track added of kind", track.kind, track.id); 68 | let media_stream = new MediaStream([track]); 69 | setVideo(media_stream); 70 | } 71 | })(); 72 | 73 | async function add_media(type) { 74 | if (type == "video" || type == undefined || type == null) { 75 | media = await navigator.mediaDevices.getUserMedia({ video: true }); 76 | setVideo(media); 77 | peer.addTrack(media.getVideoTracks()[0]); 78 | return; 79 | } 80 | else if (type == "audio") { 81 | media = await navigator.mediaDevices.getUserMedia({ audio: true }); 82 | peer.addTrack(media.getAudioTracks()[0]); 83 | console.warn("audio aded"); 84 | return; 85 | } 86 | 87 | //stream1 = media.getVideoTracks()[0].clone(); 88 | //peer.addTrack(stream1); 89 | 90 | } 91 | function send_offer() { 92 | peer.createOffer().then(async (localdesc) => { 93 | console.log("create and send offer " + localdesc.sdp); 94 | peer.setLocalDescription(localdesc).then(() => { 95 | websocket.send(JSON.stringify({ "command": "offer", "offer": localdesc, "peer": myid })); 96 | }); 97 | }); 98 | } 99 | function send_answer() { 100 | peer.createAnswer().then(async (answer) => { 101 | console.log(" create and send answer : " + answer.sdp); 102 | await peer.setLocalDescription(answer).then(() => { 103 | websocket.send(JSON.stringify({ "command": "answer", "answer": answer, "peer": myid })); 104 | }) 105 | }); 106 | } 107 | function setVideo(video_stream) { 108 | let video_player = document.getElementById("video_player"); 109 | video_player.srcObject = video_stream; 110 | video_player.play(); 111 | } 112 | -------------------------------------------------------------------------------- /WebRTC_Browser_APP/serv.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const path = require('path'); 3 | 4 | const app = express(); 5 | const PORT = process.env.PORT || 3000; 6 | 7 | // Serve static files from the 'public' directory 8 | app.use(express.static(path.join(__dirname, 'public'))); 9 | 10 | // Start the server 11 | app.listen(PORT, () => { 12 | console.log(`Server is running on http://localhost:${PORT}`); 13 | }); 14 | -------------------------------------------------------------------------------- /compile_commands.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "arguments": [ 4 | "/usr/bin/gcc", 5 | "-c", 6 | "-pthread", 7 | "-I/usr/include/libsoup-2.4", 8 | "-I/usr/include/libxml2", 9 | "-I/usr/include/json-glib-1.0", 10 | "-I/usr/include/libmount", 11 | "-I/usr/include/blkid", 12 | "-I/usr/include/glib-2.0", 13 | "-I/usr/lib/x86_64-linux-gnu/glib-2.0/include", 14 | "-Wl,--export-dynamic", 15 | "-pthread", 16 | "-o", 17 | "./build/webrtc.o", 18 | "WebRTC/webrtc.c" 19 | ], 20 | "directory": "/home/usama/learn/webrtc-from-scrach", 21 | "file": "/home/usama/learn/webrtc-from-scrach/WebRTC/webrtc.c", 22 | "output": "/home/usama/learn/webrtc-from-scrach/build/webrtc.o" 23 | }, 24 | { 25 | "arguments": [ 26 | "/usr/bin/gcc", 27 | "-c", 28 | "-pthread", 29 | "-I/usr/include/libsoup-2.4", 30 | "-I/usr/include/libxml2", 31 | "-I/usr/include/json-glib-1.0", 32 | "-I/usr/include/libmount", 33 | "-I/usr/include/blkid", 34 | "-I/usr/include/glib-2.0", 35 | "-I/usr/lib/x86_64-linux-gnu/glib-2.0/include", 36 | "-Wl,--export-dynamic", 37 | "-pthread", 38 | "-o", 39 | "./build/sdp.o", 40 | "SDP/sdp.c" 41 | ], 42 | "directory": "/home/usama/learn/webrtc-from-scrach", 43 | "file": "/home/usama/learn/webrtc-from-scrach/SDP/sdp.c", 44 | "output": "/home/usama/learn/webrtc-from-scrach/build/sdp.o" 45 | }, 46 | { 47 | "arguments": [ 48 | "/usr/bin/gcc", 49 | "-c", 50 | "-pthread", 51 | "-I/usr/include/libsoup-2.4", 52 | "-I/usr/include/libxml2", 53 | "-I/usr/include/json-glib-1.0", 54 | "-I/usr/include/libmount", 55 | "-I/usr/include/blkid", 56 | "-I/usr/include/glib-2.0", 57 | "-I/usr/lib/x86_64-linux-gnu/glib-2.0/include", 58 | "-Wl,--export-dynamic", 59 | "-pthread", 60 | "-o", 61 | "./build/rtp_session.o", 62 | "RTP/rtp_session.c" 63 | ], 64 | "directory": "/home/usama/learn/webrtc-from-scrach", 65 | "file": "/home/usama/learn/webrtc-from-scrach/RTP/rtp_session.c", 66 | "output": "/home/usama/learn/webrtc-from-scrach/build/rtp_session.o" 67 | }, 68 | { 69 | "arguments": [ 70 | "/usr/bin/gcc", 71 | "-c", 72 | "-pthread", 73 | "-I/usr/include/libsoup-2.4", 74 | "-I/usr/include/libxml2", 75 | "-I/usr/include/json-glib-1.0", 76 | "-I/usr/include/libmount", 77 | "-I/usr/include/blkid", 78 | "-I/usr/include/glib-2.0", 79 | "-I/usr/lib/x86_64-linux-gnu/glib-2.0/include", 80 | "-Wl,--export-dynamic", 81 | "-pthread", 82 | "-o", 83 | "./build/rtp_stream.o", 84 | "RTP/rtp_stream.c" 85 | ], 86 | "directory": "/home/usama/learn/webrtc-from-scrach", 87 | "file": "/home/usama/learn/webrtc-from-scrach/RTP/rtp_stream.c", 88 | "output": "/home/usama/learn/webrtc-from-scrach/build/rtp_stream.o" 89 | }, 90 | { 91 | "arguments": [ 92 | "/usr/bin/gcc", 93 | "-c", 94 | "-pthread", 95 | "-I/usr/include/libsoup-2.4", 96 | "-I/usr/include/libxml2", 97 | "-I/usr/include/json-glib-1.0", 98 | "-I/usr/include/libmount", 99 | "-I/usr/include/blkid", 100 | "-I/usr/include/glib-2.0", 101 | "-I/usr/lib/x86_64-linux-gnu/glib-2.0/include", 102 | "-Wl,--export-dynamic", 103 | "-pthread", 104 | "-o", 105 | "./build/h264_parser.o", 106 | "parser/h264_parser/h264_parser.c" 107 | ], 108 | "directory": "/home/usama/learn/webrtc-from-scrach", 109 | "file": "/home/usama/learn/webrtc-from-scrach/parser/h264_parser/h264_parser.c", 110 | "output": "/home/usama/learn/webrtc-from-scrach/build/h264_parser.o" 111 | }, 112 | { 113 | "arguments": [ 114 | "/usr/bin/gcc", 115 | "-c", 116 | "-pthread", 117 | "-I/usr/include/libsoup-2.4", 118 | "-I/usr/include/libxml2", 119 | "-I/usr/include/json-glib-1.0", 120 | "-I/usr/include/libmount", 121 | "-I/usr/include/blkid", 122 | "-I/usr/include/glib-2.0", 123 | "-I/usr/lib/x86_64-linux-gnu/glib-2.0/include", 124 | "-Wl,--export-dynamic", 125 | "-pthread", 126 | "-o", 127 | "./build/webrtc_app.o", 128 | "webrtc_app.c" 129 | ], 130 | "directory": "/home/usama/learn/webrtc-from-scrach", 131 | "file": "/home/usama/learn/webrtc-from-scrach/webrtc_app.c", 132 | "output": "/home/usama/learn/webrtc-from-scrach/build/webrtc_app.o" 133 | }, 134 | { 135 | "arguments": [ 136 | "/usr/bin/gcc", 137 | "-c", 138 | "-pthread", 139 | "-I/usr/include/libsoup-2.4", 140 | "-I/usr/include/libxml2", 141 | "-I/usr/include/json-glib-1.0", 142 | "-I/usr/include/libmount", 143 | "-I/usr/include/blkid", 144 | "-I/usr/include/glib-2.0", 145 | "-I/usr/lib/x86_64-linux-gnu/glib-2.0/include", 146 | "-Wl,--export-dynamic", 147 | "-pthread", 148 | "-o", 149 | "./build/stun.o", 150 | "STUN/stun.c" 151 | ], 152 | "directory": "/home/usama/learn/webrtc-from-scrach", 153 | "file": "/home/usama/learn/webrtc-from-scrach/STUN/stun.c", 154 | "output": "/home/usama/learn/webrtc-from-scrach/build/stun.o" 155 | }, 156 | { 157 | "arguments": [ 158 | "/usr/bin/gcc", 159 | "-c", 160 | "-pthread", 161 | "-I/usr/include/libsoup-2.4", 162 | "-I/usr/include/libxml2", 163 | "-I/usr/include/json-glib-1.0", 164 | "-I/usr/include/libmount", 165 | "-I/usr/include/blkid", 166 | "-I/usr/include/glib-2.0", 167 | "-I/usr/lib/x86_64-linux-gnu/glib-2.0/include", 168 | "-Wl,--export-dynamic", 169 | "-pthread", 170 | "-o", 171 | "./build/signalling_client.o", 172 | "SignallingClient/signalling_client.c" 173 | ], 174 | "directory": "/home/usama/learn/webrtc-from-scrach", 175 | "file": "/home/usama/learn/webrtc-from-scrach/SignallingClient/signalling_client.c", 176 | "output": "/home/usama/learn/webrtc-from-scrach/build/signalling_client.o" 177 | }, 178 | { 179 | "arguments": [ 180 | "/usr/bin/gcc", 181 | "-c", 182 | "-pthread", 183 | "-I/usr/include/libsoup-2.4", 184 | "-I/usr/include/libxml2", 185 | "-I/usr/include/json-glib-1.0", 186 | "-I/usr/include/libmount", 187 | "-I/usr/include/blkid", 188 | "-I/usr/include/glib-2.0", 189 | "-I/usr/lib/x86_64-linux-gnu/glib-2.0/include", 190 | "-Wl,--export-dynamic", 191 | "-pthread", 192 | "-o", 193 | "./build/ice.o", 194 | "ICE/ice.c" 195 | ], 196 | "directory": "/home/usama/learn/webrtc-from-scrach", 197 | "file": "/home/usama/learn/webrtc-from-scrach/ICE/ice.c", 198 | "output": "/home/usama/learn/webrtc-from-scrach/build/ice.o" 199 | }, 200 | { 201 | "arguments": [ 202 | "/usr/bin/gcc", 203 | "-c", 204 | "-pthread", 205 | "-I/usr/include/libsoup-2.4", 206 | "-I/usr/include/libxml2", 207 | "-I/usr/include/json-glib-1.0", 208 | "-I/usr/include/libmount", 209 | "-I/usr/include/blkid", 210 | "-I/usr/include/glib-2.0", 211 | "-I/usr/lib/x86_64-linux-gnu/glib-2.0/include", 212 | "-Wl,--export-dynamic", 213 | "-pthread", 214 | "-o", 215 | "./build/read.o", 216 | "libAV/read.c" 217 | ], 218 | "directory": "/home/usama/learn/webrtc-from-scrach", 219 | "file": "/home/usama/learn/webrtc-from-scrach/libAV/read.c", 220 | "output": "/home/usama/learn/webrtc-from-scrach/build/read.o" 221 | }, 222 | { 223 | "arguments": [ 224 | "/usr/bin/gcc", 225 | "-c", 226 | "-pthread", 227 | "-I/usr/include/libsoup-2.4", 228 | "-I/usr/include/libxml2", 229 | "-I/usr/include/json-glib-1.0", 230 | "-I/usr/include/libmount", 231 | "-I/usr/include/blkid", 232 | "-I/usr/include/glib-2.0", 233 | "-I/usr/lib/x86_64-linux-gnu/glib-2.0/include", 234 | "-Wl,--export-dynamic", 235 | "-pthread", 236 | "-o", 237 | "./build/network.o", 238 | "Network/network.c" 239 | ], 240 | "directory": "/home/usama/learn/webrtc-from-scrach", 241 | "file": "/home/usama/learn/webrtc-from-scrach/Network/network.c", 242 | "output": "/home/usama/learn/webrtc-from-scrach/build/network.o" 243 | } 244 | ] 245 | -------------------------------------------------------------------------------- /libAV/read.c: -------------------------------------------------------------------------------- 1 | // #include 2 | // #include 3 | // #include 4 | // #include 5 | // #include 6 | // #include 7 | // #include 8 | // 9 | // void main() { 10 | // AVFormatContext *ctx = avformat_alloc_context(); 11 | // avformat_open_input(&ctx, "../sample.h264", NULL, NULL); 12 | // avformat_find_stream_info(ctx, NULL); 13 | // AVCodecParameters *codec_par = ctx->streams[0]->codecpar; 14 | // AVCodec *dec = avcodec_find_decoder(codec_par->codec_id); 15 | // 16 | // AVCodecContext *codec_ctx = avcodec_alloc_context3(dec); 17 | // avcodec_parameters_to_context(codec_ctx, codec_par); 18 | // avcodec_open2(codec_ctx, dec, NULL); 19 | // 20 | // AVPacket *pkt = av_packet_alloc(); 21 | // 22 | // while (av_read_frame(ctx, pkt) >= 0) { 23 | // printf(" %ld %ld %d \n ", pkt->pts, pkt->duration, pkt->size); 24 | // } 25 | // 26 | // printf("%d", ctx->nb_streams); 27 | // } 28 | -------------------------------------------------------------------------------- /minimal_offer.txt: -------------------------------------------------------------------------------- 1 | offer 2 | 3 | v=0 4 | o=- 4395291772417888753 2 IN IP4 127.0.0.1 5 | s=- 6 | t=0 0 7 | 8 | a=group:BUNDLE 0 9 | a=msid-semantic: WMS 10 | 11 | m=video 9 UDP/TLS/RTP/SAVPF 102 103 12 | c=IN IP4 0.0.0.0 13 | a=rtcp:9 IN IP4 0.0.0.0 14 | a=ice-ufrag:H0Tz 15 | a=ice-pwd:HXeKrqNxtoH7MLYV/gQXytWJ 16 | a=ice-options:trickle 17 | a=fingerprint:sha-256 3C:4A:AA:DA:3A:F5:7F:B1:60:B2:1A:BB:59:20:22:DB:FC:44:FB:71:BB:88:6D:E5:BB:2E:C6:7F:6A:9E:0B:83 18 | a=setup:actpass 19 | 20 | a=mid:0 21 | a=sendrecv 22 | a=msid:- 665d1bfb-1759-44c8-92d4-c1b6aaad5892 23 | a=rtcp-mux 24 | a=rtcp-rsize 25 | 26 | a=rtpmap:102 H264/90000 27 | a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f 28 | a=rtpmap:103 rtx/90000 29 | a=fmtp:103 apt=102 30 | a=ssrc:1044859037 cname:Dp9Bc6LU+k7YLLrs 31 | a=ssrc:1044859037 msid:- 665d1bfb-1759-44c8-92d4-c1b6aaad5892 32 | 33 | 34 | -----BEGIN CERTIFICATE----- 35 | MIIC8DCCAdigAwIBAgIGAZG3LRzEMA0GCSqGSIb3DQEBCwUAMDkxDTALBgNVBAMMBHRlc3QxCzAJBgNVBAYTAlVTMRswGQYJKoZIhvcNAQkBFgx0ZXN0QHRlc3QuaW8wHhcNMjQwOTAzMDkxNzUyWhcNMjUwOTAzMDkxNzUyWjA5MQ0wCwYDVQQDDAR0ZXN0MQswCQYDVQQGEwJVUzEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnaO5QvkK9F04Ri+t5DBMc45lA67oh7QdQsIDGG+x6yabDJt3nNkHRJbLB1ZZzZvXrMIIQ4qXcXghYl//t/dhJmp1idBJOY5Num7KaWkgVfV+Aoca2Z9DvPuy5YymoUtaU+Hr0WAd3qQgAISo0BSU2tGPkMsBqgCTLuuTrcNF0XQlhqVHVSF8m+vuecns/mo6FNKgq7fMHehzQdjNtFHoqU5rugjQ5wlZ8rjjsy3OH5UbnfGs8BgyQMJFLvbICkzZiPEdNgO0KCUTuJpy/aecigmq7Nao95hR9QrOCjP2cXKx2Om+suxxtAoBOJTQ7e9frY+5GF6k7WNvNez+fCWQbQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAxiFUw8y92fjsE3ahAGDIUx3x2pzVoFF19ejqD/12Vqv9t3wuilX0q3IuamngJm0p8Ztn8UWVsDCsW5OKrvnMgqG0XUBLWpONhCWFbTab0j0JFtd/fHv+IaqF8pH9SKj76ip28EqilAG9R71wQxdLgupVoRSY4puG4yBJfdXje8bd6aTKvRW4B1eYAMKYKALYMOG6UJwGz/oxW6KhKIsKOGTLRlhDqA8jAHsO+tZmaMaM+cLxjzFBG3855tMS9RvuYeLy87jvUcD/aDiEZxkWbiZjobSQQA1OKq0ciTeyD2gLvmnWKKsoZfLoAmrp4TufSolRXwVEHkX7o2Xy1anZg 36 | -----END CERTIFICATE----- 37 | 38 | 39 | -----BEGIN RSA PRIVATE KEY----- 40 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCdo7lC+Qr0XThGL63kMExzjmUDruiHtB1CwgMYb7HrJpsMm3ec2QdElssHVlnNm9eswghDipdxeCFiX/+392EmanWJ0Ek5jk26bsppaSBV9X4ChxrZn0O8+7LljKahS1pT4evRYB3epCAAhKjQFJTa0Y+QywGqAJMu65Otw0XRdCWGpUdVIXyb6+55yez+ajoU0qCrt8wd6HNB2M20UeipTmu6CNDnCVnyuOOzLc4flRud8azwGDJAwkUu9sgKTNmI8R02A7QoJRO4mnL9p5yKCars1qj3mFH1Cs4KM/ZxcrHY6b6y7HG0CgE4lNDt71+tj7kYXqTtY2817P58JZBtAgMBAAECggEACHO2o1Z1VbxzynY++rzzib8+P5rOq+FRL6WgWIc7QQeSXkmC+cgRzDB7lUVLeQCHPqOD9unE4e1reM9Qh31o2jrwr2Fus6Ujb2tbne2S3BkBVxhbAlpi3YyZ6cCHT0maKmTdacifVrMdEM9hZRAIGngMRwVOGF6B2w0AH4Zt8A4WcQiLd7j+ObW0qQHe1dTImq4/08KqvSImBoxVYg+smLfcyDMyvkFsXwcPtWpjRhrritFjdELSsL3s0WBI0EOWBSpIQRdxgjEmQuAvYZii4jbLyIT6VPGNk2PEIq9c+zLCH3At0ja0ceSMuX9XHcjhYNkukBIoAir8+eawUNNd/wKBgQDP4pflIwLVhDfBSoZ2JjlkAZcBScOvg2hHFQ3eH863yU/IflvqbtnbSv9FGDEYU7IFIF1+/Jr3H+M93+w8Esdz4HnkXGjz+Ecvu2f4bGtockCYVSbd2RR6hAOm6/IweOCN4+JLVfAz4QkqqlCXNfEMAOgO7pacUlWIfaV9Wr9FIwKBgQDCIActvruJklLaEOF8YQDtO8NWrDepEfd1/Kh0ynUU/dTtnQkHiW2ImnuHq4GMGYMRBW8Zztjl63wDrjTfr49VTuF2aNKlvjB/0uiodSLdFCEtvpJ67H8Rc0krbq07/c+kneKBpo4DOskVWmzuUSJ8yMv9RbFxXAwU3o10H/QVLwKBgBy4Mz/mrFePIpzDjPv5n+gfCBuXcz9mKhvX3siXIFnnp+wM+OnUUqinHckP5Ih115w5snD+uPH3J8++hcZu2bs6gdx4n89Et6DyhRSe9d/CGQZyjSINAXVDk7WV1ym3KV6w4uyBfOPN7RRF30hknV6JKYYWlBwYi9SFdz1wMgh9AoGAQwFFGRAVsVWVTXm4KvNcm4YeVaNaDvyJmusbxjw/j4BR57ZlcHmKGjWgX+Ld81q298AVaiYQjcPraWXPEEqLwdlZT0K9OsJcATLuZX8RCpgxH5YA/3b0ITTW06v/FY71BhANJ80yhYDb+Yfdw6Czs7inWIOezM8FyIpM7wE8gbcCgYAXltZPPMmo9C8Cq9cZNDL63NhW/Ghd7BL4kQG2ELqLv55J8iC3O8ua/cV77q1B3/JAmoohze97kX7qUxLbzmzepOGskKbpFaYBHGTzPfG1njnZRNEPTYjCn8fnuKZoNvUrB1xC6AwcdLKvlMeeOyii+Y9ZKab7o4ndPI+0yQxsUw== 41 | -----END RSA PRIVATE KEY----- 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | DTLSv1.2 Record Layer: Handshake Protocol: Client Hello 51 | Content Type: Handshake (22) 52 | Version: DTLS 1.0 (0xfeff) 53 | Epoch: 0 54 | Sequence Number: 0 55 | Length: 75 56 | Handshake Protocol: Client Hello 57 | Handshake Type: Client Hello (1) 58 | Length: 63 59 | Message Sequence: 0 60 | Fragment Offset: 0 61 | Fragment Length: 63 62 | Version: DTLS 1.2 (0xfefd) 63 | Random: 35333631326534622d303233312d343031612d396463352d3364323938366665 64 | Session ID Length: 0 65 | Cookie Length: 0 66 | Cipher Suites Length: 2 67 | Cipher Suites (1 suite) 68 | Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f) 69 | Compression Methods Length: 1 70 | Compression Methods (1 method) 71 | Compression Method: null (0) 72 | Extensions Length: 19 73 | Extension: use_srtp (len=5) 74 | Type: use_srtp (14) 75 | Length: 5 76 | SRTP Protection Profiles Length: 2 77 | SRTP Protection Profile: SRTP_AES128_CM_HMAC_SHA1_80 (0x0001) 78 | MKI Length: 0 79 | Extension: signature_algorithms (len=6) 80 | Type: signature_algorithms (13) 81 | Length: 6 82 | Signature Hash Algorithms Length: 4 83 | Signature Hash Algorithms (2 algorithms) 84 | Signature Algorithm: rsa_pkcs1_sha1 (0x0201) 85 | Signature Hash Algorithm Hash: SHA1 (2) 86 | Signature Hash Algorithm Signature: RSA (1) 87 | Signature Algorithm: rsa_pkcs1_sha256 (0x0401) 88 | Signature Hash Algorithm Hash: SHA256 (4) 89 | Signature Hash Algorithm Signature: RSA (1) 90 | [JA3 Fullstring: 65277,47,14-13,,] 91 | [JA3: 30abed3938e3296fd330aafadca96fe8] 92 | 93 | Frame 706: 201 bytes on wire (1608 bits), 201 bytes captured (1608 bits) on interface any, id 0 94 | Linux cooked capture v1 95 | Internet Protocol Version 4, Src: usama-H110M-H.local (192.168.0.115), Dst: usama-H110M-H.local (192.168.0.115) 96 | User Datagram Protocol, Src Port: 50870, Dst Port: 51795 97 | Datagram Transport Layer Security 98 | DTLSv1.2 Record Layer: Handshake Protocol: Client Hello 99 | Content Type: Handshake (22) 100 | Version: DTLS 1.0 (0xfeff) 101 | Epoch: 0 102 | Sequence Number: 0 103 | Length: 144 104 | Handshake Protocol: Client Hello 105 | Handshake Type: Client Hello (1) 106 | Length: 132 107 | Message Sequence: 0 108 | Fragment Offset: 0 109 | Fragment Length: 132 110 | Version: DTLS 1.2 (0xfefd) 111 | Random: 6bdacb89310eb32ea9d62e6f26ff3d2d1ab8af564209bae48fb7b51a555580e3 112 | Session ID Length: 0 113 | Cookie Length: 0 114 | Cipher Suites Length: 22 115 | Cipher Suites (11 suites) 116 | Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f) 117 | Compression Methods Length: 1 118 | Compression Methods (1 method) 119 | Compression Method: null (0) 120 | Extensions Length: 68 121 | Extension: signature_algorithms (len=20) 122 | Type: signature_algorithms (13) 123 | Length: 20 124 | Signature Hash Algorithms Length: 18 125 | Signature Hash Algorithms (9 algorithms) 126 | Signature Algorithm: rsa_pkcs1_sha1 (0x0201) 127 | Signature Hash Algorithm Hash: SHA1 (2) 128 | Signature Hash Algorithm Signature: RSA (1) 129 | Extension: use_srtp (len=9) 130 | Type: use_srtp (14) 131 | Length: 9 132 | SRTP Protection Profiles Length: 6 133 | SRTP Protection Profile: SRTP_AES128_CM_HMAC_SHA1_80 (0x0001) 134 | SRTP Protection Profile: SRTP_AEAD_AES_256_GCM (0x0008) 135 | SRTP Protection Profile: SRTP_AEAD_AES_128_GCM (0x0007) 136 | MKI Length: 0 137 | 138 | 139 | 140 | todo 141 | signal passing for callbacks 142 | dtls decrypt 143 | ice dtls and webrtc state changes 144 | refactor all code 145 | dtls finish message verify 146 | -------------------------------------------------------------------------------- /parser/h264_parser/h264_parser.c: -------------------------------------------------------------------------------- 1 | 2 | #include "./h264_parser.h" 3 | #include "../../RTP/rtp.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | enum NAL_TYPE { 14 | NAL_NOT_FOUND = -1, 15 | NAL_BUFFER_END = 0, 16 | NAL_THREE = 3, 17 | NAL_FOUR = 4 18 | }; 19 | int start_code[4] = {0, 0, 0, 1}; 20 | 21 | FILE *fptr; 22 | enum NAL_TYPE check_if_nal(unsigned char buffer, int *start_code_index) { 23 | int nal_type = 0; 24 | if (buffer == start_code[*start_code_index] || 25 | (*start_code_index == 2 && buffer == 1)) { 26 | if (*start_code_index == 2 && buffer == 1) { 27 | // printf("got three start index in nal unit %d \n", buffer); 28 | *start_code_index += 2; 29 | nal_type = NAL_THREE; 30 | } else { 31 | *start_code_index += 1; 32 | nal_type = NAL_FOUR; 33 | } 34 | } else 35 | *start_code_index = 0; 36 | 37 | if (*start_code_index == 4) { 38 | *start_code_index = 0; 39 | return nal_type; 40 | } 41 | return NAL_NOT_FOUND; 42 | } 43 | unsigned char get_nal_type(char nal_first_byte) { 44 | char mask = 0x1F; // 0001 1111 45 | nal_first_byte = nal_first_byte & mask; 46 | printf("%u\n", nal_first_byte); 47 | return nal_first_byte; 48 | } 49 | 50 | char *h264_parser_get_nal_unit(uint8_t *au_buffer, int buffer_size, 51 | void(on_parsed_data)(struct RtpStream *, 52 | unsigned char *, int), 53 | struct RtpStream *rtpStream) { 54 | unsigned char nal_buffer[buffer_size + 1]; 55 | int start_code_1 = -1; 56 | int start_code_2 = -1; 57 | int start_code_index = 0; 58 | 59 | for (int i = 0; i < buffer_size; i++) { 60 | int start_code_len = (i == buffer_size - 1) 61 | ? NAL_BUFFER_END 62 | : check_if_nal(au_buffer[i], &start_code_index); 63 | 64 | if (start_code_len != -1) { 65 | if (start_code_1 < 0) { 66 | start_code_1 = i + 1; 67 | } else if (start_code_2 < 0) { 68 | start_code_2 = i; 69 | 70 | if (start_code_len == NAL_BUFFER_END) { 71 | rtpStream->rtp_packet->marker = 1; 72 | } else { 73 | rtpStream->rtp_packet->marker = 0; 74 | } 75 | 76 | int nal_size = ((start_code_2 - start_code_1) - start_code_len) + 1; 77 | if (nal_size > buffer_size) { 78 | printf("failed\n"); 79 | exit(0); 80 | goto next_buffer; 81 | } 82 | 83 | memcpy(nal_buffer, &au_buffer[0] + (start_code_1), nal_size); 84 | // printf("%d\n", get_nal_type(nal_buffer[0])); 85 | // 86 | on_parsed_data(rtpStream, nal_buffer, nal_size); 87 | // printf("\n=---------------------------------------------------\n"); 88 | // for (int b = 0; b < nal_size; b++) 89 | // printf(" %x ", *(nal_buffer + b)); 90 | // exit(0); 91 | // sleep(4); 92 | 93 | // printf("%d %d\n", nal_size, buffer_size); 94 | // uint32_t code = 0x01000000; 95 | // fwrite(&code, 1, 4, fptr); 96 | // fwrite(nal_buffer, 1, nal_size, fptr); 97 | next_buffer: 98 | start_code_1 = start_code_2 + 1; 99 | start_code_2 = -1; 100 | } 101 | } 102 | } 103 | // printf("-0-00000000000000000000000000000000000000"); 104 | // printf("\n=---------------------------------------------------\n"); 105 | // for (int b = 0; b < buffer_size; b++) 106 | // printf(" %x ", *(au_buffer + b)); 107 | 108 | return NULL; 109 | } 110 | 111 | void file_parse(void *file, 112 | void(on_parsed_data)(struct RtpStream *, unsigned char *, int), 113 | struct RtpStream *rtpStream) { 114 | int buffer_size = 10000; 115 | FILE *filePtr = (FILE *)file; 116 | char buffer[buffer_size]; 117 | 118 | while (!feof(filePtr)) { 119 | fread(buffer, 1, buffer_size, filePtr); 120 | h264_parser_get_nal_unit(buffer, buffer_size, on_parsed_data, rtpStream); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /parser/h264_parser/h264_parser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef __file_reader__ 3 | #define __file_reader__ 4 | 5 | #include "../../RTP/rtp.h" 6 | char *h264_parser_get_nal_unit(uint8_t *au_buffer, int buffer_size, 7 | void(on_parsed_data)(struct RtpStream *, 8 | unsigned char *, int), 9 | struct RtpStream *rtpStream); 10 | void file_parse(void *file, 11 | void(on_parsed_data)(struct RtpStream *, unsigned char *, int), 12 | struct RtpStream *rtpStream); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /sample.h264: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/USAMAWIZARD/webrtc-from-scratch/c427f0ec643f6504d5bdbdb02924de68b3bd404d/sample.h264 -------------------------------------------------------------------------------- /test/mastersecretkey.txt: -------------------------------------------------------------------------------- 1 | 2 | # Cipher Suite RSA-AES128-CBC-SHA 3 | CLIENT_RANDOM 65376537356430382d636465372d343030392d616664332d6665393661353261 FF63E7A44B7D57BE1E32EA008A25B11ED27F8C5A6FC1F4C06809892F6C774A5A8433D0F153CA10DC011FB13E85A4A146 4 | CLIENT_RANDOM 65376537356430382d636465372d343030392d616664332d6665393661353261 FF63E7A44B7D57BE1E32EA008A25B11ED27F8C5A6FC1F4C06809892F6C774A5A8433D0F153CA10DC011FB13E85A4A146 5 | -------------------------------------------------------------------------------- /test/test.c: -------------------------------------------------------------------------------- 1 | #include "../DTLS/Encryptions/encryption.h" 2 | #include "../RTP/rtp.h" 3 | #include "../SRTP/srtp.h" 4 | #include "../Utils/utils.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | void hex_eql_assert(guchar *data, gchar *hexstring) { 16 | guchar *bin_test_encrypted; 17 | int len = hexstr_to_char_2(&bin_test_encrypted, hexstring); 18 | assert(memcmp(data, bin_test_encrypted, len) == 0); 19 | free(bin_test_encrypted); 20 | } 21 | struct Rtp; 22 | struct aes_ctx *get_test_aes_ctx(gchar *key, gchar *iv, enum mode mode) { 23 | guchar *bin_iv, *bin_key; 24 | 25 | uint16_t key_size = hexstr_to_char_2(&bin_key, key); 26 | uint16_t iv_size = hexstr_to_char_2(&bin_iv, iv); 27 | 28 | struct encryption_keys encryption_key; 29 | struct cipher_suite_info *cipher_info = 30 | malloc(sizeof(struct cipher_suite_info)); 31 | cipher_info->symitric_algo = AES; 32 | cipher_info->mode = mode; 33 | 34 | encryption_key.client_write_key = bin_key; 35 | encryption_key.client_write_IV = bin_iv; 36 | encryption_key.client_write_mac_key = bin_iv; 37 | 38 | cipher_info->key_size = key_size; 39 | cipher_info->iv_size = iv_size; 40 | cipher_info->hmac_key_len = 14; 41 | 42 | encryption_key.server_write_key = bin_key; 43 | encryption_key.server_write_IV = bin_iv; 44 | encryption_key.server_write_mac_key = bin_iv; 45 | 46 | union symmetric_encrypt symmetric_encrypt; 47 | init_client_server_encryption_ctx(&symmetric_encrypt, &encryption_key, 48 | cipher_info); 49 | 50 | struct aes_ctx *ctx = symmetric_encrypt.aes; 51 | return ctx; 52 | } 53 | void aes_test() { 54 | 55 | // to encrypt 56 | // 14 00 00 0c 00 05 00 00 00 00 00 0c d7 7f a4 a3 2a d1 d6 bc 76 2e 0a fb 57 | // ------------IV 58 | // c8 7c bb fd 9e 77 77 05 2c 74 25 5e 4a 74 92 51 59 | // -------------initial key 60 | // 0c cb 1d 0c 65 cb 44 48 3e 45 74 b8 fb 95 3d 63 61 | // 62 | // encrypted 63 | // 1d 36 dd bb 3d e6 42 3f 64 f4 f3 ba 81 54 f6 b6 9a 27 b7 c8 28 41 71 b7 9e 64 | // b2 36 17 4f 6b 0a 88 65 | 66 | printf("testing AES encryption\n"); 67 | printf("test AES Mode :CBC \n"); 68 | 69 | struct aes_ctx *aes_ctx = 70 | get_test_aes_ctx("aaf5f65767682a3c62ca89863926f24d", 71 | "cc681eaa679a4d70bd2e6a1099eb6a6d", CBC); 72 | uint8_t *block; 73 | 74 | uint32_t len = hexstr_to_char_2( 75 | &block, "1400000c000500000000000c4366e450f4d5828d2e5341a6"); 76 | block = realloc(block, len + 300); 77 | 78 | len = encrypt_aes(aes_ctx->client, block, 0, len); 79 | 80 | printf("after encryption \n"); 81 | 82 | print_hex(block, len); 83 | 84 | hex_eql_assert( 85 | block, 86 | "07a240b00d520ea32d22e8ace7c55f9085f7709ccb816b308b6be928201d669f"); 87 | 88 | printf("encryption with AES CBC TEST successfull \n"); 89 | 90 | ///// 91 | printf("Test AES Mode : CM"); 92 | hexstr_to_char_2(&aes_ctx->client->IV, "3511c3d9d5fc86619febd91467380000"); 93 | aes_ctx->client->mode = CM; 94 | 95 | len = hexstr_to_char_2(&block, 96 | "1400000c000500000000000c4366e450f4d5828d2e5341a6"); 97 | block = realloc(block, len + 300); 98 | 99 | len = encrypt_aes(aes_ctx->client, block, 0, len); 100 | 101 | printf("after encryption %d\n", len); 102 | 103 | print_aes_matrix2(block, 4); 104 | print_aes_matrix2(block + 16, 4); 105 | hex_eql_assert( 106 | block, 107 | "0217192FB91A349F7B3213F210A91397AAA8A56E6D6CB727A0148EC48809BFFE"); 108 | 109 | printf("encryption with AES CM TEST successfull "); 110 | } 111 | 112 | void prf_test() { 113 | 114 | printf("starting prf test \n"); 115 | BIGNUM *secret = BN_new(); 116 | 117 | BIGNUM *client_hello = BN_new(); 118 | BIGNUM *server_hello = BN_new(); 119 | 120 | BN_hex2bn(&secret, "FEFD7D4F93402EAC6C6D875E9A8EE8B8CC9CDCBC03D2E661CC75214B7" 121 | "9F1C938A20215621987912ED841E68B770D3427"); 122 | BN_hex2bn(&client_hello, 123 | "34323532313133382d313163362d343132612d386531382d3835346361616134"); 124 | BN_hex2bn(&server_hello, 125 | "6ba317d2c22dbc6310c03f82d657002658823f15d9923eb7aae0dd5f7acca2d8"); 126 | 127 | guchar *master_secret = 128 | PRF(secret, "master secret", 129 | get_dtls_rand_appended(client_hello, server_hello), G_CHECKSUM_SHA256, 130 | 48); 131 | 132 | guchar *expected; 133 | hexstr_to_char_2(&expected, 134 | "29273fd9c595b788a2c3abfb8e172ba0c4430859083820bb50fd77c4a" 135 | "b0cd290f10219ac5627d788d3c1af2885b03262b11a"); 136 | assert(memcmp(master_secret, expected, 48) == 0); 137 | printf("prf test success full\n"); 138 | // 29273fd9c595b788a2c3abfb8e172ba0c4430859083820bb50fd77c4ab0cd290 139 | } 140 | 141 | void key_generate_keystream(guchar *counter) {} 142 | void test_srtp_iv() { 143 | printf("testing srtp iv generateiton \n"); 144 | 145 | guchar iv[16]; 146 | uint64_t ssrc = 0xdeadbeef; 147 | gchar *salt_key = "9e94cabcc69ccae5b2f7da076b1b"; 148 | guchar *salt_key_bin; 149 | uint32_t key_len = hexstr_to_char_2(&salt_key_bin, salt_key); 150 | 151 | uint64_t packet_index = 17767; 152 | compute_srtp_iv(iv, salt_key_bin, key_len, &ssrc, (guchar *)&packet_index); 153 | 154 | print_hex(iv, 16); 155 | 156 | guchar *expected; 157 | hexstr_to_char_2(&expected, "9e94cabc1831740ab2f7da072e7c0000"); 158 | memcmp(iv, expected, 16); 159 | 160 | printf("iv derivation test successful"); 161 | } 162 | 163 | void test_srtp_key_derivation() { 164 | 165 | guchar *master_key; 166 | hexstr_to_char_2(&master_key, "E1F97A0D3E018BE0D64FA32C06DE4139"); 167 | 168 | guchar *master_salt; 169 | hexstr_to_char_2(&master_salt, "0EC675AD498AFEEBB6960B3AABE6"); 170 | 171 | struct SrtpEncryptionCtx *srtp_encryption_ctx = 172 | malloc(sizeof(struct SrtpEncryptionCtx)); 173 | srtp_encryption_ctx->roc = 0; 174 | srtp_encryption_ctx->kdr = 0; 175 | srtp_encryption_ctx->master_salt_key = master_salt; 176 | srtp_encryption_ctx->master_write_key = master_key; 177 | 178 | struct cipher_suite_info *cipher_info = 179 | malloc(sizeof(struct cipher_suite_info)); 180 | 181 | cipher_info->key_size = 16; 182 | cipher_info->salt_key_len = 14; 183 | cipher_info->hmac_key_len = 20; 184 | cipher_info->hmac_len = 16; 185 | 186 | srtp_key_derivation(srtp_encryption_ctx, cipher_info); 187 | 188 | hex_eql_assert(srtp_encryption_ctx->k_e, "C61E7A93744F39EE10734AFE3FF7A087"); 189 | 190 | hex_eql_assert(srtp_encryption_ctx->k_s, "30CBBC08863D8C85D49DB34A9AE17AC6"); 191 | 192 | hex_eql_assert( 193 | srtp_encryption_ctx->k_a, 194 | "CEBE321F6FF7716B6FD4AB49AF256A156D38BAA48F0A0ACF3C34E2359E6CDBCE"); 195 | 196 | printf("srtp key generation successfull\n"); 197 | } 198 | void test_srtp_encryption() { 199 | 200 | struct SrtpEncryptionCtx *srtp_encryption_ctx = 201 | malloc(sizeof(struct SrtpEncryptionCtx)); 202 | struct cipher_suite_info *cipher_info = 203 | malloc(sizeof(struct cipher_suite_info)); 204 | srtp_encryption_ctx->cipher_suite_info = cipher_info; 205 | 206 | cipher_info->hmac_len = 10; 207 | srtp_encryption_ctx->roc = 0; 208 | 209 | guchar *iv; 210 | uint32_t ssrc = 0x00000000; 211 | uint16_t seq_no = 0x00000000; 212 | 213 | cipher_info->salt_key_len = 14; 214 | hexstr_to_char_2(&srtp_encryption_ctx->k_s, 215 | "F0F1F2F3F4F5F6F7F8F9FAFBFCFD0000"); 216 | 217 | cipher_info->key_size = 16; 218 | hexstr_to_char_2(&srtp_encryption_ctx->k_e, 219 | "2B7E151628AED2A6ABF7158809CF4F3C"); 220 | 221 | cipher_info->hmac_len = 16; 222 | cipher_info->hmac_key_len = 16; 223 | hexstr_to_char_2(&srtp_encryption_ctx->k_a, 224 | "CEBE321F6FF7716B6FD4AB49AF256A15"); 225 | 226 | init_aes(&srtp_encryption_ctx->aes, srtp_encryption_ctx->k_e, 227 | cipher_info->key_size, NULL, 0, NULL, CM); 228 | 229 | uint32_t len = 32; 230 | struct Rtp *rtp = malloc(sizeof(struct Rtp) + len); 231 | 232 | memset(rtp->payload, 0x0, len); 233 | print_hex(rtp->payload, len); 234 | 235 | rtp->ssrc = ssrc; 236 | rtp->seq_no = seq_no; 237 | 238 | encrypt_srtp(srtp_encryption_ctx, rtp, &len); 239 | 240 | guchar *expected; 241 | hexstr_to_char_2(&expected, "E03EAD0935C95E80E166B16DD92B4EB4" 242 | "D23513162B02D0F72A43A2FE4A5F97AB" 243 | "41E95B3BB0A2E8DD477901E4FCA894C0"); 244 | print_hex(rtp->payload, len); 245 | assert(memcmp(expected, rtp->payload, 32) == 0); 246 | printf("srtp encryption successful \n"); 247 | } 248 | void test_srtp_mac() {} 249 | 250 | void test_srtp() { 251 | 252 | struct srtp_ctx *srtp; 253 | 254 | struct encryption_keys *encryption_keys = 255 | calloc(1, sizeof(struct encryption_keys)); 256 | 257 | struct cipher_suite_info *cipher_info; 258 | set_cipher_suite_info(&cipher_info, SRTP_AES128_CM_HMAC_SHA1_80); 259 | encryption_keys->cipher_suite_info = cipher_info; 260 | 261 | encryption_keys->client_write_key = malloc(cipher_info->key_size); 262 | encryption_keys->client_write_SRTP_salt = malloc(cipher_info->salt_key_len); 263 | 264 | guchar *key_block; 265 | hexstr_to_char_2(&key_block, 266 | "E1F97A0D3E018BE0D64FA32C06DE4139" // master encrytion key 267 | "0EC675AD498AFEEBB6960B3AABE6"); // master salt 268 | 269 | copy_key_block(key_block, &encryption_keys->client_write_key, 270 | cipher_info->key_size, 271 | &encryption_keys->client_write_SRTP_salt, 272 | cipher_info->salt_key_len, NULL); 273 | 274 | init_srtp(&srtp, encryption_keys); 275 | 276 | struct Rtp *rtp_packet = malloc(sizeof(struct Rtp) + 400); 277 | hexstr_to_char_2(&rtp_packet, "a1664567507ed7abdeadbeef01000000"); 278 | 279 | guchar *rtp_payload; 280 | uint32_t rtp_payload_size = hexstr_to_char_2( 281 | &rtp_payload, 282 | "6742c01fd9005005bb016a020202800001f480007530078c1924000000000006000000"); 283 | memcpy(rtp_packet->payload, rtp_payload, rtp_payload_size); 284 | 285 | printf("to encrypt rtp packet\n"); 286 | printf("header\n"); 287 | print_hex(rtp_packet, sizeof(struct Rtp)); 288 | printf("payload\n"); 289 | print_hex(rtp_packet->payload, rtp_payload_size); 290 | 291 | encrypt_srtp(srtp->client, rtp_packet, &rtp_payload_size); 292 | 293 | printf("srtp encrypted payload\n"); 294 | print_hex(rtp_packet->payload, rtp_payload_size); 295 | } 296 | 297 | void test_aes_decrypt() { 298 | 299 | printf("----------------------------------------------------\n"); 300 | printf("testing AES decryption\n"); 301 | printf("AES Mode :CBC \n"); 302 | 303 | struct aes_ctx *aes_ctx = 304 | get_test_aes_ctx("aaf5f65767682a3c62ca89863926f24d", 305 | "3511c3d9d5fc86619febd91467380000", CBC); 306 | 307 | uint8_t *block; // encrypted 308 | 309 | uint32_t len = hexstr_to_char_2(&block, "8625B940519AF8AA776FD094120D19C7"); 310 | 311 | len = decrypt_aes(aes_ctx->server, block, 0, len); 312 | 313 | printf("after decryption \n"); 314 | 315 | print_hex(block, len); 316 | 317 | hex_eql_assert(block, "1400000c000500000000000c4366e450"); 318 | printf("decryption with AES CBC TEST successfull \n"); 319 | 320 | free(block); 321 | printf("----------------------------------------------------\n"); 322 | printf("testing AES decryption\n"); 323 | printf("AES Mode :CM \n"); 324 | 325 | aes_ctx = get_test_aes_ctx("aaf5f65767682a3c62ca89863926f24d", 326 | "3511c3d9d5fc86619febd91467380000", CM); 327 | 328 | len = hexstr_to_char_2( 329 | &block, 330 | "0217192FB91A349F7B3213F210A913974A7D27EF433AF681A0148EC8CB6F5BAE"); 331 | len = decrypt_aes(aes_ctx->server, block, 0, len); 332 | hex_eql_assert( 333 | block, 334 | "1400000c000500000000000c4366e4501400000c000500000000000c4366e450"); 335 | printf("decryption with AES CM TEST successful"); 336 | free(block); 337 | } 338 | 339 | void test_inverse_counter_incr() { 340 | 341 | uint8_t add[4][4] = {{0x02, 0x03, 0x01, 0xff}, 342 | {0x01, 0x02, 0x03, 0xff}, 343 | {0x01, 0x01, 0x02, 0x00}, 344 | {0x03, 0x01, 0x01, 0xff}}; 345 | 346 | print_aes_matrix2(add, 4); 347 | increment_counter(add); 348 | increment_counter(add); 349 | increment_counter(add); 350 | print_aes_matrix2(add, 4); 351 | hex_eql_assert(add, "020301ff010203ff0101020103010102"); 352 | printf("inversed counter increment_counter"); 353 | } 354 | int main() { 355 | 356 | // test_srtp_mac(); 357 | // test_srtp_encryption(); 358 | // test_srtp_key_derivation(); 359 | // test_srtp_iv(); 360 | // test_srtp(); 361 | // aes_test(); 362 | // test_aes_decrypt(); 363 | // prf_test(); 364 | // test_inverse_counter_incr(); 365 | } 366 | -------------------------------------------------------------------------------- /webrtc_app.c: -------------------------------------------------------------------------------- 1 | #include "./ICE/ice.h" 2 | #include "./Network/network.h" 3 | #include "./RTP/rtp.h" 4 | #include "./SDP/sdp.h" 5 | #include "./SignallingClient/signalling_client.h" 6 | #include "./Utils/utils.h" 7 | #include "./WebRTC/webrtc.h" 8 | #include "./parser/h264_parser/h264_parser.h" 9 | #include "json-glib/json-glib.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | struct RTCPeerConnection *peer; 22 | SoupWebsocketConnection *ws_conn; 23 | const gchar *peer_pair; 24 | 25 | static gchar *get_string_from_json_object(JsonObject *object) { 26 | JsonNode *root; 27 | JsonGenerator *generator; 28 | gchar *text; 29 | /* Make it the root node */ 30 | root = json_node_init_object(json_node_alloc(), object); 31 | generator = json_generator_new(); 32 | json_generator_set_root(generator, root); 33 | text = json_generator_to_data(generator, NULL); 34 | 35 | /* Release everything */ 36 | g_object_unref(generator); 37 | json_node_free(root); 38 | return text; 39 | } 40 | 41 | extern FILE *fptr; 42 | void user_defined_read_data(char *file_name, 43 | void(send_rtp_packet)(struct RtpStream *, 44 | unsigned char *, int), 45 | struct RtpStream *rtpStream) { 46 | 47 | AVFormatContext *ctx = avformat_alloc_context(); 48 | if (avformat_open_input(&ctx, file_name, NULL, NULL)) { 49 | exit(0); 50 | } 51 | avformat_find_stream_info(ctx, NULL); 52 | 53 | AVCodecParameters *codec_par = ctx->streams[0]->codecpar; 54 | 55 | AVCodec *dec = avcodec_find_decoder(codec_par->codec_id); 56 | 57 | AVCodecContext *codec_ctx = avcodec_alloc_context3(dec); 58 | avcodec_parameters_to_context(codec_ctx, codec_par); 59 | avcodec_open2(codec_ctx, dec, NULL); 60 | 61 | AVPacket *pkt = av_packet_alloc(); 62 | 63 | fptr = fopen("sample.h264", "rb"); 64 | g_assert(fptr); 65 | 66 | while (av_read_frame(ctx, pkt) >= 0) { 67 | static int i = 1; 68 | h264_parser_get_nal_unit(pkt->data, pkt->size, send_rtp_packet, rtpStream); 69 | rtpStream->timestamp += 3000; 70 | 71 | // if(i==4) 72 | // exit(0); 73 | // 74 | // i++; 75 | } 76 | } 77 | void on_ice_candidate(struct RTCPeerConnection *peer, 78 | struct RTCIecCandidates *candidate) { 79 | 80 | JsonObject *candidate_message = json_object_new(); 81 | json_object_set_string_member(candidate_message, "command", "candidate"); 82 | json_object_set_string_member(candidate_message, "peer", peer_pair); 83 | 84 | JsonObject *candidate_obj = NULL; 85 | if (candidate != NULL) { 86 | 87 | candidate_obj = json_object_new(); 88 | json_object_set_string_member(candidate_obj, "candidate", 89 | candidate->candidate); 90 | char *sdpmid = g_strdup_printf("%d", candidate->sdpMid); 91 | json_object_set_string_member(candidate_obj, "sdpMid", sdpmid); 92 | json_object_set_int_member(candidate_obj, "sdpMLineIndex", 0); 93 | } 94 | 95 | json_object_set_object_member(candidate_message, "candidate", candidate_obj); 96 | 97 | char *candidate_message_str = get_string_from_json_object(candidate_message); 98 | printf("send %s\n", candidate_message_str); 99 | soup_websocket_connection_send_text(ws_conn, candidate_message_str); 100 | } 101 | void on_remote_ice_candidate(JsonObject *object, const gchar *webrtcbin_id) { 102 | 103 | struct RTCIecCandidates *remote_candidate = NULL; 104 | 105 | if (object != NULL) { 106 | remote_candidate = calloc(1, sizeof(struct RTCIecCandidates)); 107 | remote_candidate->candidate = 108 | (char *)json_object_get_string_member(object, "candidate"); 109 | remote_candidate->sdpMid = 110 | atoi(json_object_get_string_member(object, "sdpMid")); 111 | } 112 | add_ice_candidate(peer, remote_candidate); 113 | } 114 | void on_remote_description(JsonObject *object, const gchar *type, 115 | const gchar *webrtcbin_id) { 116 | 117 | gchar *sdp_string = (gchar *)json_object_get_string_member(object, "sdp"); 118 | 119 | if (strncmp(type, "answer", 6) == 0) { 120 | 121 | struct RTCSessionDescription *session_desc = json_object_to_sdp(object); 122 | if (session_desc == NULL) { 123 | printf("invalid sdp"); 124 | return; 125 | } 126 | set_remote_discription(peer, session_desc); 127 | } 128 | if (strncmp(type, "offer", 5)) { 129 | } 130 | } 131 | 132 | void on_websocket_connected(SoupWebsocketConnection *conn) { ws_conn = conn; } 133 | 134 | void on_websocket_disconnected(SoupWebsocketConnection *conn) { 135 | printf("websocket disconected"); 136 | exit(0); 137 | } 138 | 139 | void on_start(JsonObject *object) { 140 | if (ws_conn == NULL) { 141 | printf("websocket is not connected"); 142 | return; 143 | } 144 | 145 | peer_pair = json_object_get_string_member(object, "peer"); 146 | peer = NEW_RTCPeerConnection(); 147 | peer->bundle_policy = BUNDLE_MAX_BUNDLE; 148 | peer->on_ice_candidate = &on_ice_candidate; 149 | 150 | struct MediaStreamTrack *video_track = 151 | NEW_MediaTrack("video", "video NEW_MediaTrack", &user_defined_read_data, 152 | "./sample.h264"); 153 | add_track(peer, video_track); 154 | 155 | JsonObject *offer_message = json_object_new(); 156 | JsonObject *sdp = get_test_ofer(); 157 | json_object_set_object_member(offer_message, "offer", sdp); 158 | 159 | json_object_set_string_member(offer_message, "command", "offer"); 160 | json_object_set_string_member(offer_message, "peer", peer_pair); 161 | 162 | char *str_offer_message = get_string_from_json_object(offer_message); 163 | printf("%s\n", str_offer_message); 164 | 165 | soup_websocket_connection_send_text(ws_conn, str_offer_message); 166 | // create_offer(peer); 167 | struct RTCSessionDescription *local_sdp = json_object_to_sdp(sdp); 168 | 169 | set_local_description(peer, local_sdp); 170 | } 171 | 172 | gint main(gint argc, gchar **argv) { 173 | 174 | static GMainLoop *main_loop; 175 | // struct RtpSession *rtpSession = create_rtp_session(); 176 | // char *loopback_ip = "127.0.0.1"; 177 | // void *filePtr = fopen("./sample.h264", "rb"); 178 | // if (filePtr == NULL) { 179 | // printf("file not found "); 180 | // } 181 | 182 | // struct MediaStreamTrack *video_track = NEW_MediaTrack( 183 | // "video", "video_1", &user_defined_read_data, "sample.h264"); 184 | // struct RtpStream *rtpStream = create_rtp_stream(NULL, video_track, 1244, 185 | // 98); struct CandidataPair *pair = malloc(sizeof(struct CandidataPair)); 186 | // pair->p0 = malloc(sizeof(struct RTCIecCandidates)); 187 | // pair->p1 = malloc(sizeof(struct RTCIecCandidates)); 188 | // pair->p0->sock_desc = get_udp_sock_desc(); 189 | // pair->p1->src_socket = get_network_socket("127.0.0.1", 5001); 190 | // init_rtp_stream(rtpStream, pair, NULL); 191 | // start_rtp_stream(rtpStream); 192 | 193 | websocket_connect("127.0.0.1", 3001); 194 | 195 | main_loop = g_main_loop_new(NULL, FALSE); 196 | g_main_loop_run(main_loop); 197 | g_main_loop_unref(main_loop); 198 | } 199 | 200 | 201 | --------------------------------------------------------------------------------