diff --git a/COPYRIGHT b/COPYRIGHT index 41d8fda3f..8a2fe82fc 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -55,4 +55,6 @@ UltraGrid - A High Definition Collaboratory at Lawrence Berkeley Laboratory. This product uses the RSA Data Security, Inc. MD5 Message-Digest Algorithm. + This product includes software developed by the OpenSSL Project + for use in the OpenSSL Toolkit. (http://www.openssl.org/) diff --git a/Makefile.in b/Makefile.in index f7bea7ebe..aab209601 100644 --- a/Makefile.in +++ b/Makefile.in @@ -89,10 +89,13 @@ OBJS = @OBJS@ \ src/compat/platform_spin.o \ src/compat/platform_time.o \ src/compat/usleep.o \ + src/crypto/crc_32.o \ src/crypto/crypt_aes.o \ src/crypto/crypt_aes_impl.o \ src/crypto/crypt_des.o \ src/crypto/md5.o \ + src/crypto/openssl_encrypt.o \ + src/crypto/openssl_decrypt.o \ src/crypto/random.o \ src/ihdtv/ihdtv.o \ src/module.o \ diff --git a/configure.ac b/configure.ac index c76af745a..05f71c89c 100644 --- a/configure.ac +++ b/configure.ac @@ -2526,6 +2526,33 @@ fi AC_SUBST(IMPORT_CONTROL_KEYBOARD_LIBS) +# ------------------------------------------------------------------------------------------------- +# OpenSSL-libcrypto +# ------------------------------------------------------------------------------------------------- +crypto=no +crypto_req=auto +AC_ARG_ENABLE(openssl, + AS_HELP_STRING([--disable-openssl], [disable OpenSSL support(default is auto)]), + [crypto_req=$enableval], + [crypto_req=auto] + ) + +PKG_CHECK_MODULES([CRYPTO], [libcrypto], [crypto=yes], [crypto=no]) + +if test $crypto_req != no -a $crypto = yes; then + AC_DEFINE([HAVE_CRYPTO], [1], [Build with OpenSSL support]) + CFLAGS="$CFLAGS $CRYPTO_CFLAGS" + CXXFLAGS="$CXXFLAGS $CRYPTO_CFLAGS" + CPPFLAGS="$CPPFLAGS $CRYPTO_CFLAGS" + LIBS="$LIBS $CRYPTO_LIBS" +else + crypto=no +fi + +if test $crypto_req = yes -a $crypto = no; then + AC_MSG_ERROR([OpenSSL not found]); +fi + # ------------------------------------------------------------------------------------------------- # Run subsequent configure scripts # ------------------------------------------------------------------------------------------------- @@ -2552,6 +2579,7 @@ RESULT=\ Standalone modules .......... $build_libraries License ..................... $license iHDTV support ............... $ihdtv + OpenSSL-libcrypto ........... $crypto Bluefish444 ................. $bluefish444 (audio: $blue_audio) DeckLink .................... $decklink diff --git a/src/audio/audio.c b/src/audio/audio.c index 484457bd1..eba91659c 100644 --- a/src/audio/audio.c +++ b/src/audio/audio.c @@ -129,6 +129,8 @@ struct state_audio { echo_cancellation_t *echo_state; struct audio_export *exporter; int resample_to; + + char *requested_encryption; }; /** @@ -181,7 +183,8 @@ static void audio_scale_usage(void) */ struct state_audio * audio_cfg_init(struct module *parent, char *addrs, int recv_port, int send_port, const char *send_cfg, const char *recv_cfg, - char *jack_cfg, char *fec_cfg, char *audio_channel_map, const char *audio_scale, + char *jack_cfg, char *fec_cfg, const char *encryption, + char *audio_channel_map, const char *audio_scale, bool echo_cancellation, bool use_ipv6, char *mcast_if, audio_codec_t audio_codec, int resample_to) { @@ -259,8 +262,12 @@ struct state_audio * audio_cfg_init(struct module *parent, char *addrs, int recv } else { s->echo_state = NULL; } + + if(encryption) { + s->requested_encryption = strdup(encryption); + } - s->tx_session = tx_init(&s->mod, 1500, TX_MEDIA_AUDIO, fec_cfg); + s->tx_session = tx_init(&s->mod, 1500, TX_MEDIA_AUDIO, fec_cfg, encryption); if(!s->tx_session) { fprintf(stderr, "Unable to initialize audio transmit.\n"); goto error; @@ -420,6 +427,8 @@ void audio_done(struct state_audio *s) pdb_destroy(&s->audio_participants); } audio_export_destroy(s->exporter); + module_done(&s->mod); + free(s->requested_encryption); free(s); } } @@ -457,7 +466,7 @@ static void *audio_receiver_thread(void *arg) memset(&pbuf_data.buffer, 0, sizeof(struct audio_frame)); memset(&device_desc, 0, sizeof(struct audio_desc)); - pbuf_data.decoder = audio_decoder_init(s->audio_channel_map, s->audio_scale); + pbuf_data.decoder = audio_decoder_init(s->audio_channel_map, s->audio_scale, s->requested_encryption); assert(pbuf_data.decoder != NULL); printf("Audio receiving started.\n"); diff --git a/src/audio/audio.h b/src/audio/audio.h index 3177f6d01..8f32b2dd5 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -120,7 +120,8 @@ struct module; struct state_audio * audio_cfg_init(struct module *parent, char *addrs, int recv_port, int send_port, const char *send_cfg, const char *recv_cfg, - char *jack_cfg, char *fec_cfg, char *audio_channel_map, const char *audio_scale, + char *jack_cfg, char *fec_cfg, const char *encryption, + char *audio_channel_map, const char *audio_scale, bool echo_cancellation, bool use_ipv6, char *mcast_iface, audio_codec_t audio_codec, int resample_to); void audio_finish(struct state_audio *s); diff --git a/src/control.c b/src/control.cpp similarity index 78% rename from src/control.c rename to src/control.cpp index 7db557bdb..ceaf934f2 100644 --- a/src/control.c +++ b/src/control.cpp @@ -52,13 +52,19 @@ #include "control.h" +#include + #include "debug.h" #include "messaging.h" #include "module.h" +#include "stats.h" +#include "tv.h" #define DEFAULT_CONTROL_PORT 5054 #define MAX_CLIENTS 16 +using namespace std; + struct client { int fd; char buff[1024]; @@ -69,10 +75,14 @@ struct client { }; struct control_state { + struct module mod; pthread_t thread_id; int local_fd[2]; int network_port; struct module *root_module; + + set stats; + pthread_mutex_t stats_lock; }; #define CONTROL_EXIT -1 @@ -84,6 +94,10 @@ static ssize_t write_all(int fd, const void *buf, size_t count); static void * control_thread(void *args); static void send_response(int fd, struct response *resp); +/** + * This function writes all data (in contrast to write() which + * can write only part of passed buffer) + */ static ssize_t write_all(int fd, const void *buf, size_t count) { unsigned char *p = (unsigned char *) buf; @@ -103,10 +117,16 @@ static ssize_t write_all(int fd, const void *buf, size_t count) int control_init(int port, struct control_state **state, struct module *root_module) { - struct control_state *s = (struct control_state *) malloc(sizeof(struct control_state)); + control_state *s = new control_state; s->root_module = root_module; + pthread_mutex_init(&s->stats_lock, NULL); + + module_init_default(&s->mod); + s->mod.cls = MODULE_CLASS_CONTROL; + s->mod.priv_data = s; + if(port == -1) { s->network_port = DEFAULT_CONTROL_PORT; } else { @@ -125,6 +145,8 @@ int control_init(int port, struct control_state **state, struct module *root_mod return -1; } + module_register(&s->mod, root_module); + *state = s; return 0; } @@ -207,15 +229,6 @@ static int process_msg(struct control_state *s, int client_fd, char *message) append_message_path(path, sizeof(path), (enum module_class[]){ MODULE_CLASS_COMPRESS, MODULE_CLASS_NONE }); resp = send_message(s->root_module, path, (struct message *) msg); } - } else if(prefix_matches(message, "stats ")) { - struct msg_stats *msg = (struct msg_stats *) - new_message(sizeof(struct msg_stats)); - char *stats = suffix(message, "stats "); - - strncpy(msg->what, stats, sizeof(msg->what) - 1); - - // resp = send_message(s->root_module, "blblbla", &data); - resp = new_response(RESPONSE_NOT_FOUND, strdup("statistics currently not working")); } else if(strcasecmp(message, "bye") == 0) { ret = CONTROL_CLOSE_HANDLE; resp = new_response(RESPONSE_OK, NULL); @@ -284,6 +297,9 @@ static bool parse_msg(char *buffer, char buffer_len, /* out */ char *message, in return ret; } + +#define is_internal_port(x) (x == s->local_fd[1]) + static void * control_thread(void *args) { struct control_state *s = (struct control_state *) args; @@ -310,7 +326,7 @@ static void * control_thread(void *args) struct client *clients = NULL; - struct client *new_client = malloc(sizeof(struct client)); + struct client *new_client = (struct client *) malloc(sizeof(struct client)); new_client->fd = s->local_fd[1]; new_client->prev = NULL; new_client->next = NULL; @@ -319,25 +335,39 @@ static void * control_thread(void *args) bool should_exit = false; + struct timeval last_report_sent; + const int report_interval_sec = 5; + gettimeofday(&last_report_sent, NULL); + while(!should_exit) { - fd_set set; - FD_ZERO(&set); - FD_SET(fd, &set); + fd_set fds; + FD_ZERO(&fds); + FD_SET(fd, &fds); int max_fd = fd + 1; struct client *cur = clients; while(cur) { - FD_SET(cur->fd, &set); + FD_SET(cur->fd, &fds); if(cur->fd + 1 > max_fd) { max_fd = cur->fd + 1; } cur = cur->next; } - if(select(max_fd, &set, NULL, NULL, NULL) >= 1) { - if(FD_ISSET(fd, &set)) { - struct client *new_client = malloc(sizeof(struct client)); + struct timeval timeout; + timeout.tv_sec = report_interval_sec; + timeout.tv_usec = 0; + + struct timeval *timeout_ptr = NULL; + if(clients->next != NULL) { // some remote client + timeout_ptr = &timeout; + } + + if(select(max_fd, &fds, NULL, NULL, timeout_ptr) >= 1) { + if(FD_ISSET(fd, &fds)) { + struct client *new_client = (struct client *) + malloc(sizeof(struct client)); new_client->fd = accept(fd, (struct sockaddr *) &client_addr, &len); new_client->prev = NULL; new_client->next = clients; @@ -348,7 +378,7 @@ static void * control_thread(void *args) struct client *cur = clients; while(cur) { - if(FD_ISSET(cur->fd, &set)) { + if(FD_ISSET(cur->fd, &fds)) { ssize_t ret = read(cur->fd, cur->buff + cur->buff_len, sizeof(cur->buff) - cur->buff_len); if(ret == -1) { @@ -381,7 +411,7 @@ static void * control_thread(void *args) cur->buff_len = cur_buffer_len; int ret = process_msg(s, cur->fd, msg); - if(ret == CONTROL_EXIT) { + if(ret == CONTROL_EXIT && is_internal_port(cur->fd)) { should_exit = true; } else if(ret == CONTROL_CLOSE_HANDLE) { shutdown(cur->fd, SHUT_RDWR); @@ -394,6 +424,42 @@ static void * control_thread(void *args) cur = cur->next; } + + struct timeval curr_time; + gettimeofday(&curr_time, NULL); + if(tv_diff(curr_time, last_report_sent) > report_interval_sec) { + char buffer[1025]; + bool empty = true; + memset(buffer, '\0', sizeof(buffer)); + strncpy(buffer + strlen(buffer), "stats", sizeof(buffer) - + strlen(buffer) - 1); + pthread_mutex_lock(&s->stats_lock); + for(set::iterator it = s->stats.begin(); + it != s->stats.end(); ++it) { + empty = false; + strncpy(buffer + strlen(buffer), " ", sizeof(buffer) - + strlen(buffer) - 1); + stats_format(*it, buffer + strlen(buffer), + sizeof(buffer) - strlen(buffer)); + } + + pthread_mutex_unlock(&s->stats_lock); + strncpy(buffer + strlen(buffer), "\r\n", sizeof(buffer) - + strlen(buffer) - 1); + + if(strlen(buffer) < 1024 && !empty) { + cur = clients; + while(cur) { + if(is_internal_port(cur->fd)) { // skip local FD + cur = cur->next; + continue; + } + write_all(cur->fd, buffer, strlen(buffer)); + cur = cur->next; + } + } + last_report_sent = curr_time; + } } struct client *cur = clients; @@ -415,10 +481,30 @@ void control_done(struct control_state *s) return; } + module_done(&s->mod); + write_all(s->local_fd[0], "quit\r\n", 6); pthread_join(s->thread_id, NULL); close(s->local_fd[0]); + + pthread_mutex_destroy(&s->stats_lock); + + delete s; +} + +void control_add_stats(struct control_state *s, struct stats *stats) +{ + pthread_mutex_lock(&s->stats_lock); + s->stats.insert(stats); + pthread_mutex_unlock(&s->stats_lock); +} + +void control_remove_stats(struct control_state *s, struct stats *stats) +{ + pthread_mutex_lock(&s->stats_lock); + s->stats.erase(stats); + pthread_mutex_unlock(&s->stats_lock); } diff --git a/src/control.h b/src/control.h index 796a5eb2e..b4315fdb9 100644 --- a/src/control.h +++ b/src/control.h @@ -45,8 +45,13 @@ * */ +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + struct control_state; struct module; +struct stats; #define CONTROL_DEFAULT_PORT -1 @@ -55,4 +60,10 @@ struct module; */ int control_init(int port, struct control_state **state, struct module *root_module); void control_done(struct control_state *s); +void control_add_stats(struct control_state *state, struct stats *stats); +void control_remove_stats(struct control_state *state, struct stats *stats); + +#ifdef __cplusplus +} +#endif // __cplusplus diff --git a/src/crypto/crc.h b/src/crypto/crc.h new file mode 100644 index 000000000..304dae524 --- /dev/null +++ b/src/crypto/crc.h @@ -0,0 +1,57 @@ +/* +** CRC.H - header file for SNIPPETS CRC and checksum functions +*/ + +#ifndef CRC__H +#define CRC__H + +#include /* For size_t */ + +/* +** File: ARCCRC16.C +*/ + +void init_crc_table(void); +uint16_t crc_calc(uint16_t crc, char *buf, unsigned nbytes); +void do_file(char *fn); + +/* +** File: CRC-16.C +*/ + +uint16_t crc16(char *data_p, uint16_t length); + +/* +** File: CRC-16F.C +*/ + +uint16_t updcrc(uint16_t icrc, uint8_t *icp, size_t icnt); + +/* +** File: CRC_32.C +*/ + +#define UPDC32(octet,crc) (crc_32_tab[((crc)\ + ^ ((uint8_t)octet)) & 0xff] ^ ((crc) >> 8)) + +uint32_t updateCRC32(unsigned char ch, uint32_t crc); +bool crc32file(char *name, uint32_t *crc, long *charcnt); +uint32_t crc32buf(char *buf, size_t len); + +uint32_t crc32buf_with_oldcrc(char *buf, size_t len, uint32_t oldcrc); + +/* +** File: CHECKSUM.C +*/ + +unsigned checksum(void *buffer, size_t len, unsigned int seed); + +/* +** File: CHECKEXE.C +*/ + +void checkexe(char *fname); + + + +#endif /* CRC__H */ diff --git a/src/crypto/crc_32.c b/src/crypto/crc_32.c new file mode 100644 index 000000000..66b119528 --- /dev/null +++ b/src/crypto/crc_32.c @@ -0,0 +1,206 @@ +/* Crc - 32 BIT ANSI X3.66 CRC checksum files */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#include "config_unix.h" +#include "config_win32.h" +#endif // HAVE_CONFIG_H + +#include +#include "crc.h" + +#ifdef __TURBOC__ + #pragma warn -cln +#endif + +/**********************************************************************\ +|* Demonstration program to compute the 32-bit CRC used as the frame *| +|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *| +|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *| +|* protocol). The 32-bit FCS was added via the Federal Register, *| +|* 1 June 1982, p.23798. I presume but don't know for certain that *| +|* this polynomial is or will be included in CCITT V.41, which *| +|* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *| +|* PUB 78 says that the 32-bit FCS reduces otherwise undetected *| +|* errors by a factor of 10^-5 over 16-bit FCS. *| +\**********************************************************************/ + +/* Need an unsigned type capable of holding 32 bits; */ + +typedef uint32_t UNS_32_BITS; + +/* Copyright (C) 1986 Gary S. Brown. You may use this program, or + code or tables extracted from it, as desired without restriction.*/ + +/* First, the polynomial itself and its table of feedback terms. The */ +/* polynomial is */ +/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ +/* Note that we take it "backwards" and put the highest-order term in */ +/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +/* the MSB being 1. */ + +/* Note that the usual hardware shift register implementation, which */ +/* is what we're using (we're merely optimizing it by doing eight-bit */ +/* chunks at a time) shifts bits into the lowest-order term. In our */ +/* implementation, that means shifting towards the right. Why do we */ +/* do it this way? Because the calculated CRC must be transmitted in */ +/* order from highest-order term to lowest-order term. UARTs transmit */ +/* characters in order from LSB to MSB. By storing the CRC this way, */ +/* we hand it to the UART in the order low-byte to high-byte; the UART */ +/* sends each low-bit to hight-bit; and the result is transmission bit */ +/* by bit from highest- to lowest-order term without requiring any bit */ +/* shuffling on our part. Reception works similarly. */ + +/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +/* */ +/* 1. The table can be generated at runtime if desired; code to do so */ +/* is shown later. It might not be obvious, but the feedback */ +/* terms simply represent the results of eight shift/xor opera- */ +/* tions for all combinations of data and CRC register values. */ +/* */ +/* 2. The CRC accumulation logic is the same for all CRC polynomials, */ +/* be they sixteen or thirty-two bits wide. You simply choose the */ +/* appropriate table. Alternatively, because the table can be */ +/* generated at runtime, you can start by generating the table for */ +/* the polynomial in question and use exactly the same "updcrc", */ +/* if your application needn't simultaneously handle two CRC */ +/* polynomials. (Note, however, that XMODEM is strange.) */ +/* */ +/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */ +/* of course, 32-bit entries work OK if the high 16 bits are zero. */ +/* */ +/* 4. The values must be right-shifted by eight bits by the "updcrc" */ +/* logic; the shift must be unsigned (bring in zeroes). On some */ +/* hardware you could probably optimize the shift in assembler by */ +/* using byte-swap instructions. */ + +static UNS_32_BITS crc_32_tab[] = { /* CRC polynomial 0xedb88320 */ +0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, +0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, +0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, +0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, +0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, +0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, +0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, +0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, +0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, +0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, +0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, +0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, +0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, +0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, +0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, +0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, +0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, +0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, +0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, +0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, +0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, +0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, +0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, +0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, +0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, +0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, +0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, +0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, +0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, +0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, +0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, +0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, +0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, +0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, +0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, +0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, +0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, +0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, +0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, +0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, +0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, +0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, +0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +uint32_t updateCRC32(unsigned char ch, uint32_t crc) +{ + return UPDC32(ch, crc); +} + +bool crc32file(char *name, uint32_t *crc, long *charcnt) +{ + register FILE *fin; + register uint32_t oldcrc32; + register int c; + + oldcrc32 = 0xFFFFFFFF; *charcnt = 0; +#ifdef MSDOS + if ((fin=fopen(name, "rb"))==NULL) +#else + if ((fin=fopen(name, "r"))==NULL) +#endif + { + perror(name); + return false; + } + while ((c=getc(fin))!=EOF) + { + ++*charcnt; + oldcrc32 = UPDC32(c, oldcrc32); + } + + if (ferror(fin)) + { + perror(name); + *charcnt = -1; + } + fclose(fin); + + *crc = oldcrc32 = ~oldcrc32; + + return true; +} + +uint32_t crc32buf(char *buf, size_t len) +{ + register uint32_t oldcrc32; + + oldcrc32 = 0xFFFFFFFF; + + for ( ; len; --len, ++buf) + { + oldcrc32 = UPDC32(*buf, oldcrc32); + } + + return ~oldcrc32; +} + +uint32_t crc32buf_with_oldcrc(char *buf, size_t len, uint32_t old_crc) +{ + register uint32_t oldcrc32; + + oldcrc32 = old_crc; + + for ( ; len; --len, ++buf) + { + oldcrc32 = UPDC32(*buf, oldcrc32); + } + + return ~oldcrc32; +} + +#ifdef TEST + +main(int argc, char *argv[]) +{ + uint32_t crc; + long charcnt; + register errors = 0; + + while(--argc > 0) + { + errors |= crc32file(*++argv, &crc, &charcnt); + printf("%08lX %7ld %s\n", crc, charcnt, *argv); + } + return(errors != 0); +} + +#endif /* TEST */ diff --git a/src/crypto/openssl_decrypt.c b/src/crypto/openssl_decrypt.c new file mode 100644 index 000000000..b73343690 --- /dev/null +++ b/src/crypto/openssl_decrypt.c @@ -0,0 +1,185 @@ +/* + * FILE: aes_decrypt.c + * AUTHOR: Colin Perkins + * Ladan Gharai + * Martin Benes + * Lukas Hejtmanek + * Petr Holub + * Milos Liska + * Jiri Matela + * Dalibor Matura <255899@mail.muni.cz> + * Ian Wesley-Smith + * + * Copyright (c) 2001-2004 University of Southern California + * Copyright (c) 2005-2010 CESNET z.s.p.o. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by the University of Southern + * California Information Sciences Institute. This product also includes + * software developed by CESNET z.s.p.o. + * + * 4. Neither the name of the University, Institute, CESNET nor the names of + * its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#include "config_unix.h" +#include "config_win32.h" +#endif // HAVE_CONFIG_H + +#ifdef HAVE_CRYPTO + +#include "crypto/crc.h" +#include "crypto/md5.h" +#include "crypto/openssl_decrypt.h" +#include "debug.h" + +#include +#include + +struct openssl_decrypt { + AES_KEY key; + + enum openssl_mode mode; + + unsigned char ivec[AES_BLOCK_SIZE]; + unsigned char ecount[AES_BLOCK_SIZE]; + unsigned int num; +}; + +int openssl_decrypt_init(struct openssl_decrypt **state, + const char *passphrase, + enum openssl_mode mode) +{ + struct openssl_decrypt *s = + (struct openssl_decrypt *) + calloc(1, sizeof(struct openssl_decrypt)); + + MD5_CTX context; + unsigned char hash[16]; + + MD5Init(&context); + MD5Update(&context, (unsigned char *) passphrase, + strlen(passphrase)); + MD5Final(hash, &context); + + switch(mode) { + case MODE_AES128_ECB: + AES_set_decrypt_key(hash, 128, &s->key); + break; + case MODE_AES128_CTR: + AES_set_encrypt_key(hash, 128, &s->key); + break; + default: + abort(); + } + + s->mode = mode; + + *state = s; + return 0; +} + +void openssl_decrypt_destroy(struct openssl_decrypt *s) +{ + if(!s) + return; + free(s); +} + +static void openssl_decrypt_block(struct openssl_decrypt *s, + unsigned char *ciphertext, unsigned char *plaintext, const char *nonce_and_counter, + int len) +{ + if(nonce_and_counter) { + memcpy(s->ivec, nonce_and_counter, AES_BLOCK_SIZE); + s->num = 0; + } + + switch(s->mode) { + case MODE_AES128_ECB: + assert(len == AES_BLOCK_SIZE); + AES_ecb_encrypt(ciphertext, plaintext, + &s->key, AES_DECRYPT); + break; + case MODE_AES128_CTR: + AES_ctr128_encrypt(ciphertext, plaintext, len, &s->key, s->ivec, + s->ecount, &s->num); + break; + default: + abort(); + } +} + +int openssl_decrypt(struct openssl_decrypt *decrypt, + const char *ciphertext, int ciphertext_len, + const char *aad, int aad_len, + char *plaintext) +{ + UNUSED(ciphertext_len); + uint32_t data_len; + memcpy(&data_len, ciphertext, sizeof(uint32_t)); + ciphertext += sizeof(uint32_t); + + const char *nonce_and_counter = ciphertext; + ciphertext += 16; + uint32_t expected_crc; + uint32_t crc = 0xffffffff; + if(aad > 0) { + crc = crc32buf_with_oldcrc((char *) aad, aad_len, crc); + } + for(unsigned int i = 0; i < data_len; i += 16) { + int block_length = 16; + if(data_len - i < 16) block_length = data_len - i; +#ifdef HAVE_CRYPTO + openssl_decrypt_block(decrypt, + (unsigned char *) ciphertext + i, + (unsigned char *) plaintext + i, + nonce_and_counter, block_length); +#endif // HAVE_CRYPTO + nonce_and_counter = NULL; + crc = crc32buf_with_oldcrc((char *) plaintext + i, block_length, crc); + } +#ifdef HAVE_CRYPTO + openssl_decrypt_block(decrypt, + (unsigned char *) ciphertext + data_len, + (unsigned char *) &expected_crc, + 0, sizeof(uint32_t)); +#endif // HAVE_CRYPTO + if(crc != expected_crc) { + return 0; + } + return data_len; +} + +#endif // HAVE_CRYPTO + diff --git a/src/crypto/openssl_decrypt.h b/src/crypto/openssl_decrypt.h new file mode 100644 index 000000000..12dfcbccf --- /dev/null +++ b/src/crypto/openssl_decrypt.h @@ -0,0 +1,93 @@ +/* + * FILE: openssl_encrypt.h + * AUTHOR: Colin Perkins + * Martin Benes + * Lukas Hejtmanek + * Petr Holub + * Milos Liska + * Jiri Matela + * Dalibor Matura <255899@mail.muni.cz> + * Ian Wesley-Smith + * + * Copyright (c) 2001-2002 University of Southern California + * Copyright (c) 2005-2010 CESNET z.s.p.o. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by the University of Southern + * California Information Sciences Institute. This product also includes + * software developed by CESNET z.s.p.o. + * + * 4. Neither the name of the University, Institute, CESNET nor the names of + * its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef OPENSSL_DECRYPT_H_ +#define OPENSSL_DECRYPT_H_ + +#include "crypto/openssl_encrypt.h" + +struct openssl_decrypt; + +/** + * Creates decryption state + * + * @param[out] state state pointer + * @param[in] passphrase key material (NULL-terminated) + * @param[in] mode mode + * @retval 0 ok + * @retval <0 failure + * @retval >0 state was not created + */ +int openssl_decrypt_init(struct openssl_decrypt **state, + const char *passphrase, enum openssl_mode mode); +/** + * Destroys decryption state + */ +void openssl_decrypt_destroy(struct openssl_decrypt *state); +/** + * Decrypts block of data + * + * @param[in] decrypt decrypt state + * @param[in] ciphertext encrypted text + * @param[in] ciphertext_len lenght of encrypted text + * @param[in] aad Aditional Authenticated Data (see openssl_encrypt documentation) + * @param[in] aad_len length of aad block + * @param[out] plaintext otput plaintext + * @retval 0 if checksum doesn't match + * @retval >0 length of output plaintext + */ +int openssl_decrypt(struct openssl_decrypt *decrypt, + const char *ciphertext, int ciphertext_len, + const char *aad, int aad_len, + char *plaintext); + +#endif // OPENSSL_DECRYPT_H_ + diff --git a/src/crypto/openssl_encrypt.c b/src/crypto/openssl_encrypt.c new file mode 100644 index 000000000..45019eadb --- /dev/null +++ b/src/crypto/openssl_encrypt.c @@ -0,0 +1,186 @@ +/* + * FILE: aes_encrypt.c + * AUTHOR: Colin Perkins + * Ladan Gharai + * Martin Benes + * Lukas Hejtmanek + * Petr Holub + * Milos Liska + * Jiri Matela + * Dalibor Matura <255899@mail.muni.cz> + * Ian Wesley-Smith + * + * Copyright (c) 2001-2004 University of Southern California + * Copyright (c) 2005-2010 CESNET z.s.p.o. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by the University of Southern + * California Information Sciences Institute. This product also includes + * software developed by CESNET z.s.p.o. + * + * 4. Neither the name of the University, Institute, CESNET nor the names of + * its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#include "config_unix.h" +#include "config_win32.h" +#endif + +#ifdef HAVE_CRYPTO + +#include "crypto/crc.h" +#include "crypto/md5.h" +#include "crypto/openssl_encrypt.h" + +#include +#include +#include + +struct openssl_encrypt { + AES_KEY key; + + enum openssl_mode mode; + + unsigned char ivec[16]; + unsigned int num; + unsigned char ecount[16]; +}; + +int openssl_encrypt_init(struct openssl_encrypt **state, const char *passphrase, + enum openssl_mode mode) +{ + struct openssl_encrypt *s = (struct openssl_encrypt *) + calloc(1, sizeof(struct openssl_encrypt)); + + MD5_CTX context; + unsigned char hash[16]; + + if (!RAND_bytes(s->ivec, 8)) { + return -1; + } + + MD5Init(&context); + MD5Update(&context, (unsigned char *) passphrase, + strlen(passphrase)); + MD5Final(hash, &context); + + AES_set_encrypt_key(hash, 128, &s->key); + s->mode = mode; + assert(s->mode == MODE_AES128_CTR); // only functional by now + + *state = s; + return 0; +} + +static void openssl_encrypt_block(struct openssl_encrypt *s, unsigned char *plaintext, + unsigned char *ciphertext, char *nonce_plus_counter, int len) +{ + if(nonce_plus_counter) { + memcpy(nonce_plus_counter, (char *) s->ivec, 16); + /* We do start a new block so we zero the byte counter + * Please NB that counter doesn't need to be incremented + * because the counter is incremented everytime s->num == 0, + * presumably before encryption, so setting it to 0 forces + * counter increment as well. + */ + if(s->num != 0) { + s->num = 0; + } + } + + switch(s->mode) { + case MODE_AES128_CTR: + AES_ctr128_encrypt(plaintext, ciphertext, len, &s->key, s->ivec, + s->ecount, &s->num); + break; + case MODE_AES128_ECB: + assert(len == AES_BLOCK_SIZE); + AES_ecb_encrypt(plaintext, ciphertext, + &s->key, AES_ENCRYPT); + break; + } +} + +void openssl_encrypt_destroy(struct openssl_encrypt *s) +{ + free(s); +} + +int openssl_encrypt(struct openssl_encrypt *encryption, + char *plaintext, int data_len, char *aad, int aad_len, char *ciphertext) { + uint32_t crc = 0xffffffff; + memcpy(ciphertext, &data_len, sizeof(uint32_t)); + ciphertext += sizeof(uint32_t); + char *nonce_and_counter = ciphertext; + ciphertext += 16; + + if(aad_len > 0) { + crc = crc32buf_with_oldcrc(aad, aad_len, crc); + } + + for(int i = 0; i < data_len; i+=16) { + int block_length = 16; + if(data_len - i < 16) block_length = data_len - i; + crc = crc32buf_with_oldcrc(plaintext + i, block_length, crc); +#ifdef HAVE_CRYPTO + openssl_encrypt_block(encryption, + (unsigned char *) plaintext + i, + (unsigned char *) ciphertext + i, + nonce_and_counter, + block_length); + nonce_and_counter = NULL; +#endif // HAVE_CRYPTO + } +#ifdef HAVE_CRYPTO + openssl_encrypt_block(encryption, + (unsigned char *) &crc, + (unsigned char *) ciphertext + data_len, + NULL, + sizeof(uint32_t)); +#endif // HAVE_CRYPTO + return data_len + sizeof(crc) + 16 + sizeof(uint32_t); +} + +int openssl_get_overhead(struct openssl_encrypt *s) +{ + switch(s->mode) { + case MODE_AES128_CTR: + return sizeof(uint32_t) /* data_len */ + + 16 /* nonce + counter */ + sizeof(uint32_t) /* crc */; + default: + abort(); + } +} + +#endif // HAVE_CRYPTO + diff --git a/src/crypto/openssl_encrypt.h b/src/crypto/openssl_encrypt.h new file mode 100644 index 000000000..af75aba3d --- /dev/null +++ b/src/crypto/openssl_encrypt.h @@ -0,0 +1,113 @@ +/* + * FILE: aes_encrypt.h + * AUTHOR: Colin Perkins + * Martin Benes + * Lukas Hejtmanek + * Petr Holub + * Milos Liska + * Jiri Matela + * Dalibor Matura <255899@mail.muni.cz> + * Ian Wesley-Smith + * + * Copyright (c) 2001-2002 University of Southern California + * Copyright (c) 2005-2010 CESNET z.s.p.o. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by the University of Southern + * California Information Sciences Institute. This product also includes + * software developed by CESNET z.s.p.o. + * + * 4. Neither the name of the University, Institute, CESNET nor the names of + * its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef OPENSSL_ENCRYPT_H_ +#define OPENSSL_ENCRYPT_H_ + +#ifdef __cplusplus +extern "C" { +#endif +struct openssl_encrypt; + +enum openssl_mode { + MODE_AES128_CTR, // no autenticity, only integrity (CRC) + MODE_AES128_ECB // do not use +}; + +#define MAX_CRYPTO_EXTRA_DATA 24 // == maximal overhead of available encryptions +#define MAX_CRYPTO_PAD 0 // CTR does not need padding +#define MAX_CRYPTO_EXCEED (MAX_CRYPTO_EXTRA_DATA + MAX_CRYPTO_PAD) + +/** + * Initializes encryption + * @param[out] state created state + * @param[in] passphrase key material (NULL-terminated) + * @param[in] mode + * @retval 0 success + * @retval <0 failure + * @retval >0 state not created + */ +int openssl_encrypt_init(struct openssl_encrypt **state, + const char *passphrase, enum openssl_mode mode); +/** + * Destroys state + */ +void openssl_encrypt_destroy(struct openssl_encrypt *state); +/** + * Encrypts a block of data + * + * @param[in] encryption state + * @param[in] plaintext plain text + * @param[in] plaintext_len length of plain text + * @param[in] aad Additional Authenticated Data + * this won't be encrypted but passed in plaintext along ciphertext. + * These data are autheticated only if working in some AE mode + * @param[in] aad_len length of AAD text + * @param[out] ciphertext resulting ciphertext, can be up to (plaintext_len + MAX_CRYPTO_EXCEED) length + * @returns size of writen ciphertext + */ +int openssl_encrypt(struct openssl_encrypt *encryption, + char *plaintext, int plaintext_len, char *aad, int aad_len, char *ciphertext); +/** + * Returns maximal number of bytest that the ciphertext length may exceed plaintext for selected + * encryption. + * + * @param[in] encryption state + * @returns max overhead (must be <= MAX_CRYPTO_EXCEED) + */ +int openssl_get_overhead(struct openssl_encrypt *encryption); + +#ifdef __cplusplus +} +#endif + +#endif // OPENSSL_ENCRYPT_H_ + diff --git a/src/hd-rum-translator/hd-rum-recompress.cpp b/src/hd-rum-translator/hd-rum-recompress.cpp index aefeb54c9..466927331 100644 --- a/src/hd-rum-translator/hd-rum-recompress.cpp +++ b/src/hd-rum-translator/hd-rum-recompress.cpp @@ -171,7 +171,8 @@ void *recompress_init(struct module *parent, s->required_compress = strdup(compress); s->frame = NULL; - s->tx = tx_init(s->parent, mtu, TX_MEDIA_VIDEO, fec); + const char *requested_encryption = NULL; + s->tx = tx_init(s->parent, mtu, TX_MEDIA_VIDEO, fec, requested_encryption); gettimeofday(&s->start_time, NULL); diff --git a/src/main.c b/src/main.c index d139b4bab..f5527465e 100644 --- a/src/main.c +++ b/src/main.c @@ -122,6 +122,7 @@ #define OPT_IMPORT (('I' << 8) | 'M') #define OPT_AUDIO_CODEC (('A' << 8) | 'C') #define OPT_CAPTURE_FILTER (('O' << 8) | 'F') +#define OPT_ENCRYPTION (('E' << 8) | 'N') #ifdef HAVE_MACOSX #define INITIAL_VIDEO_RECV_BUFFER_SIZE 5944320 @@ -162,6 +163,12 @@ struct state_uv { pthread_mutex_t master_lock; struct video_export *video_exporter; + + struct sender_data sender_data; + + struct module *root_module; + + const char *requested_encryption; }; static volatile int wait_to_finish = FALSE; @@ -309,6 +316,8 @@ static void usage(void) printf("\n"); printf("\t--capture-filter \tCapture filter(s)\n"); printf("\n"); + printf("\t--encryption \tKey material for encryption\n"); + printf("\n"); printf("\taddress(es) \tdestination address\n"); printf("\n"); printf("\t \tIf comma-separated list of addresses\n"); @@ -454,13 +463,6 @@ static void destroy_devices(struct rtp ** network_devices) free(network_devices); } -static struct tx *initialize_transmit(struct module *parent, unsigned requested_mtu, char *fec) -{ - /* Currently this is trivial. It'll get more complex once we */ - /* have multiple codecs and/or error correction. */ - return tx_init(parent, requested_mtu, TX_MEDIA_VIDEO, fec); -} - #ifdef HAVE_IHDTV static void *ihdtv_receiver_thread(void *arg) { @@ -504,7 +506,8 @@ static struct vcodec_state *new_decoder(struct state_uv *uv) { if(state) { state->messages = simple_linked_list_init(); - state->decoder = decoder_init(uv->decoder_mode, uv->postprocess, uv->display_device); + state->decoder = decoder_init(uv->decoder_mode, uv->postprocess, uv->display_device, + uv->requested_encryption); if(!state->decoder) { fprintf(stderr, "Error initializing decoder (incorrect '-M' or '-p' option?).\n"); @@ -563,7 +566,11 @@ static void *receiver_thread(void *arg) fr = 1; - stat_loss = stats_new_statistics("loss"); + struct module *control_mod = get_module(get_root_module(uv->root_module), "control"); + stat_loss = stats_new_statistics( + (struct control_state *) control_mod, + "loss"); + unlock_module(control_mod); while (!should_exit_receiver) { /* Housekeeping and RTCP... */ @@ -712,7 +719,6 @@ static void *compress_thread(void *arg) { struct module *uv_mod = (struct module *)arg; struct state_uv *uv = (struct state_uv *) uv_mod->priv_data; - struct sender_data sender_data; struct video_frame *tx_frame; struct audio_frame *audio; @@ -722,17 +728,17 @@ static void *compress_thread(void *arg) struct compress_state *compression; int ret = compress_init(uv_mod, uv->requested_compression, &compression); - sender_data.parent = uv_mod; /// @todo should be compress thread module - sender_data.connections_count = uv->connections_count; - sender_data.tx_protocol = uv->tx_protocol; + uv->sender_data.parent = uv_mod; /// @todo should be compress thread module + uv->sender_data.connections_count = uv->connections_count; + uv->sender_data.tx_protocol = uv->tx_protocol; if(uv->tx_protocol == ULTRAGRID_RTP) { - sender_data.network_devices = uv->network_devices; + uv->sender_data.network_devices = uv->network_devices; } else { - sender_data.sage_tx_device = uv->sage_tx_device; + uv->sender_data.sage_tx_device = uv->sage_tx_device; } - sender_data.tx = uv->tx; + uv->sender_data.tx = uv->tx; - if(!sender_init(&sender_data)) { + if(!sender_init(&uv->sender_data)) { fprintf(stderr, "Error initializing sender.\n"); exit_uv(1); pthread_mutex_unlock(&uv->master_lock); @@ -780,13 +786,13 @@ static void *compress_thread(void *arg) nonblock = false; } - sender_post_new_frame(&sender_data, tx_frame, nonblock); + sender_post_new_frame(&uv->sender_data, tx_frame, nonblock); } } vidcap_finish(uv_state->capture_device); - sender_done(&sender_data); + sender_done(&uv->sender_data); compress_done: module_done(CAST_MODULE(compression)); @@ -933,12 +939,13 @@ int main(int argc, char *argv[]) {"audio-host", required_argument, 0, 'A'}, {"audio-codec", required_argument, 0, OPT_AUDIO_CODEC}, {"capture-filter", required_argument, 0, OPT_CAPTURE_FILTER}, + {"encryption", required_argument, 0, OPT_ENCRYPTION}, {0, 0, 0, 0} }; int option_index = 0; // uv = (struct state_uv *) calloc(1, sizeof(struct state_uv)); - uv = (struct state_uv *)malloc(sizeof(struct state_uv)); + uv = (struct state_uv *) calloc(1, sizeof(struct state_uv)); uv_state = uv; uv->audio = NULL; @@ -962,6 +969,7 @@ int main(int argc, char *argv[]) uv->sage_tx_device = NULL; init_root_module(&root_mod, uv); + uv->root_module = &root_mod; pthread_mutex_init(&uv->master_lock, NULL); @@ -1178,6 +1186,9 @@ int main(int argc, char *argv[]) case OPT_CAPTURE_FILTER: requested_capture_filter = optarg; break; + case OPT_ENCRYPTION: + uv->requested_encryption = optarg; + break; case '?': default: usage(); @@ -1225,6 +1236,10 @@ int main(int argc, char *argv[]) audio_rx_port = uv->recv_port_number + 2; } + if(control_init(CONTROL_DEFAULT_PORT, &control, &root_mod) != 0) { + fprintf(stderr, "Warning: Unable to initialize remote control!\n:"); + } + if(should_export) { if(!enable_export(export_opts)) { fprintf(stderr, "Export initialization failed.\n"); @@ -1281,7 +1296,8 @@ int main(int argc, char *argv[]) } uv->audio = audio_cfg_init (&root_mod, audio_host, audio_rx_port, audio_tx_port, audio_send, audio_recv, - jack_cfg, requested_audio_fec, audio_channel_map, + jack_cfg, requested_audio_fec, uv->requested_encryption, + audio_channel_map, audio_scale, echo_cancellation, use_ipv6, mcast_if, audio_codec, compressed_audio_sample_rate); free(requested_audio_fec); @@ -1445,8 +1461,10 @@ int main(int argc, char *argv[]) packet_rate = 0; } - if ((uv->tx = initialize_transmit(&root_mod, - uv->requested_mtu, requested_video_fec)) == NULL) { + if ((uv->tx = tx_init(&root_mod, + uv->requested_mtu, TX_MEDIA_VIDEO, + requested_video_fec, + uv->requested_encryption)) == NULL) { printf("Unable to initialize transmitter.\n"); exit_uv(EXIT_FAIL_TRANSMIT); goto cleanup_wait_display; @@ -1469,7 +1487,8 @@ int main(int argc, char *argv[]) /* following block only shows help (otherwise initialized in receiver thread */ if((uv->postprocess && strstr(uv->postprocess, "help") != NULL) || (uv->decoder_mode && strstr(uv->decoder_mode, "help") != NULL)) { - struct state_decoder *dec = decoder_init(uv->decoder_mode, uv->postprocess, NULL); + struct state_decoder *dec = decoder_init(uv->decoder_mode, uv->postprocess, NULL, + uv->requested_encryption); decoder_destroy(dec); exit_uv(EXIT_SUCCESS); goto cleanup_wait_display; @@ -1518,10 +1537,6 @@ int main(int argc, char *argv[]) pthread_mutex_lock(&uv->master_lock); - if(control_init(CONTROL_DEFAULT_PORT, &control, &root_mod) != 0) { - fprintf(stderr, "Warning: Unable to initialize remote control!\n:"); - } - if(audio_get_display_flags(uv->audio)) { audio_register_put_callback(uv->audio, (void (*)(void *, struct audio_frame *)) display_put_audio_frame, uv->display_device); audio_register_reconfigure_callback(uv->audio, (int (*)(void *, int, int, @@ -1595,6 +1610,8 @@ cleanup: control_done(control); + module_done(&root_mod); + printf("Exit\n"); return exit_status; diff --git a/src/messaging.cpp b/src/messaging.cpp index 14384508c..1670c3227 100644 --- a/src/messaging.cpp +++ b/src/messaging.cpp @@ -10,56 +10,10 @@ #include "utils/list.h" #include "utils/lock_guard.h" -static struct module *find_child(struct module *node, const char *node_name, int index) -{ - for(void *it = simple_linked_list_it_init(node->childs); it != NULL; ) { - struct module *child = (struct module *) simple_linked_list_it_next(&it); - if(strcasecmp(module_class_name(child->cls), node_name) == 0) { - if(index-- == 0) { - return child; - } - } - } - return NULL; -} - -static void get_receiver_index(char *node_str, int *index) { - *index = 0; - if(strchr(node_str, '[')) { - *index = atoi(strchr(node_str, '[') + 1); - *strchr(node_str, '[') = '\0'; - } -} - struct response *send_message(struct module *root, const char *const_path, struct message *msg) { - struct module *receiver = root; - char *path, *tmp; - char *item, *save_ptr; char buf[1024]; - - assert(root != NULL); - - pthread_mutex_lock(&receiver->lock); - - tmp = path = strdup(const_path); - while ((item = strtok_r(path, ".", &save_ptr))) { - struct module *old_receiver = receiver; - int index; - get_receiver_index(item, &index); - receiver = find_child(receiver, item, index); - if(!receiver) { - pthread_mutex_unlock(&old_receiver->lock); - break; - } - pthread_mutex_lock(&receiver->lock); - pthread_mutex_unlock(&old_receiver->lock); - - path = NULL; - - } - free(tmp); - + struct module *receiver = get_module(root, const_path); /** * @invariant * either receiver is NULL or receiver->lock is locked (exactly once) diff --git a/src/messaging.h b/src/messaging.h index 6b8783b41..076801139 100644 --- a/src/messaging.h +++ b/src/messaging.h @@ -50,12 +50,14 @@ struct msg_change_fec_data { char fec[128]; }; +enum compress_change_type { + CHANGE_COMPRESS, + CHANGE_PARAMS +}; + struct msg_change_compress_data { struct message m; - enum { - CHANGE_COMPRESS, - CHANGE_PARAMS - } what; + enum compress_change_type what; char config_string[128]; }; diff --git a/src/module.c b/src/module.c index f20ffc278..283cc18b3 100644 --- a/src/module.c +++ b/src/module.c @@ -124,6 +124,7 @@ const char *module_class_name_pairs[] = { [MODULE_CLASS_SENDER] = "sender", [MODULE_CLASS_TX] = "transmit", [MODULE_CLASS_AUDIO] = "audio", + [MODULE_CLASS_CONTROL] = "control", }; const char *module_class_name(enum module_class cls) @@ -150,3 +151,70 @@ void append_message_path(char *buf, int buflen, enum module_class modules[]) } } +struct module *get_root_module(struct module *node) +{ + while(node->parent) { + node = node->parent; + } + assert(node->cls == MODULE_CLASS_ROOT); + + return node; +} + +static struct module *find_child(struct module *node, const char *node_name, int index) +{ + for(void *it = simple_linked_list_it_init(node->childs); it != NULL; ) { + struct module *child = (struct module *) simple_linked_list_it_next(&it); + if(strcasecmp(module_class_name(child->cls), node_name) == 0) { + if(index-- == 0) { + return child; + } + } + } + return NULL; +} + +static void get_receiver_index(char *node_str, int *index) { + *index = 0; + if(strchr(node_str, '[')) { + *index = atoi(strchr(node_str, '[') + 1); + *strchr(node_str, '[') = '\0'; + } +} + +struct module *get_module(struct module *root, const char *const_path) +{ + struct module *receiver = root; + char *path, *tmp; + char *item, *save_ptr; + + assert(root != NULL); + + pthread_mutex_lock(&receiver->lock); + + tmp = path = strdup(const_path); + while ((item = strtok_r(path, ".", &save_ptr))) { + struct module *old_receiver = receiver; + int index; + get_receiver_index(item, &index); + receiver = find_child(receiver, item, index); + if(!receiver) { + pthread_mutex_unlock(&old_receiver->lock); + break; + } + pthread_mutex_lock(&receiver->lock); + pthread_mutex_unlock(&old_receiver->lock); + + path = NULL; + + } + free(tmp); + + return receiver; +} + +void unlock_module(struct module *module) +{ + pthread_mutex_unlock(&module->lock); +} + diff --git a/src/module.h b/src/module.h index f0913fffb..8ce742c9a 100644 --- a/src/module.h +++ b/src/module.h @@ -70,6 +70,7 @@ enum module_class { MODULE_CLASS_SENDER, MODULE_CLASS_TX, MODULE_CLASS_AUDIO, + MODULE_CLASS_CONTROL, }; struct module; @@ -77,6 +78,11 @@ struct simple_linked_list; typedef void (*module_deleter_t)(struct module *); +/** + * @struct module + * Only members cls, deleter, priv_data and msg_queue may be directly touched + * by user. The others should be considered private. + */ struct module { uint32_t magic; pthread_mutex_t lock; @@ -86,6 +92,7 @@ struct module { module_deleter_t deleter; /** + * @var msg_callback * Module may implement a push method that will respond synchronously to events. * If not, message will be enqueued to message queue. */ @@ -100,6 +107,25 @@ void module_register(struct module *module_data, struct module *parent); void module_done(struct module *module_data); const char *module_class_name(enum module_class cls); void append_message_path(char *buf, int buflen, enum module_class modules[]); +/** + * IMPORTANT: returned module will be locked on return and needs to be unlocked by caller + * when it is done! + * + * @retval NULL if not found + * @retval non-NULL pointer to the module + */ +struct module *get_module(struct module *root, const char *path); +/** + * @see get_module + * Caller of get_module should call this when done with module + */ +void unlock_module(struct module *module); +/** + * Returns pointer to root module. It WON'T be locked. + * + * @retval root module + */ +struct module *get_root_module(struct module *node); #define CAST_MODULE(x) ((struct module *) x) diff --git a/src/rtp/audio_decoders.c b/src/rtp/audio_decoders.c index 9d906e365..3773eab12 100644 --- a/src/rtp/audio_decoders.c +++ b/src/rtp/audio_decoders.c @@ -71,6 +71,8 @@ #include "audio/codec.h" #include "audio/resampler.h" #include "audio/utils.h" +#include "crypto/crc.h" +#include "crypto/openssl_decrypt.h" #include "utils/packet_counter.h" @@ -115,6 +117,8 @@ struct state_audio_decoder { uint32_t saved_audio_tag; int samples_decoded; + + struct openssl_decrypt *decrypt; }; static int validate_mapping(struct channel_map *map); @@ -168,7 +172,7 @@ static void compute_scale(struct scale_data *scale_data, float vol_avg, int samp } } -void *audio_decoder_init(char *audio_channel_map, const char *audio_scale) +void *audio_decoder_init(char *audio_channel_map, const char *audio_scale, const char *encryption) { struct state_audio_decoder *s; bool scale_auto = false; @@ -187,6 +191,19 @@ void *audio_decoder_init(char *audio_channel_map, const char *audio_scale) s->resampler = resampler_init(48000); + if(encryption) { +#ifdef HAVE_CRYPTO + if(openssl_decrypt_init(&s->decrypt, + encryption, MODE_AES128_CTR) != 0) { + fprintf(stderr, "Unable to create decompress!\n"); + return NULL; + } +#else + fprintf(stderr, "This " PACKAGE_NAME " version was build " + "without OpenSSL support!\n"); + return NULL; +#endif // HAVE_CRYPTO + } if(audio_channel_map) { char *save_ptr = NULL; @@ -311,6 +328,8 @@ void audio_decoder_destroy(void *state) audio_codec_done(s->audio_decompress); resampler_done(s->resampler); + openssl_decrypt_destroy(s->decrypt); + free(s); } @@ -333,12 +352,57 @@ int decode_audio_frame(struct coded_data *cdata, void *data) while (cdata != NULL) { char *data; // for definition see rtp_callbacks.h - uint32_t *hdr = (uint32_t *)(void *) cdata->data->data; - + uint32_t *audio_hdr = (uint32_t *)(void *) cdata->data->data; + uint32_t *encryption_hdr; + const int pt = cdata->data->pt; + + if(pt == PT_ENCRYPT_AUDIO) { + encryption_hdr = (uint32_t *)((void *) cdata->data->data + + sizeof(audio_payload_hdr_t)); + if(!decoder->decrypt) { + fprintf(stderr, "Receiving encrypted audio data but " + "no decryption key entered!\n"); + ret = false; goto cleanup; + } + } else if(pt == PT_AUDIO) { + if(decoder->decrypt) { + fprintf(stderr, "Receiving unencrypted audio data " + "while expecting encrypted.\n"); + ret = false; goto cleanup; + } + } else { + fprintf(stderr, "Unknown audio packet type: %d\n", pt); + abort(); + } + + unsigned int length; + char plaintext[cdata->data->data_len]; // plaintext will be actually shorter + if(pt == PT_AUDIO) { + length = cdata->data->data_len - sizeof(audio_payload_hdr_t); + data = cdata->data->data + sizeof(audio_payload_hdr_t); + } else { + assert(pt == PT_ENCRYPT_AUDIO); + char *ciphertext = cdata->data->data + sizeof(crypto_payload_hdr_t) + + sizeof(audio_payload_hdr_t); + int ciphertext_len = cdata->data->data_len - sizeof(audio_payload_hdr_t) - + sizeof(crypto_payload_hdr_t); + + if((length = openssl_decrypt(decoder->decrypt, + ciphertext, ciphertext_len, + (char *) audio_hdr, sizeof(audio_payload_hdr_t), + plaintext + )) == 0) { + fprintf(stderr, "Warning: Packet dropped AES - wrong CRC!\n"); + ret = false; + goto cleanup; + } + data = plaintext; + } + /* we receive last channel first (with m bit, last packet) */ /* thus can be set only with m-bit packet */ if(cdata->data->m) { - input_channels = ((ntohl(hdr[0]) >> 22) & 0x3ff) + 1; + input_channels = ((ntohl(audio_hdr[0]) >> 22) & 0x3ff) + 1; } // we have: @@ -346,16 +410,19 @@ int decode_audio_frame(struct coded_data *cdata, void *data) // 2) not last, but the last one was processed at first assert(input_channels > 0); - channel = (ntohl(hdr[0]) >> 22) & 0x3ff; - int bufnum = ntohl(hdr[0]) & 0x3fffff; - sample_rate = ntohl(hdr[3]) & 0x3fffff; - bps = (ntohl(hdr[3]) >> 26) / 8; - uint32_t audio_tag = ntohl(hdr[4]); + channel = (ntohl(audio_hdr[0]) >> 22) & 0x3ff; + int bufnum = ntohl(audio_hdr[0]) & 0x3fffff; + sample_rate = ntohl(audio_hdr[3]) & 0x3fffff; + bps = (ntohl(audio_hdr[3]) >> 26) / 8; + uint32_t audio_tag = ntohl(audio_hdr[4]); - output_channels = decoder->channel_remapping ? decoder->channel_map.max_output + 1: input_channels; + output_channels = decoder->channel_remapping ? + decoder->channel_map.max_output + 1: input_channels; - /** - * TODO: obtain supported rates from device + /* + * Reconfiguration + * + * @todo obtain supported rates from device */ int device_sample_rate = 48000; int device_bps = 2; @@ -404,13 +471,9 @@ int decode_audio_frame(struct coded_data *cdata, void *data) return FALSE; } } - - data = cdata->data->data + sizeof(audio_payload_hdr_t); - - unsigned int length = cdata->data->data_len - sizeof(audio_payload_hdr_t); - unsigned int offset = ntohl(hdr[1]); - unsigned int buffer_len = ntohl(hdr[2]); + unsigned int offset = ntohl(audio_hdr[1]); + unsigned int buffer_len = ntohl(audio_hdr[2]); //fprintf(stderr, "%d-%d-%d ", length, bufnum, channel); diff --git a/src/rtp/audio_decoders.h b/src/rtp/audio_decoders.h index 99890129b..faa99e5b7 100644 --- a/src/rtp/audio_decoders.h +++ b/src/rtp/audio_decoders.h @@ -54,6 +54,7 @@ struct coded_data; int decode_audio_frame(struct coded_data *cdata, void *data); -void *audio_decoder_init(char *audio_channel_map, const char *audio_scale); +void *audio_decoder_init(char *audio_channel_map, const char *audio_scale, + const char *encryption); void audio_decoder_destroy(void *state); diff --git a/src/rtp/decoders.c b/src/rtp/decoders.c index 00250606e..037a9a2d5 100644 --- a/src/rtp/decoders.c +++ b/src/rtp/decoders.c @@ -44,6 +44,7 @@ #include "config_unix.h" #include "config_win32.h" #endif // HAVE_CONFIG_H +#include "crypto/openssl_decrypt.h" #include "debug.h" #include "host.h" #include "perf.h" @@ -170,6 +171,8 @@ struct state_decoder { double set_fps; // "message" passed to our master codec_t codec; bool slow; + + struct openssl_decrypt *decrypt; }; // message definitions @@ -202,7 +205,14 @@ static void wait_for_framebuffer_swap(struct state_decoder *decoder) { pthread_mutex_unlock(&decoder->lock); } +#define ENCRYPTED_ERR "Receiving encrypted video data but " \ + "no decryption key entered!\n" +#define NOT_ENCRYPTED_ERR "Receiving unencrypted video data " \ + "while expecting encrypted.\n" +#define SKIP_LDGM_FRAME ret = FALSE; goto cleanup; + static void *ldgm_thread(void *args) { + uint32_t tmp_ui32; struct state_decoder *decoder = args; struct fec fec_state; @@ -251,6 +261,7 @@ static void *ldgm_thread(void *args) { decompress_data->buffer_num = calloc(data->substream_count, sizeof(int)); memcpy(decompress_data->buffer_num, data->buffer_num, data->substream_count * sizeof(int)); memcpy(decompress_data->fec_buffers, data->recv_buffers, data->substream_count * sizeof(char *)); + if (data->pt == PT_VIDEO_LDGM) { if(!fec_state.state || fec_state.k != data->k || fec_state.m != data->m || @@ -274,70 +285,118 @@ static void *ldgm_thread(void *args) { } if (data->pt == PT_VIDEO_LDGM) { - int x,y; - for (x = 0; x < get_video_mode_tiles_x(decoder->video_mode) ; ++x) { - for (y = 0; y < get_video_mode_tiles_y(decoder->video_mode); ++y) { - int pos = x + get_video_mode_tiles_x(decoder->video_mode) * y; - char *out_buffer = NULL; - int out_len = 0; + int pos; + for (pos = 0; pos < get_video_mode_tiles_x(decoder->video_mode) + * get_video_mode_tiles_y(decoder->video_mode); ++pos) { + char *ldgm_out_buffer = NULL; + int ldgm_out_len = 0; - ldgm_decoder_decode(fec_state.state, data->recv_buffers[pos], - data->buffer_len[pos], - &out_buffer, &out_len, data->pckt_list[pos]); + ldgm_decoder_decode(fec_state.state, data->recv_buffers[pos], + data->buffer_len[pos], + &ldgm_out_buffer, &ldgm_out_len, data->pckt_list[pos]); - if(out_len == 0) { - ret = FALSE; - fprintf(stderr, "[decoder] LDGM: unable to reconstruct data.\n"); - goto cleanup; + if(ldgm_out_len == 0) { + ret = FALSE; + fprintf(stderr, "[decoder] LDGM: unable to reconstruct data.\n"); + goto cleanup; + } + + uint32_t ldgm_pt; + char *ldgm_hdr = ldgm_out_buffer; + memcpy(&ldgm_pt, ldgm_out_buffer, sizeof(ldgm_pt)); + ldgm_pt = htonl(ldgm_pt); + assert(ldgm_pt == PT_VIDEO || ldgm_pt == PT_ENCRYPT_VIDEO); + + video_payload_hdr_t video_hdr; + memcpy(&video_hdr, ldgm_out_buffer + sizeof(uint32_t), + sizeof(video_payload_hdr_t)); + ldgm_out_buffer += sizeof(video_payload_hdr_t) + sizeof(uint32_t); + ldgm_out_len -= sizeof(video_payload_hdr_t) + sizeof(uint32_t); + + if(ldgm_pt == PT_ENCRYPT_VIDEO) { + if(!decoder->decrypt) { + fprintf(stderr, ENCRYPTED_ERR); + SKIP_LDGM_FRAME } - check_for_mode_change(decoder, (uint32_t *)(void *) out_buffer, - &frame); + uint32_t *crypto_hdr = (uint32_t *)(void *) ldgm_out_buffer; + tmp_ui32 = ntohl(crypto_hdr[0]); + uint8_t crypto_type = tmp_ui32 >> 24; - if(!frame) { - ret = FALSE; - goto cleanup; + if(crypto_type != CRYPTO_TYPE_AES128_CTR) { + fprintf(stderr, "Unknown encryption!\n"); } - out_buffer += sizeof(video_payload_hdr_t); - out_len -= sizeof(video_payload_hdr_t); + int ciphertext_len = ldgm_out_len - + sizeof(crypto_payload_hdr_t); + char *plaintext = malloc(ciphertext_len); + char *ciphertext = (char *) + ldgm_out_buffer + sizeof(crypto_payload_hdr_t); + int plaintext_len; + if((plaintext_len = openssl_decrypt(decoder->decrypt, ciphertext, + ciphertext_len, + ldgm_hdr, sizeof(video_payload_hdr_t) + sizeof(uint32_t), + plaintext)) == 0) { + fprintf(stderr, "Warning: Packet dropped AES - wrong CRC!\n"); + free(plaintext); + ret = FALSE; goto cleanup; + } - if(decoder->decoder_type == EXTERNAL_DECODER) { - decompress_data->buffer_len[pos] = out_len; - decompress_data->decompress_buffer[pos] = out_buffer; - } else { // linedecoder - wait_for_framebuffer_swap(decoder); + free(data->recv_buffers[pos]); + decompress_data->fec_buffers[pos] = data->recv_buffers[pos] = + plaintext; - struct video_frame *out_frame; - int divisor; + ldgm_out_len = plaintext_len; + ldgm_out_buffer = plaintext; + } else { + if(decoder->decrypt) { + fprintf(stderr, NOT_ENCRYPTED_ERR); + SKIP_LDGM_FRAME + } + } - if(!decoder->postprocess) { - out_frame = frame; - } else { - out_frame = decoder->pp_frame; - } + check_for_mode_change(decoder, video_hdr, + &frame); - if (!decoder->merged_fb) { - divisor = decoder->max_substreams; - } else { - divisor = 1; - } + if(!frame) { + SKIP_LDGM_FRAME + } - tile = vf_get_tile(out_frame, pos % divisor); + if(decoder->decoder_type == EXTERNAL_DECODER) { + decompress_data->buffer_len[pos] = ldgm_out_len; + decompress_data->decompress_buffer[pos] = ldgm_out_buffer; + } else { // linedecoder + wait_for_framebuffer_swap(decoder); - struct line_decoder *line_decoder = - &decoder->line_decoder[pos]; + struct video_frame *out_frame; + int divisor; - int data_pos = 0; - char *src = out_buffer; - char *dst = tile->data + line_decoder->base_offset; - while(data_pos < (int) out_len) { - line_decoder->decode_line((unsigned char*)dst, (unsigned char *) src, line_decoder->src_linesize, - line_decoder->rshift, line_decoder->gshift, - line_decoder->bshift); - src += line_decoder->src_linesize; - dst += vc_get_linesize(tile->width ,frame->color_spec); - data_pos += line_decoder->src_linesize; - } + if(!decoder->postprocess) { + out_frame = frame; + } else { + out_frame = decoder->pp_frame; + } + + if (!decoder->merged_fb) { + divisor = decoder->max_substreams; + } else { + divisor = 1; + } + + tile = vf_get_tile(out_frame, pos % divisor); + + struct line_decoder *line_decoder = + &decoder->line_decoder[pos]; + + int data_pos = 0; + char *src = ldgm_out_buffer; + char *dst = tile->data + line_decoder->base_offset; + while(data_pos < (int) ldgm_out_len) { + line_decoder->decode_line((unsigned char*)dst, (unsigned char *) src, line_decoder->src_linesize, + line_decoder->rshift, line_decoder->gshift, + line_decoder->bshift); + src += line_decoder->src_linesize; + dst += vc_get_linesize(tile->width ,frame->color_spec); + data_pos += line_decoder->src_linesize; } } } @@ -553,7 +612,7 @@ static void decoder_set_video_mode(struct state_decoder *decoder, unsigned int v } struct state_decoder *decoder_init(const char *requested_mode, const char *postprocess, - struct display *display) + struct display *display, const char *encryption) { struct state_decoder *s; @@ -577,6 +636,20 @@ struct state_decoder *decoder_init(const char *requested_mode, const char *postp int video_mode = VIDEO_NORMAL; + if(encryption) { +#ifdef HAVE_CRYPTO + if(openssl_decrypt_init(&s->decrypt, + encryption, MODE_AES128_CTR) != 0) { + fprintf(stderr, "Unable to create decompress!\n"); + return NULL; + } +#else + fprintf(stderr, "This " PACKAGE_NAME " version was build " + "without OpenSSL support!\n"); + return NULL; +#endif // HAVE_CRYPTO + } + if(requested_mode) { /* these are data comming from newtork ! */ if(strcasecmp(requested_mode, "help") == 0) { @@ -765,6 +838,8 @@ void decoder_destroy(struct state_decoder *decoder) if(!decoder) return; + openssl_decrypt_destroy(decoder->decrypt); + decoder_remove_display(decoder); pthread_mutex_destroy(&decoder->lock); @@ -1292,6 +1367,8 @@ static int check_for_mode_change(struct state_decoder *decoder, uint32_t *hdr, s return ret; } +#define SKIP_PACKET ret = FALSE; goto cleanup; + int decode_frame(struct coded_data *cdata, void *decode_data) { struct vcodec_state *pbuf_data = (struct vcodec_state *) decode_data; @@ -1348,13 +1425,14 @@ int decode_frame(struct coded_data *cdata, void *decode_data) } int pt; + int contained_pt; // if packed is encrypted it encapsulates other pt bool buffer_swapped = false; while (cdata != NULL) { uint32_t *hdr; pckt = cdata->data; - pt = pckt->pt; + contained_pt = pt = pckt->pt; hdr = (uint32_t *)(void *) pckt->data; data_pos = ntohl(hdr[1]); tmp = ntohl(hdr[0]); @@ -1366,6 +1444,10 @@ int decode_frame(struct coded_data *cdata, void *decode_data) if(pt == PT_VIDEO) { len = pckt->data_len - sizeof(video_payload_hdr_t); data = (char *) hdr + sizeof(video_payload_hdr_t); + if(decoder->decrypt) { + fprintf(stderr, NOT_ENCRYPTED_ERR); + SKIP_PACKET + } } else if (pt == PT_VIDEO_LDGM) { len = pckt->data_len - sizeof(ldgm_video_payload_hdr_t); data = (char *) hdr + sizeof(ldgm_video_payload_hdr_t); @@ -1375,6 +1457,16 @@ int decode_frame(struct coded_data *cdata, void *decode_data) m = 0x1fff & (tmp >> 6); c = 0x3f & tmp; seed = ntohl(hdr[4]); + } else if (pt == PT_ENCRYPT_VIDEO) { + len = pckt->data_len - sizeof(video_payload_hdr_t) + - sizeof(crypto_payload_hdr_t); + data = (char *) hdr + sizeof(video_payload_hdr_t) + + sizeof(crypto_payload_hdr_t); + contained_pt = PT_VIDEO; + if(!decoder->decrypt) { + fprintf(stderr, ENCRYPTED_ERR); + SKIP_PACKET + } } else { fprintf(stderr, "[decoder] Unknown packet type: %d.\n", pckt->pt); exit_uv(1); @@ -1411,23 +1503,38 @@ int decode_frame(struct coded_data *cdata, void *decode_data) buffer_num[substream] = buffer_number; buffer_len[substream] = buffer_length; - - ll_insert(pckt_list[substream], data_pos, len); - if (pt == PT_VIDEO) { - /* Critical section - * each thread *MUST* wait here if this condition is true - */ - check_for_mode_change(decoder, (uint32_t *)(void *) - pckt->data, &frame); + uint32_t *video_header = hdr; + + char plaintext[len]; // will be actually shorter + if(pt == PT_ENCRYPT_VIDEO) { + int data_len; + + if((data_len = openssl_decrypt(decoder->decrypt, + data, len, + (char *) video_header, sizeof(video_payload_hdr_t), + plaintext)) == 0) { + fprintf(stderr, "Warning: Packet dropped AES - wrong CRC!\n"); + goto next_packet; + } + data = (char *) plaintext; + len = data_len; } - if(pt == PT_VIDEO && !frame) { + if(contained_pt == PT_VIDEO) { + /* Critical section + * each thread *MUST* wait here if this condition is true + */ + check_for_mode_change(decoder, video_header, &frame); + } + if(contained_pt == PT_VIDEO && !frame) { ret = FALSE; goto cleanup; } - if (pt == PT_VIDEO && decoder->decoder_type == LINE_DECODER) { + ll_insert(pckt_list[substream], data_pos, len); + + if (contained_pt == PT_VIDEO && decoder->decoder_type == LINE_DECODER) { if(!buffer_swapped) { wait_for_framebuffer_swap(decoder); buffer_swapped = true; @@ -1528,6 +1635,7 @@ int decode_frame(struct coded_data *cdata, void *decode_data) len); } +next_packet: cdata = cdata->nxt; } @@ -1549,7 +1657,7 @@ int decode_frame(struct coded_data *cdata, void *decode_data) ldgm_data->c = c; ldgm_data->seed = seed; ldgm_data->substream_count = decoder->max_substreams; - ldgm_data->pt = pt; + ldgm_data->pt = contained_pt; ldgm_data->poisoned = false; memcpy(ldgm_data->buffer_len, buffer_len, sizeof(buffer_len)); memcpy(ldgm_data->buffer_num, buffer_num, sizeof(buffer_num)); diff --git a/src/rtp/decoders.h b/src/rtp/decoders.h index 69034c574..cb8b2e624 100644 --- a/src/rtp/decoders.h +++ b/src/rtp/decoders.h @@ -56,7 +56,7 @@ struct tile; int decode_frame(struct coded_data *compressed_frame, void *decode_data); struct state_decoder *decoder_init(const char *requested_mode, const char *postprocess, - struct display *display); + struct display *display, const char *encryption); void decoder_destroy(struct state_decoder *decoder); bool decoder_register_video_display(struct state_decoder *decoder, struct display *display); diff --git a/src/rtp/rtp_callback.h b/src/rtp/rtp_callback.h index e647cc396..3f4c9f0e5 100644 --- a/src/rtp/rtp_callback.h +++ b/src/rtp/rtp_callback.h @@ -46,9 +46,11 @@ * Packet formats: * http://www.sitola.cz/files/4K-packet-format.pdf */ -#define PT_VIDEO 20 -#define PT_AUDIO 21 -#define PT_VIDEO_LDGM 22 +#define PT_VIDEO 20 +#define PT_AUDIO 21 +#define PT_VIDEO_LDGM 22 +#define PT_ENCRYPT_VIDEO 24 +#define PT_ENCRYPT_AUDIO 25 /* * Video payload @@ -101,6 +103,8 @@ typedef uint32_t video_payload_hdr_t[6]; */ typedef uint32_t audio_payload_hdr_t[5]; +typedef uint32_t ldgm_payload_hdr_t; + /* * LDGM video payload * @@ -124,8 +128,19 @@ typedef uint32_t audio_payload_hdr_t[5]; */ typedef uint32_t ldgm_video_payload_hdr_t[5]; +/* + * Crypto video payload + * + * 1st word + * bits 0 - 8 crypto type + * bits 9 - 31 currently unused + */ +#define CRYPTO_TYPE_AES128_CTR 1u +typedef uint32_t crypto_payload_hdr_t[1]; + void rtp_recv_callback(struct rtp *session, rtp_event *e); int handle_with_buffer(struct rtp *session,rtp_event *e); int check_for_frame_completion(struct rtp *); void process_packet_for_display(char *); void call_display_frame(void); + diff --git a/src/sender.c b/src/sender.c index 9626e87da..bdab1f0bc 100644 --- a/src/sender.c +++ b/src/sender.c @@ -231,7 +231,6 @@ static void *sender_thread(void *arg) { struct video_frame *splitted_frames = NULL; int tile_y_count; struct video_desc saved_vid_desc; - struct stats *stat_data_sent = stats_new_statistics("data"); tile_y_count = data->connections_count; memset(&saved_vid_desc, 0, sizeof(saved_vid_desc)); @@ -250,6 +249,11 @@ static void *sender_thread(void *arg) { pthread_mutex_unlock(&data->priv->lock); + struct module *control_mod = get_module(get_root_module(&data->priv->mod), "control"); + struct stats *stat_data_sent = stats_new_statistics((struct control_state *) + control_mod, "data"); + unlock_module(control_mod); + while(1) { pthread_mutex_lock(&data->priv->lock); struct video_frame *tx_frame = NULL; diff --git a/src/stats.cpp b/src/stats.cpp index 957c17836..87042b949 100644 --- a/src/stats.cpp +++ b/src/stats.cpp @@ -3,6 +3,7 @@ #include #include +#include "control.h" #include "compat/platform_spin.h" #include "debug.h" #include "messaging.h" @@ -14,49 +15,42 @@ using namespace std; -static struct response *messaging_callback(struct received_message *msg, void *udata); - struct stats { public: - stats(string name) { - m_name = name; - m_val = 0; + stats(string name, struct control_state *control) + : m_control(control), m_name(name), m_val(0) { + platform_spin_init(&m_spin); + control_add_stats(control, this); } ~stats() { + control_remove_stats(m_control, this); + platform_spin_destroy(&m_spin); } void update_int(int64_t val) { + platform_spin_lock(&m_spin); m_val = val; + platform_spin_unlock(&m_spin); } - struct response *process_message(void *msg) { - struct msg_stats *stats = (struct msg_stats *) msg; - - if(string(stats->what).compare(m_name) == 0) { - char buf[128]; - snprintf(buf, sizeof(buf), "%lu", m_val); - return new_response(RESPONSE_OK, strdup(buf)); - } else { - return NULL; - } + void get_stat(char *buffer, int buffer_len) { + platform_spin_lock(&m_spin); + snprintf(buffer, buffer_len, "%s %lu", m_name.c_str(), m_val); + platform_spin_unlock(&m_spin); } private: string m_name; int64_t m_val; void *m_messaging_subscribtion; + struct control_state *m_control; + platform_spin_t m_spin; }; -static struct response *messaging_callback(void *msg, struct module *mod) +struct stats *stats_new_statistics(struct control_state *control, char * name) { - stats *s = (stats *) mod->priv_data; - return s->process_message(msg); -} - -struct stats *stats_new_statistics(char * name) -{ - return new stats(string(name)); + return new stats(string(name), control); } void stats_update_int(struct stats *s, int64_t val) @@ -64,6 +58,11 @@ void stats_update_int(struct stats *s, int64_t val) return s->update_int(val); } +void stats_format(struct stats *s, char *buffer, int buffer_len) +{ + s->get_stat(buffer, buffer_len); +} + void stats_destroy(struct stats *s) { delete s; diff --git a/src/stats.h b/src/stats.h index 0022ee5d6..59566650c 100644 --- a/src/stats.h +++ b/src/stats.h @@ -11,8 +11,12 @@ extern "C" { #endif -struct stats *stats_new_statistics(char * name); +struct control_state; +struct stats; + +struct stats *stats_new_statistics(struct control_state *control, char * name); void stats_update_int(struct stats *, int64_t); +void stats_format(struct stats *s, char *buffer, int buffer_len); void stats_destroy(struct stats *); #ifdef __cplusplus diff --git a/src/transmit.c b/src/transmit.c index 96c357c73..553d9b838 100644 --- a/src/transmit.c +++ b/src/transmit.c @@ -62,7 +62,7 @@ #include "audio/audio.h" #include "audio/codec.h" #include "audio/utils.h" -#include "messaging.h" +#include "crypto/openssl_encrypt.h" #include "module.h" #include "rtp/ldgm.h" #include "rtp/rtp.h" @@ -72,7 +72,6 @@ #include "host.h" #include "video_codec.h" #include "compat/platform_spin.h" -#include "compat/platform_time.h" #define TRANSMIT_MAGIC 0xe80ab15f @@ -138,8 +137,9 @@ struct tx { int last_fragment; - void *messaging_subscription; platform_spin_t spin; + + struct openssl_encrypt *encryption; }; static bool fec_is_ldgm(struct tx *tx) @@ -180,11 +180,12 @@ static void tx_update(struct tx *tx, struct tile *tile) } } -struct tx *tx_init(struct module *parent, unsigned mtu, enum tx_media_type media_type, char *fec) +struct tx *tx_init(struct module *parent, unsigned mtu, enum tx_media_type media_type, + char *fec, const char *encryption) { struct tx *tx; - tx = (struct tx *)malloc(sizeof(struct tx)); + tx = (struct tx *) calloc(1, sizeof(struct tx)); if (tx != NULL) { module_init_default(&tx->mod); tx->mod.cls = MODULE_CLASS_TX; @@ -208,6 +209,20 @@ struct tx *tx_init(struct module *parent, unsigned mtu, enum tx_media_type media return NULL; } } + if(encryption) { +#ifdef HAVE_CRYPTO + if(openssl_encrypt_init(&tx->encryption, + encryption, MODE_AES128_CTR) != 0) { + fprintf(stderr, "Unable to initialize encryption\n"); + return NULL; + } +#else + fprintf(stderr, "This " PACKAGE_NAME " version was build " + "without OpenSSL support!\n"); + return NULL; +#endif // HAVE_CRYPTO + } + platform_spin_init(&tx->spin); module_register(&tx->mod, parent); @@ -372,17 +387,42 @@ tx_send_tile(struct tx *tx, struct video_frame *frame, int pos, struct rtp *rtp_ platform_spin_unlock(&tx->spin); } +static uint32_t format_interl_fps_hdr_row(enum interlacing_t interlacing, double input_fps) +{ + unsigned int fpsd, fd, fps, fi; + uint32_t tmp; + + tmp = interlacing << 29; + fps = round(input_fps); + fpsd = 1; + if(fabs(input_fps - round(input_fps) / 1.001) < 0.005) + fd = 1; + else + fd = 0; + fi = 0; + + tmp |= fps << 19; + tmp |= fpsd << 15; + tmp |= fd << 14; + tmp |= fi << 13; + return htonl(tmp); +} + static void tx_send_base(struct tx *tx, struct tile *tile, struct rtp *rtp_session, uint32_t ts, int send_m, - codec_t color_spec, double input_fps, + codec_t color_spec, double fps, enum interlacing_t interlacing, unsigned int substream, int fragment_offset) { int m, data_len; // see definition in rtp_callback.h - video_payload_hdr_t video_hdr; - ldgm_video_payload_hdr_t ldgm_hdr; + + uint32_t hdr_data[100]; + uint32_t *ldgm_payload_hdr = hdr_data; + uint32_t *video_hdr = ldgm_payload_hdr + 1; + uint32_t *ldgm_hdr = video_hdr + sizeof(video_payload_hdr_t)/sizeof(uint32_t); + uint32_t *encryption_hdr; int pt = PT_VIDEO; /* A value specified in our packet format */ char *data; unsigned int pos; @@ -395,11 +435,10 @@ tx_send_base(struct tx *tx, struct tile *tile, struct rtp *rtp_session, #endif long delta; uint32_t tmp; - unsigned int fps, fpsd, fd, fi; int mult_pos[FEC_MAX_MULT]; int mult_index = 0; int mult_first_sent = 0; - int hdrs_len = 40 + (sizeof(video_payload_hdr_t)); + int hdrs_len = 40 + (sizeof(video_payload_hdr_t)); // for computing max payload size char *data_to_send; int data_to_send_len; @@ -423,6 +462,24 @@ tx_send_base(struct tx *tx, struct tile *tile, struct rtp *rtp_session, m = 0; pos = 0; + char *rtp_hdr; + int rtp_hdr_len; + + if(tx->encryption && !fec_is_ldgm(tx)) { + /* + * Important + * Crypto and video header must be in specified order placed one right after + * the another since both will be sent as a RTP header. + */ + encryption_hdr = video_hdr + sizeof(video_payload_hdr_t)/sizeof(uint32_t); + + encryption_hdr[0] = htonl(CRYPTO_TYPE_AES128_CTR << 24); + hdrs_len += sizeof(crypto_payload_hdr_t) + openssl_get_overhead(tx->encryption); + rtp_hdr = (char *) video_hdr; + rtp_hdr_len = sizeof(crypto_payload_hdr_t) + sizeof(video_payload_hdr_t); + pt = PT_ENCRYPT_VIDEO; + } + video_hdr[3] = htonl(tile->width << 16 | tile->height); video_hdr[4] = get_fourcc(color_spec); video_hdr[2] = htonl(data_to_send_len); @@ -431,28 +488,39 @@ tx_send_base(struct tx *tx, struct tile *tile, struct rtp *rtp_session, video_hdr[0] = htonl(tmp); /* word 6 */ - tmp = interlacing << 29; - fps = round(input_fps); - fpsd = 1; - if(fabs(input_fps - round(input_fps) / 1.001) < 0.005) - fd = 1; - else - fd = 0; - fi = 0; - - tmp |= fps << 19; - tmp |= fpsd << 15; - tmp |= fd << 14; - tmp |= fi << 13; - video_hdr[5] = htonl(tmp); - - char *hdr; - int hdr_len; + video_hdr[5] = format_interl_fps_hdr_row(interlacing, fps); if(fec_is_ldgm(tx)) { hdrs_len = 40 + (sizeof(ldgm_video_payload_hdr_t)); - ldgm_encoder_encode(tx->fec_state, (char *) &video_hdr, sizeof(video_hdr), - tile->data, tile->data_len, &data_to_send, &data_to_send_len); + char *tmp_data = NULL; + char *ldgm_input_data; + int ldgm_input_len; + int ldgm_payload_hdr_len = sizeof(ldgm_payload_hdr_t) + sizeof(video_payload_hdr_t); + if(tx->encryption) { + ldgm_input_len = tile->data_len + sizeof(crypto_payload_hdr_t) + + MAX_CRYPTO_EXCEED; + ldgm_input_data = tmp_data = malloc(ldgm_input_len); + char *ciphertext = tmp_data + sizeof(crypto_payload_hdr_t); + encryption_hdr = (uint32_t *)(void *) tmp_data; + encryption_hdr[0] = htonl(CRYPTO_TYPE_AES128_CTR << 24); + ldgm_payload_hdr[0] = ntohl(PT_ENCRYPT_VIDEO); +#ifdef HAVE_CRYPTO + int ret = openssl_encrypt(tx->encryption, + tile->data, tile->data_len, + (char *) ldgm_payload_hdr, ldgm_payload_hdr_len, + ciphertext); +#endif + ldgm_input_len = sizeof(crypto_payload_hdr_t) + ret; + + } else { + ldgm_input_data = tile->data; + ldgm_input_len = tile->data_len; + ldgm_payload_hdr[0] = ntohl(PT_VIDEO); + } + ldgm_encoder_encode(tx->fec_state, (char *) ldgm_payload_hdr, + ldgm_payload_hdr_len, + ldgm_input_data, ldgm_input_len, &data_to_send, &data_to_send_len); + free(tmp_data); tmp = substream << 22; tmp |= 0x3fffff & tx->buffer; // see definition in rtp_callback.h @@ -466,11 +534,19 @@ tx_send_base(struct tx *tx, struct tile *tile, struct rtp *rtp_session, pt = PT_VIDEO_LDGM; - hdr = (char *) &ldgm_hdr; - hdr_len = sizeof(ldgm_hdr); + rtp_hdr = (char *) ldgm_hdr; + rtp_hdr_len = sizeof(ldgm_video_payload_hdr_t); + } else if(!tx->encryption) { + rtp_hdr = (char *) video_hdr; + rtp_hdr_len = sizeof(video_payload_hdr_t); + } + + uint32_t *hdr_offset; // data offset pointer - contains field that needs to be updated + // every cycle + if(fec_is_ldgm(tx)) { + hdr_offset = ldgm_hdr + 1; } else { - hdr = (char *) &video_hdr; - hdr_len = sizeof(video_hdr); + hdr_offset = video_hdr + 1; } do { @@ -480,11 +556,7 @@ tx_send_base(struct tx *tx, struct tile *tile, struct rtp *rtp_session, int offset = pos + fragment_offset; - video_hdr[1] = htonl(offset); - if(fec_is_ldgm(tx)) { - ldgm_hdr[1] = htonl(offset); - } - + *hdr_offset = htonl(offset); data = data_to_send + pos; data_len = tx->mtu - hdrs_len; @@ -498,14 +570,24 @@ tx_send_base(struct tx *tx, struct tile *tile, struct rtp *rtp_session, pos += data_len; GET_STARTTIME; if(data_len) { /* check needed for FEC_MULT */ + char encrypted_data[data_len + MAX_CRYPTO_EXCEED]; + + if(tx->encryption && tx->fec_scheme != FEC_LDGM) { + data_len = openssl_encrypt(tx->encryption, + data, data_len, + (char *) video_hdr, sizeof(video_payload_hdr_t), + encrypted_data); + data = encrypted_data; + } + rtp_send_data_hdr(rtp_session, ts, pt, m, 0, 0, - hdr, hdr_len, + rtp_hdr, rtp_hdr_len, data, data_len, 0, 0, 0); if(m && tx->fec_scheme != FEC_NONE) { int i; for(i = 0; i < 5; ++i) { rtp_send_data_hdr(rtp_session, ts, pt, m, 0, 0, - hdr, hdr_len, + rtp_hdr, rtp_hdr_len, data, data_len, 0, 0, 0); } } @@ -543,7 +625,7 @@ tx_send_base(struct tx *tx, struct tile *tile, struct rtp *rtp_session, */ void audio_tx_send(struct tx* tx, struct rtp *rtp_session, audio_frame2 * buffer) { - const int pt = PT_AUDIO; /* PT set for audio in our packet format */ + int pt; /* PT set for audio in our packet format */ unsigned int pos = 0u, m = 0u; int channel; @@ -551,7 +633,9 @@ void audio_tx_send(struct tx* tx, struct rtp *rtp_session, audio_frame2 * buffer int data_len; char *data; // see definition in rtp_callback.h - audio_payload_hdr_t payload_hdr; + uint32_t hdr_data[100]; + uint32_t *audio_hdr = hdr_data; + uint32_t *crypto_hdr = audio_hdr + sizeof(audio_payload_hdr_t) / sizeof(uint32_t); uint32_t timestamp; #ifdef HAVE_LINUX struct timespec start, stop; @@ -564,12 +648,21 @@ void audio_tx_send(struct tx* tx, struct rtp *rtp_session, audio_frame2 * buffer int mult_pos[FEC_MAX_MULT]; int mult_index = 0; int mult_first_sent = 0; + int rtp_hdr_len; platform_spin_lock(&tx->spin); timestamp = get_local_mediatime(); perf_record(UVP_SEND, timestamp); + if(tx->encryption) { + rtp_hdr_len = sizeof(crypto_payload_hdr_t) + sizeof(audio_payload_hdr_t); + pt = PT_ENCRYPT_AUDIO; + } else { + rtp_hdr_len = sizeof(audio_payload_hdr_t); + pt = PT_AUDIO; /* PT set for audio in our packet format */ + } + for(channel = 0; channel < buffer->ch_count; ++channel) { chan_data = buffer->data[channel]; @@ -586,17 +679,17 @@ void audio_tx_send(struct tx* tx, struct rtp *rtp_session, audio_frame2 * buffer uint32_t tmp; tmp = channel << 22; /* bits 0-9 */ tmp |= tx->buffer; /* bits 10-31 */ - payload_hdr[0] = htonl(tmp); + audio_hdr[0] = htonl(tmp); - payload_hdr[2] = htonl(buffer->data_len[channel]); + audio_hdr[2] = htonl(buffer->data_len[channel]); /* fourth word */ tmp = (buffer->bps * 8) << 26; tmp |= buffer->sample_rate; - payload_hdr[3] = htonl(tmp); + audio_hdr[3] = htonl(tmp); /* fifth word */ - payload_hdr[4] = htonl(get_audio_tag(buffer->codec)); + audio_hdr[4] = htonl(get_audio_tag(buffer->codec)); do { if(tx->fec_scheme == FEC_MULT) { @@ -610,15 +703,25 @@ void audio_tx_send(struct tx* tx, struct rtp *rtp_session, audio_frame2 * buffer if(channel == buffer->ch_count - 1) m = 1; } - payload_hdr[1] = htonl(pos); + audio_hdr[1] = htonl(pos); pos += data_len; GET_STARTTIME; if(data_len) { /* check needed for FEC_MULT */ + char encrypted_data[data_len + MAX_CRYPTO_EXCEED]; + if(tx->encryption) { + crypto_hdr[0] = htonl(CRYPTO_TYPE_AES128_CTR << 24); + data_len = openssl_encrypt(tx->encryption, + data, data_len, + (char *) audio_hdr, sizeof(audio_payload_hdr_t), + encrypted_data); + data = encrypted_data; + } + rtp_send_data_hdr(rtp_session, timestamp, pt, m, 0, /* contributing sources */ 0, /* contributing sources length */ - (char *) &payload_hdr, sizeof(payload_hdr), + (char *) audio_hdr, rtp_hdr_len, data, data_len, 0, 0, 0); } @@ -650,3 +753,4 @@ void audio_tx_send(struct tx* tx, struct rtp *rtp_session, audio_frame2 * buffer platform_spin_unlock(&tx->spin); } + diff --git a/src/transmit.h b/src/transmit.h index 5e4313e65..595b9a01a 100644 --- a/src/transmit.h +++ b/src/transmit.h @@ -64,7 +64,8 @@ enum tx_media_type { TX_MEDIA_VIDEO }; -struct tx *tx_init(struct module *parent, unsigned mtu, enum tx_media_type media_type, char *fec); +struct tx *tx_init(struct module *parent, unsigned mtu, enum tx_media_type media_type, + char *fec, const char *encryption); void tx_send_tile(struct tx *tx_session, struct video_frame *frame, int pos, struct rtp *rtp_session); void tx_send(struct tx *tx_session, struct video_frame *frame, struct rtp *rtp_session); void audio_tx_send(struct tx *tx_session, struct rtp *rtp_session, audio_frame2 *buffer); diff --git a/src/video_compress/jpeg.c b/src/video_compress/jpeg.c index e80f205bc..2493342ac 100644 --- a/src/video_compress/jpeg.c +++ b/src/video_compress/jpeg.c @@ -59,7 +59,6 @@ #include "video_compress/jpeg.h" #include "libgpujpeg/gpujpeg_encoder.h" #include "libgpujpeg/gpujpeg_common.h" -#include "messaging.h" #include "video_codec.h" #include #include @@ -80,7 +79,6 @@ struct compress_jpeg_state { struct video_desc saved_desc; int restart_interval; - void *messaging_subscription; platform_spin_t spin; };