Browse Source

modified partial aes encrypt function to be able to decrypt/encrypt 'future' packets, fixed spacing, added webm checks

cecylia 6 years ago
parent
commit
089644b189

+ 26 - 10
relay_station/crypto.c

@@ -1626,30 +1626,35 @@ static int check_tag(byte key[16], const byte privkey[PTWIST_BYTES],
 #define GCM_CTX_LEN 380 + sizeof(block128_f)
 
 int partial_aes_gcm_tls_cipher(flow *f, unsigned char *out,
-        const unsigned char *in, size_t len, uint8_t enc)
+        const unsigned char *in, size_t len, size_t offset, uint8_t enc)
 {
 
-    // Encrypt/decrypt must be performed in place 
+    // Encrypt/decrypt must be performed in place
     int rv = -1;
     if (out != in
             || len < (EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN))
         return -1;
 
+    //if we're missing the first part of the record, abort
+    if((offset > EVP_GCM_TLS_EXPLICIT_IV_LEN) && (f->partial_record_len < EVP_GCM_TLS_EXPLICIT_IV_LEN )){
+        return -1;
+    }
     //set IV
     uint8_t *iv = smalloc(f->gcm_ctx_ivlen);
     memcpy(iv, f->gcm_ctx_iv, EVP_GCM_TLS_FIXED_IV_LEN);
 
+    //make encryption/decryption buffer
+    uint8_t *data = scalloc(1, offset + len);
+    memset(data, 0, offset); //dummy data to offset
+    memcpy(data+offset, in, len);
+
     if(enc){
-        memcpy(iv + f->gcm_ctx_ivlen - EVP_GCM_TLS_EXPLICIT_IV_LEN , out, EVP_GCM_TLS_EXPLICIT_IV_LEN);
-        memcpy(out, iv + f->gcm_ctx_ivlen - EVP_GCM_TLS_EXPLICIT_IV_LEN, EVP_GCM_TLS_EXPLICIT_IV_LEN);
+        memcpy(iv + f->gcm_ctx_ivlen - EVP_GCM_TLS_EXPLICIT_IV_LEN , f->partial_record_dec, EVP_GCM_TLS_EXPLICIT_IV_LEN);
     } else {
         memcpy(iv + f->gcm_ctx_ivlen - EVP_GCM_TLS_EXPLICIT_IV_LEN , f->partial_record, EVP_GCM_TLS_EXPLICIT_IV_LEN);
     }
     CRYPTO_gcm128_setiv(f->gcm_ctx_out, iv, f->gcm_ctx_ivlen);
 
-    // Fix buffer and length to point to payload
-    in += EVP_GCM_TLS_EXPLICIT_IV_LEN;
-    out += EVP_GCM_TLS_EXPLICIT_IV_LEN;
     len -= EVP_GCM_TLS_EXPLICIT_IV_LEN;
 
     //set AAD
@@ -1673,17 +1678,28 @@ int partial_aes_gcm_tls_cipher(flow *f, unsigned char *out,
 
     CRYPTO_gcm128_aad(f->gcm_ctx_out, buf, 13);
 
+    // Fix buffer and length to point to payload
+    uint8_t *p = data + EVP_GCM_TLS_EXPLICIT_IV_LEN;
+
     if(enc){
-        if ((len > 16) && CRYPTO_gcm128_encrypt(f->gcm_ctx_out, in, out, len))
+        if ((len > 16) && CRYPTO_gcm128_encrypt(f->gcm_ctx_out, p, p, len+offset))
             goto err;
     } else {
-        if ((len > 16) && CRYPTO_gcm128_decrypt(f->gcm_ctx_out, in, out, len))
+        if ((len > 16) && CRYPTO_gcm128_decrypt(f->gcm_ctx_out, p, p, len+offset))
             goto err;
     }
-    rv = len;
+
+    //copy data from buffer to output
+    memcpy(out, data+offset, len + EVP_GCM_TLS_EXPLICIT_IV_LEN);
+    if(offset > 0){
+        rv = len + EVP_GCM_TLS_EXPLICIT_IV_LEN;
+    } else {
+        rv = len;
+    }
 
 err:
     free(iv);
+    free(data);
 
     return rv;
 

+ 1 - 1
relay_station/crypto.h

@@ -42,7 +42,7 @@ void generate_client_super_keys(uint8_t *secret, client *c);
 int super_encrypt(client *c, uint8_t *data, uint32_t len);
 int check_handshake(struct packet_info *info);
 
-int partial_aes_gcm_tls_cipher(flow *f, unsigned char *out, const unsigned char *in, size_t len, uint8_t env);
+int partial_aes_gcm_tls_cipher(flow *f, unsigned char *out, const unsigned char *in, size_t len, size_t offset, uint8_t enc);
 void partial_aes_gcm_tls_tag(flow *f, unsigned char *tag, size_t len);
 
 #endif /* CRYPTO_H */

+ 43 - 18
relay_station/relay.c

@@ -19,14 +19,14 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  * Additional permission under GNU GPL version 3 section 7
- * 
+ *
  * If you modify this Program, or any covered work, by linking or combining
- * it with the OpenSSL library (or a modified version of that library), 
+ * it with the OpenSSL library (or a modified version of that library),
  * containing parts covered by the terms of the OpenSSL Licence and the
  * SSLeay license, the licensors of this Program grant you additional
  * permission to convey the resulting work. Corresponding Source for a
@@ -56,6 +56,7 @@
 #include "flow.h"
 #include "crypto.h"
 #include "util.h"
+#include "webm.h"
 
 /* Data structures */
 struct proxy_thread_data {
@@ -458,7 +459,7 @@ static int read_header(flow *f, struct packet_info *info){
                 uint8_t *initial_data = smalloc(stream_len);
                 memcpy(initial_data, p, stream_len);
 
-                struct proxy_thread_data *thread_data = 
+                struct proxy_thread_data *thread_data =
                     smalloc(sizeof(struct proxy_thread_data));
                 thread_data->initial_data = initial_data;
                 thread_data->initial_len = stream_len;
@@ -736,7 +737,7 @@ static void *proxy_covert_site(void *data){
     }
 
     DEBUG_MSG(DEBUG_PROXY, "Closing connection for stream %d\n", stream_id);
-    //remove self from list 
+    //remove self from list
     stream *last = streams->first;
     stream *prev = last;
     if(streams->first != NULL){
@@ -800,7 +801,7 @@ err:
  *  censored queue, padding with garbage bytes if no more
  *  censored data exists.
  *
- *  Inputs: 
+ *  Inputs:
  *  	f: the tagged flow
  *  	data: a pointer to the received packet's application
  *  		data
@@ -809,7 +810,7 @@ err:
  *  		application-level bytes in missing packets
  *
  *  Output:
- *  	Returns 0 on sucess 
+ *  	Returns 0 on success
  */
 static int process_downstream(flow *f, int32_t offset, struct packet_info *info){
 
@@ -866,7 +867,7 @@ static int process_downstream(flow *f, int32_t offset, struct packet_info *info)
 
 
             if(f->partial_record_header_len > 0){
-                memcpy(f->partial_record_header+ f->partial_record_header_len, 
+                memcpy(f->partial_record_header+ f->partial_record_header_len,
                         p, RECORD_HEADER_LEN - f->partial_record_header_len);
                 record_hdr = (struct record_header *) f->partial_record_header;
             } else {
@@ -932,7 +933,7 @@ static int process_downstream(flow *f, int32_t offset, struct packet_info *info)
             } else {
 
                 //partially decrypt record
-                n = partial_aes_gcm_tls_cipher(f, record_ptr, record_ptr, f->partial_record_len, 0);
+                n = partial_aes_gcm_tls_cipher(f, record_ptr, record_ptr, f->partial_record_len, 0, 0);
                 if(n <= 0){
                     //do something smarter here
                     printf("Decryption failed\n");
@@ -1010,22 +1011,35 @@ static int process_downstream(flow *f, int32_t offset, struct packet_info *info)
                         DEBUG_MSG(DEBUG_DOWN, "Found and replaced leaf header\n");
 
                     } else {
-                        //check for video
+                        //check for video/audio
                         len_ptr = strstr((const char *) p, "Content-Type: video/webm");
                         if(len_ptr != NULL){
                             printf("Found webm resource!\n");
                             f->replace_response = 1;
-                            memcpy(len_ptr + 14, "sli/theenv", 10);
+                            f->webmstate = BEGIN_ELEMENT;
+                            //memcpy(len_ptr + 14, "sli/theenv", 10);
 
                             char *c = len_ptr + 14+10;
                             while(c[0] != '\r'){
                                 c[0] = ' ';
                                 c++;
                             }
-                        }
-
-                        else {
-                            f->replace_response = 0;
+                        } else {
+                            len_ptr = strstr((const char *) p, "Content-Type: hfjdkahfk"); //audio/webm");
+                            if(len_ptr != NULL){
+                                printf("Found webm resource!\n");
+                                f->replace_response = 1;
+                                f->webmstate = BEGIN_ELEMENT;
+                                //memcpy(len_ptr + 14, "sli/theena", 10);
+
+                                char *c = len_ptr + 14+10;
+                                while(c[0] != '\r'){
+                                    c[0] = ' ';
+                                    c++;
+                                }
+                            } else {
+                                f->replace_response = 0;
+                            }
                         }
                     }
 
@@ -1112,6 +1126,10 @@ static int process_downstream(flow *f, int32_t offset, struct packet_info *info)
                 case MID_CONTENT:
                     //check if content is replaceable
                     if(f->remaining_response_len > remaining_record_len){
+                        if (f->webmstate) {
+                            //parse_webm(f, p, remaining_record_len);
+                        }
+
                         if(f->replace_response){
                             fill_with_downstream(f, p, remaining_record_len);
 
@@ -1122,13 +1140,16 @@ static int process_downstream(flow *f, int32_t offset, struct packet_info *info)
                         f->remaining_response_len -= remaining_record_len;
                         p += remaining_record_len;
 
-
                         remaining_record_len = 0;
                     } else {
+                        if (f->webmstate) {
+                            //parse_webm(f, p, f->remaining_response_len);
+                        }
+
                         if(f->replace_response){
                             fill_with_downstream(f, p, remaining_record_len);
 
-                            DEBUG_MSG(DEBUG_DOWN, "Replaced leaf with:\n");
+                            DEBUG_MSG(DEBUG_DOWN, "ERR: Replaced leaf with:\n");
                             DEBUG_BYTES(DEBUG_DOWN, p, remaining_record_len);
                         }
                         remaining_record_len -= f->remaining_response_len;
@@ -1241,7 +1262,7 @@ static int process_downstream(flow *f, int32_t offset, struct packet_info *info)
                 memcpy(f->partial_record_dec + partial_offset, record_ptr+partial_offset, n + EVP_GCM_TLS_EXPLICIT_IV_LEN - partial_offset);
             } //otherwise, this packet contains only part of the tag
 
-            n = partial_aes_gcm_tls_cipher(f, record_ptr, record_ptr, n+ EVP_GCM_TLS_EXPLICIT_IV_LEN, 1);
+            n = partial_aes_gcm_tls_cipher(f, record_ptr, record_ptr, n+ EVP_GCM_TLS_EXPLICIT_IV_LEN, 0, 1);
             if(n < 0){
                 printf("Partial decryption failed!\n");
                 free(record_ptr);
@@ -1296,6 +1317,10 @@ static int process_downstream(flow *f, int32_t offset, struct packet_info *info)
                 free(record_ptr);
                 return 0;
             }
+
+            DEBUG_MSG(DEBUG_DOWN, "Re-encrypted bytes:\n");
+            DEBUG_BYTES(DEBUG_DOWN, record_ptr, n);
+
             p = record_ptr;
         }
 

+ 4 - 1
relay_station/tests/Makefile

@@ -1,7 +1,7 @@
 CC=gcc
 CFLAGS=-g -ggdb -Wall -std=gnu99
 
-TARGETS=check_tagged check_handshake test_webm
+TARGETS=check_tagged check_handshake test_webm test_partial_aes
 
 all: $(TARGETS)
 
@@ -13,6 +13,9 @@ check_tagged: check_tagged.c test_util.o ../flow.c ../crypto.o ../relay.o ../cry
 check_handshake: check_handshake.c test_util.o ../flow.c ../crypto.o ../relay.o ../cryptothread.o ../ptwist168.o ../packet.o ../util.o ../flow.h ../crypto.h ../relay.h ../cryptothread.h ../ptwist.h ../packet.h ../util.h
 	gcc -g -ggdb -o $@ $^ -L/usr/local/lib -I/usr/local/include -lssl -lcrypto -ldl -lpthread -lpcap -lcheck_pic -lrt -lm -lsubunit
 
+test_partial_aes: test_partial_aes.c test_util.o ../flow.c ../crypto.o ../relay.o ../cryptothread.o ../ptwist168.o ../packet.o ../util.o ../flow.h ../crypto.h ../relay.h ../cryptothread.h ../ptwist.h ../packet.h ../util.h
+	gcc -g -ggdb -o $@ $^ -L/usr/local/lib -I/usr/local/include -lssl -lcrypto -ldl -lpthread -lpcap -lcheck_pic -lrt -lm -lsubunit
+
 test_webm: test_webm.c test_util.o ../flow.o ../crypto.o ../relay.o ../cryptothread.o ../ptwist168.o ../packet.o ../util.o ../flow.h ../crypto.h ../relay.h ../cryptothread.h ../ptwist.h ../packet.h ../util.h
 	gcc -g -ggdb -o $@ $^ -L/usr/local/lib -I/usr/local/include -lssl -lcrypto -ldl -lpthread -lpcap -lcheck_pic -lrt -lm -lsubunit
 

BIN
relay_station/tests/data/ciphertext.dat


+ 1 - 0
relay_station/tests/data/ctx.dat

@@ -0,0 +1 @@
+;VЙ├ЧЁ)тЪMБ]┌ь▀bnJБУMx╘┬L╗&`╥E┬═нЕ╘■$т╤s]bЯ▐$┼<)$╘мnЫуыzn&│л╘ЮРр░╡)-/yюк▌
╧╪о©.ёэfб&≤Й┴b÷5тk╞S╔бP

BIN
relay_station/tests/data/plaintext.dat


+ 277 - 0
relay_station/tests/test_partial_aes.c

@@ -0,0 +1,277 @@
+/** test_partial_aes.c
+ *
+ * Unit tests for testing the AES-GCM partial enc/dec
+ * functionality for small/misorded packets
+ */
+
+#include <check.h>
+#include <stdlib.h>
+
+#include "../flow.h"
+#include "../crypto.h"
+#include "../cryptothread.h"
+#include "../packet.h"
+#include "../util.h"
+#include "test_util.h"
+
+static void initialize_ciphers(flow *f){
+
+    uint8_t *data;
+
+    f->hs_md_ctx = EVP_MD_CTX_create();
+    const EVP_MD *md = EVP_sha256();
+    EVP_DigestInit_ex(f->hs_md_ctx, md, NULL);
+
+    f->cipher = NULL;
+    f->clnt_read_ctx = NULL;
+    f->clnt_write_ctx = NULL;
+    f->srvr_read_ctx = NULL;
+    f->srvr_write_ctx = NULL;
+    f->gcm_ctx_out = NULL;
+    f->gcm_ctx_iv = NULL;
+    f->gcm_ctx_key = NULL;
+
+    memset(f->read_seq, 0, 8);
+    memset(f->write_seq, 0, 8);
+
+    //skipping Finished message, so up counters
+    f->read_seq[7] = 1;
+    f->write_seq[7] = 1;
+
+    /* Cipher initialization */
+    if(!read_file("data/ctx.dat", &data)){
+        ck_abort();
+    }
+
+    memcpy(f->master_secret, data, SSL3_MASTER_SECRET_SIZE);
+    memcpy(f->client_random, data+SSL3_MASTER_SECRET_SIZE, SSL3_RANDOM_SIZE);
+    memcpy(f->server_random, data+SSL3_MASTER_SECRET_SIZE+SSL3_RANDOM_SIZE, SSL3_RANDOM_SIZE);
+
+    f->cipher = EVP_aes_128_gcm();
+    f->message_digest = EVP_sha256();
+
+    int result = init_ciphers(f);
+    ck_assert_int_eq(result, 0);
+
+    free(data);
+}
+
+START_TEST(full_decrypt){
+
+    uint8_t *data;
+    int32_t len;
+    flow *f = NULL;
+
+    /* Flow initialization */
+    f = smalloc(sizeof(flow));
+    initialize_ciphers(f);
+
+    /* Application Data */
+    if(!(read_file_len("data/ciphertext.dat", &data, &len))){
+        ck_abort();
+    }
+
+    int n = encrypt(f, data, data, len, 1, 0x17, 0, 0);
+    ck_assert_int_eq(n, len - (EVP_GCM_TLS_TAG_LEN + EVP_GCM_TLS_EXPLICIT_IV_LEN));
+
+    free(data);
+
+}
+END_TEST
+
+START_TEST(full_encrypt){
+
+    uint8_t *data;
+    int len;
+    flow *f = NULL;
+
+    /* Flow initialization */
+    f = smalloc(sizeof(flow));
+    initialize_ciphers(f);
+
+    /* Application Data */
+    if(!(read_file_len("data/plaintext.dat", &data, &len))){
+        ck_abort();
+    }
+
+    int n = encrypt(f, data, data, len-EVP_GCM_TLS_TAG_LEN, 1, 0x17, 1, 0);
+    ck_assert_int_eq(n, len);
+
+    free(data);
+
+}
+END_TEST
+
+START_TEST(partial_decrypt){
+
+    uint8_t *data;
+    uint8_t *data2;
+    int len;
+    flow *f = NULL;
+
+    /* Flow initialization */
+    f = smalloc(sizeof(flow));
+    initialize_ciphers(f);
+
+    /* Application Data */
+    if(!(read_file_len("data/ciphertext.dat", &data, &len))){
+        ck_abort();
+    }
+
+    if(!(read_file("data/ciphertext.dat", &data2))){
+        ck_abort();
+    }
+
+    int n = encrypt(f, data, data, len, 1, 0x17, 0, 0);
+    ck_assert_int_gt(n, 0);
+
+
+    f->partial_record = data2;
+    n = partial_aes_gcm_tls_cipher(f, data2, data2, len/2, 0, 0);
+    ck_assert_int_eq(n, len/2 - EVP_GCM_TLS_EXPLICIT_IV_LEN);
+
+    ck_assert_int_eq(memcmp(data + EVP_GCM_TLS_EXPLICIT_IV_LEN, data2 +
+                EVP_GCM_TLS_EXPLICIT_IV_LEN, n), 0);
+    free(data2);
+
+    if(!(read_file("data/ciphertext.dat", &data2))){
+        ck_abort();
+    }
+
+    f->partial_record = data2;
+    f->partial_record_len = 100;
+    n = partial_aes_gcm_tls_cipher(f, data2+100, data2+100, 300, 100, 0);
+    ck_assert_int_eq(n, 300);
+
+    printf("partial bytes:\n");
+    for(int i=0; i< 300; i++){
+        printf("%02x ", data[100+i]);
+    }
+    printf("\n");
+    printf("partial bytes:\n");
+    for(int i=0; i< 300; i++){
+        printf("%02x ", data2[100+i]);
+    }
+    printf("\n");
+
+
+    ck_assert_int_eq(memcmp(data + 100, data2 + 100, 300), 0);
+    free(data2);
+
+
+    free(data);
+
+}
+END_TEST
+
+START_TEST(partial_encrypt){
+
+    uint8_t *data;
+    uint8_t *data2;
+    int len;
+    flow *f = NULL;
+
+    /* Flow initialization */
+    f = smalloc(sizeof(flow));
+    initialize_ciphers(f);
+
+    /* Application Data */
+    if(!(read_file_len("data/plaintext.dat", &data, &len))){
+        ck_abort();
+    }
+
+    if(!(read_file("data/plaintext.dat", &data2))){
+        ck_abort();
+    }
+    printf("%s\n", data2+EVP_GCM_TLS_EXPLICIT_IV_LEN);
+    fflush(stdout);
+
+    //skipping decrypt, so up counters
+    f->read_seq[7] = 2;
+    f->write_seq[7] = 2;
+
+    f->partial_record_dec = data;
+    int n = partial_aes_gcm_tls_cipher(f, data, data, len/2 + EVP_GCM_TLS_EXPLICIT_IV_LEN, 0, 1);
+    ck_assert_int_gt(n, 0);
+
+    f->partial_record_dec = data2;
+    n = partial_aes_gcm_tls_cipher(f, data2, data2, len - EVP_GCM_TLS_TAG_LEN, 0, 1);
+    ck_assert_int_eq(n, len - EVP_GCM_TLS_TAG_LEN - EVP_GCM_TLS_EXPLICIT_IV_LEN);
+
+    ck_assert_int_eq(memcmp(data, data2, n/2), 0);
+
+    //compute the tag
+    partial_aes_gcm_tls_tag(f, data2 + n + EVP_GCM_TLS_EXPLICIT_IV_LEN, n);
+
+    //decrypt to check tag
+    initialize_ciphers(f);
+    n = encrypt(f, data2, data2, len, 1, 0x17, 0, 0);
+    printf("%s\n", data2+EVP_GCM_TLS_EXPLICIT_IV_LEN);
+    fflush(stdout);
+    ck_assert_int_eq(n, len - (EVP_GCM_TLS_TAG_LEN + EVP_GCM_TLS_EXPLICIT_IV_LEN));
+
+    free(data);
+    free(data2);
+
+}
+END_TEST
+
+START_TEST(future_decrypt){
+
+}
+END_TEST
+
+START_TEST(future_encrypt){
+
+}
+END_TEST
+
+Suite *tag_suite(void) {
+    Suite *s;
+    TCase *tc_core;
+
+    s = suite_create("Partial AES");
+
+    tc_core = tcase_create("Core");
+    tcase_add_test(tc_core, full_decrypt);
+    tcase_add_test(tc_core, full_encrypt);
+    tcase_add_test(tc_core, partial_decrypt);
+    tcase_add_test(tc_core, partial_encrypt);
+    tcase_add_test(tc_core, future_decrypt);
+    tcase_add_test(tc_core, future_encrypt);
+
+    suite_add_tcase(s, tc_core);
+
+    return s;
+}
+
+
+int main(void){
+
+    int number_failed;
+    Suite *s;
+    SRunner *sr;
+
+    //initialize Slitheen structures
+    if(init_tables()){
+        exit(1);
+    }
+    if(init_session_cache()){
+        exit(1);
+    }
+    init_crypto_locks();
+
+
+    s = tag_suite();
+    sr = srunner_create(s);
+
+    srunner_set_fork_status(sr, CK_NOFORK);
+
+    srunner_run_all(sr, CK_NORMAL);
+    number_failed = srunner_ntests_failed(sr);
+    srunner_free(sr);
+
+    crypto_locks_cleanup();
+
+    return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}