9 Commits 4264eb8e13 ... d6eb8ccbfa

Author SHA1 Message Date
  cecylia d6eb8ccbfa fixed bugs in socks proxy and webm state machine 6 years ago
  cecylia 1ba11d2588 fixed trailing whitespace and indentation for all socks proxy code 6 years ago
  cecylia 8860587eea Fixed trailing whitespace 6 years ago
  cecylia 3dfaa4500e fully functional video/webm replacement, fixed bug in upstream header decryption 6 years ago
  cecylia b9064640e4 delays processing of application-level packets in case of future packet 6 years ago
  cecylia 089644b189 modified partial aes encrypt function to be able to decrypt/encrypt 'future' packets, fixed spacing, added webm checks 6 years ago
  cecylia 5392bc6371 fixed bug that causes relay station to seg fault when receiving curve 25519 w/ openssl version < 1.1.0e 6 years ago
  cecylia c795ba86af fixed extra whitespace from previous commit 6 years ago
  cecylia 1e9f684215 added webm state machine to relay station + unit tests 6 years ago

+ 227 - 227
client/crypto.c

@@ -10,14 +10,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
@@ -47,106 +47,106 @@ static super_data *super;
 
 /* PRF using sha384, as defined in RFC 5246 */
 int PRF(uint8_t *secret, int32_t secret_len,
-		uint8_t *seed1, int32_t seed1_len,
-		uint8_t *seed2, int32_t seed2_len,
-		uint8_t *seed3, int32_t seed3_len,
-		uint8_t *seed4, int32_t seed4_len,
-		uint8_t *output, int32_t output_len){
+        uint8_t *seed1, int32_t seed1_len,
+        uint8_t *seed2, int32_t seed2_len,
+        uint8_t *seed3, int32_t seed3_len,
+        uint8_t *seed4, int32_t seed4_len,
+        uint8_t *output, int32_t output_len){
 
-	EVP_MD_CTX *ctx, *ctx_tmp, *ctx_init;
-	EVP_PKEY *mac_key;
-	const EVP_MD *md = EVP_sha256();
+    EVP_MD_CTX *ctx, *ctx_tmp, *ctx_init;
+    EVP_PKEY *mac_key;
+    const EVP_MD *md = EVP_sha256();
 
-	uint8_t A[EVP_MAX_MD_SIZE];
-	size_t len, A_len;
-	int chunk = EVP_MD_size(md);
-	int remaining = output_len;
+    uint8_t A[EVP_MAX_MD_SIZE];
+    size_t len, A_len;
+    int chunk = EVP_MD_size(md);
+    int remaining = output_len;
 
-	uint8_t *out = output;
+    uint8_t *out = output;
 
 #if OPENSSL_VERSION_NUMBER >= 0x1010000eL
-        ctx = EVP_MD_CTX_new();
-        ctx_tmp = EVP_MD_CTX_new();
-        ctx_init = EVP_MD_CTX_new();
+    ctx = EVP_MD_CTX_new();
+    ctx_tmp = EVP_MD_CTX_new();
+    ctx_init = EVP_MD_CTX_new();
 #else
-        ctx = ecalloc(1, sizeof(EVP_MD_CTX));
-	EVP_MD_CTX_init(ctx);
-        ctx_tmp = ecalloc(1, sizeof(EVP_MD_CTX));
-	EVP_MD_CTX_init(ctx_tmp);
-        ctx_init = ecalloc(1, sizeof(EVP_MD_CTX));
-	EVP_MD_CTX_init(ctx_init);
+    ctx = ecalloc(1, sizeof(EVP_MD_CTX));
+    EVP_MD_CTX_init(ctx);
+    ctx_tmp = ecalloc(1, sizeof(EVP_MD_CTX));
+    EVP_MD_CTX_init(ctx_tmp);
+    ctx_init = ecalloc(1, sizeof(EVP_MD_CTX));
+    EVP_MD_CTX_init(ctx_init);
 #endif
 
-	EVP_MD_CTX_set_flags(ctx_init, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
-
-	mac_key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, secret, secret_len);
-
-	/* Calculate first A value */
-	EVP_DigestSignInit(ctx_init, NULL, md, NULL, mac_key);
-	EVP_MD_CTX_copy_ex(ctx, ctx_init);
-	if(seed1 != NULL && seed1_len > 0){
-		EVP_DigestSignUpdate(ctx, seed1, seed1_len);
-	}
-	if(seed2 != NULL && seed2_len > 0){
-		EVP_DigestSignUpdate(ctx, seed2, seed2_len);
-	}
-	if(seed3 != NULL && seed3_len > 0){
-		EVP_DigestSignUpdate(ctx, seed3, seed3_len);
-	}
-	if(seed4 != NULL && seed4_len > 0){
-		EVP_DigestSignUpdate(ctx, seed4, seed4_len);
-	}
-	EVP_DigestSignFinal(ctx, A, &A_len);
-
-	//iterate until desired length is achieved
-	while(remaining > 0){
-		/* Now compute SHA384(secret, A+seed) */
-		EVP_MD_CTX_copy_ex(ctx, ctx_init);
-		EVP_DigestSignUpdate(ctx, A, A_len);
-		EVP_MD_CTX_copy_ex(ctx_tmp, ctx);
-		if(seed1 != NULL && seed1_len > 0){
-			EVP_DigestSignUpdate(ctx, seed1, seed1_len);
-		}
-		if(seed2 != NULL && seed2_len > 0){
-			EVP_DigestSignUpdate(ctx, seed2, seed2_len);
-		}
-		if(seed3 != NULL && seed3_len > 0){
-			EVP_DigestSignUpdate(ctx, seed3, seed3_len);
-		}
-		if(seed4 != NULL && seed4_len > 0){
-			EVP_DigestSignUpdate(ctx, seed4, seed4_len);
-		}
-		
-		if(remaining > chunk){
-			EVP_DigestSignFinal(ctx, out, &len);
-			out += len;
-			remaining -= len;
-
-			/* Next A value */
-			EVP_DigestSignFinal(ctx_tmp, A, &A_len);
-		} else {
-			EVP_DigestSignFinal(ctx, A, &A_len);
-			memcpy(out, A, remaining);
-			remaining -= remaining;
-		}
-	}
-
-	EVP_PKEY_free(mac_key);
+    EVP_MD_CTX_set_flags(ctx_init, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+
+    mac_key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, secret, secret_len);
+
+    /* Calculate first A value */
+    EVP_DigestSignInit(ctx_init, NULL, md, NULL, mac_key);
+    EVP_MD_CTX_copy_ex(ctx, ctx_init);
+    if(seed1 != NULL && seed1_len > 0){
+        EVP_DigestSignUpdate(ctx, seed1, seed1_len);
+    }
+    if(seed2 != NULL && seed2_len > 0){
+        EVP_DigestSignUpdate(ctx, seed2, seed2_len);
+    }
+    if(seed3 != NULL && seed3_len > 0){
+        EVP_DigestSignUpdate(ctx, seed3, seed3_len);
+    }
+    if(seed4 != NULL && seed4_len > 0){
+        EVP_DigestSignUpdate(ctx, seed4, seed4_len);
+    }
+    EVP_DigestSignFinal(ctx, A, &A_len);
+
+    //iterate until desired length is achieved
+    while(remaining > 0){
+        /* Now compute SHA384(secret, A+seed) */
+        EVP_MD_CTX_copy_ex(ctx, ctx_init);
+        EVP_DigestSignUpdate(ctx, A, A_len);
+        EVP_MD_CTX_copy_ex(ctx_tmp, ctx);
+        if(seed1 != NULL && seed1_len > 0){
+            EVP_DigestSignUpdate(ctx, seed1, seed1_len);
+        }
+        if(seed2 != NULL && seed2_len > 0){
+            EVP_DigestSignUpdate(ctx, seed2, seed2_len);
+        }
+        if(seed3 != NULL && seed3_len > 0){
+            EVP_DigestSignUpdate(ctx, seed3, seed3_len);
+        }
+        if(seed4 != NULL && seed4_len > 0){
+            EVP_DigestSignUpdate(ctx, seed4, seed4_len);
+        }
+
+        if(remaining > chunk){
+            EVP_DigestSignFinal(ctx, out, &len);
+            out += len;
+            remaining -= len;
+
+            /* Next A value */
+            EVP_DigestSignFinal(ctx_tmp, A, &A_len);
+        } else {
+            EVP_DigestSignFinal(ctx, A, &A_len);
+            memcpy(out, A, remaining);
+            remaining -= remaining;
+        }
+    }
+
+    EVP_PKEY_free(mac_key);
 
 #if OPENSSL_VERSION_NUMBER >= 0x1010000eL
-        EVP_MD_CTX_free(ctx);
-        EVP_MD_CTX_free(ctx_tmp);
-        EVP_MD_CTX_free(ctx_init);
+    EVP_MD_CTX_free(ctx);
+    EVP_MD_CTX_free(ctx_tmp);
+    EVP_MD_CTX_free(ctx_init);
 #else
-	EVP_MD_CTX_cleanup(ctx);
-	EVP_MD_CTX_cleanup(ctx_tmp);
-	EVP_MD_CTX_cleanup(ctx_init);
-        free(ctx);
-        free(ctx_tmp);
-        free(ctx_init);
+    EVP_MD_CTX_cleanup(ctx);
+    EVP_MD_CTX_cleanup(ctx_tmp);
+    EVP_MD_CTX_cleanup(ctx_init);
+    free(ctx);
+    free(ctx_tmp);
+    free(ctx_init);
 #endif
 
-	return 1;
+    return 1;
 }
 
 
@@ -155,8 +155,8 @@ int PRF(uint8_t *secret, int32_t secret_len,
  */
 int generate_super_keys(uint8_t *secret){
 
-	super = calloc(1, sizeof(super_data));
-	
+    super = calloc(1, sizeof(super_data));
+
     EVP_MD_CTX *mac_ctx;
 
     const EVP_MD *md = EVP_sha256();
@@ -180,7 +180,7 @@ int generate_super_keys(uint8_t *secret){
             key_block, total_len);
 
 #ifdef DEBUG
-	int i;
+    int i;
     printf("secret: \n");
     for(i=0; i< SLITHEEN_SUPER_SECRET_SIZE; i++){
         printf("%02x ", secret[i]);
@@ -205,220 +205,220 @@ int generate_super_keys(uint8_t *secret){
     mac_key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, mac_secret, mac_len);
     EVP_DigestSignInit(mac_ctx, NULL, md, NULL, mac_key);
 
-	super->header_key = malloc(key_len);
-	super->body_key = malloc(key_len);
-	memcpy(super->header_key, hdr_key, key_len);
-	memcpy(super->body_key, bdy_key, key_len);
+    super->header_key = malloc(key_len);
+    super->body_key = malloc(key_len);
+    memcpy(super->header_key, hdr_key, key_len);
+    memcpy(super->body_key, bdy_key, key_len);
     super->body_mac_ctx = mac_ctx;
 
     //Free everything
     free(key_block);
     EVP_PKEY_free(mac_key);
 
-	return 0;
+    return 0;
 }
 
 int peek_header(uint8_t *data){
 
-	EVP_CIPHER_CTX *hdr_ctx = NULL;
+    EVP_CIPHER_CTX *hdr_ctx = NULL;
 
-	int32_t out_len;
-	uint8_t *p = data;
-	int retval = 1;
+    int32_t out_len;
+    uint8_t *p = data;
+    int retval = 1;
 
-	//decrypt header
+    //decrypt header
 #ifdef DEBUG_PEEK
-	int i;
-	printf("Encrypted header:\n");
-	for(i=0; i< SLITHEEN_HEADER_LEN; i++){
-		printf("%02x ", p[i]);
-	}
-	printf("\n");
+    int i;
+    printf("Encrypted header:\n");
+    for(i=0; i< SLITHEEN_HEADER_LEN; i++){
+        printf("%02x ", p[i]);
+    }
+    printf("\n");
 #endif
 
     hdr_ctx = EVP_CIPHER_CTX_new();
 
     EVP_CipherInit_ex(hdr_ctx, EVP_aes_256_ecb(), NULL, super->header_key, NULL, 0);
 
-	if(!EVP_CipherUpdate(hdr_ctx, p, &out_len, p, SLITHEEN_HEADER_LEN)){
-		retval =  0;
-		goto end;
-	}
+    if(!EVP_CipherUpdate(hdr_ctx, p, &out_len, p, SLITHEEN_HEADER_LEN)){
+        retval =  0;
+        goto end;
+    }
 
-	struct slitheen_hdr *sl_hdr = (struct slitheen_hdr *) p;
+    struct slitheen_hdr *sl_hdr = (struct slitheen_hdr *) p;
 
-        //Finally, check to see if the last few bytes are zeroed.
-        if(sl_hdr->zeros){
-            //zeros have been corrupted, decryption failed
-            printf("Decryption failed!\n");
-            retval = 0;
-            goto end;
-        }
+    //Finally, check to see if the last few bytes are zeroed.
+    if(sl_hdr->zeros){
+        //zeros have been corrupted, decryption failed
+        printf("Decryption failed!\n");
+        retval = 0;
+        goto end;
+    }
 
 #ifdef DEBUG_PARSE
-	printf("Decrypted header (%d bytes):\n", SLITHEEN_HEADER_LEN);
-	for(i=0; i< SLITHEEN_HEADER_LEN; i++){
-		printf("%02x ", p[i]);
-	}
-	printf("\n");
-	fflush(stdout);
+    printf("Decrypted header (%d bytes):\n", SLITHEEN_HEADER_LEN);
+    for(i=0; i< SLITHEEN_HEADER_LEN; i++){
+        printf("%02x ", p[i]);
+    }
+    printf("\n");
+    fflush(stdout);
 #endif
 
-	retval = 1;
+    retval = 1;
 
 end:
-	if(hdr_ctx != NULL){
-		EVP_CIPHER_CTX_cleanup(hdr_ctx);
-		OPENSSL_free(hdr_ctx);
-	}
+    if(hdr_ctx != NULL){
+        EVP_CIPHER_CTX_cleanup(hdr_ctx);
+        OPENSSL_free(hdr_ctx);
+    }
 
-	return retval;
+    return retval;
 
 }
 
 int super_decrypt(uint8_t *data){
 
-	EVP_CIPHER_CTX *bdy_ctx = NULL;
-	EVP_CIPHER_CTX *hdr_ctx = NULL;
+    EVP_CIPHER_CTX *bdy_ctx = NULL;
+    EVP_CIPHER_CTX *hdr_ctx = NULL;
 
-	uint8_t *p = data;
-	int32_t out_len, len;
-	uint8_t output[EVP_MAX_MD_SIZE];
-	size_t mac_len;
-	int i, retval = 1;
+    uint8_t *p = data;
+    int32_t out_len, len;
+    uint8_t output[EVP_MAX_MD_SIZE];
+    size_t mac_len;
+    int i, retval = 1;
 
-	//decrypt header
+    //decrypt header
 #ifdef DEBUG
-	printf("Encrypted header:\n");
-	for(i=0; i< SLITHEEN_HEADER_LEN; i++){
-		printf("%02x ", p[i]);
-	}
-	printf("\n");
+    printf("Encrypted header:\n");
+    for(i=0; i< SLITHEEN_HEADER_LEN; i++){
+        printf("%02x ", p[i]);
+    }
+    printf("\n");
 #endif
 
     hdr_ctx = EVP_CIPHER_CTX_new();
 
     EVP_CipherInit_ex(hdr_ctx, EVP_aes_256_ecb(), NULL, super->header_key, NULL, 0);
 
-	if(!EVP_CipherUpdate(hdr_ctx, p, &out_len, p, SLITHEEN_HEADER_LEN)){
-		printf("Decryption failed!");
-		retval =  0;
-		goto end;
-	}
+    if(!EVP_CipherUpdate(hdr_ctx, p, &out_len, p, SLITHEEN_HEADER_LEN)){
+        printf("Decryption failed!");
+        retval =  0;
+        goto end;
+    }
 
-	struct slitheen_hdr *sl_hdr = (struct slitheen_hdr *) p;
-	len = htons(sl_hdr->len);
+    struct slitheen_hdr *sl_hdr = (struct slitheen_hdr *) p;
+    len = htons(sl_hdr->len);
 
-	if(!sl_hdr->len){//there are no data to be decrypted
-		retval =  1;
-		goto end;
-	}
+    if(!sl_hdr->len){//there are no data to be decrypted
+        retval =  1;
+        goto end;
+    }
 
-	if(len %16){ //add padding to len
-		len += 16 - len%16;
-	}
+    if(len %16){ //add padding to len
+        len += 16 - len%16;
+    }
 
 
 #ifdef DEBUG
-	printf("Decrypted header (%d bytes):\n", SLITHEEN_HEADER_LEN);
-	for(i=0; i< SLITHEEN_HEADER_LEN; i++){
-		printf("%02x ", p[i]);
-	}
-	printf("\n");
-	fflush(stdout);
+    printf("Decrypted header (%d bytes):\n", SLITHEEN_HEADER_LEN);
+    for(i=0; i< SLITHEEN_HEADER_LEN; i++){
+        printf("%02x ", p[i]);
+    }
+    printf("\n");
+    fflush(stdout);
 #endif
-	
-	p += SLITHEEN_HEADER_LEN;
 
-	//initialize body cipher context with IV
+    p += SLITHEEN_HEADER_LEN;
+
+    //initialize body cipher context with IV
     bdy_ctx = EVP_CIPHER_CTX_new();
     EVP_CipherInit_ex(bdy_ctx, EVP_aes_256_cbc(), NULL, super->body_key, p, 0);
-	p+=16;
+    p+=16;
 
-	//compute mac
-	EVP_MD_CTX *mac_ctx;
+    //compute mac
+    EVP_MD_CTX *mac_ctx;
 #if OPENSSL_VERSION_NUMBER >= 0x1010000eL
-        mac_ctx = EVP_MD_CTX_new();
+    mac_ctx = EVP_MD_CTX_new();
 #else
-        mac_ctx = ecalloc(1, sizeof(EVP_MD_CTX));
-	EVP_MD_CTX_init(mac_ctx);
+    mac_ctx = ecalloc(1, sizeof(EVP_MD_CTX));
+    EVP_MD_CTX_init(mac_ctx);
 #endif
-	EVP_MD_CTX_copy_ex(mac_ctx, super->body_mac_ctx);
+    EVP_MD_CTX_copy_ex(mac_ctx, super->body_mac_ctx);
 
-	EVP_DigestSignUpdate(mac_ctx, p, len);
+    EVP_DigestSignUpdate(mac_ctx, p, len);
 
-        EVP_DigestSignFinal(mac_ctx, output, &mac_len);
+    EVP_DigestSignFinal(mac_ctx, output, &mac_len);
 
 #if OPENSSL_VERSION_NUMBER >= 0x1010000eL
-        EVP_MD_CTX_free(mac_ctx);
+    EVP_MD_CTX_free(mac_ctx);
 #else
-	EVP_MD_CTX_cleanup(mac_ctx);
-        free(mac_ctx);
+    EVP_MD_CTX_cleanup(mac_ctx);
+    free(mac_ctx);
 #endif
 
 #ifdef DEBUG_PARSE
-	printf("Received mac:\n");
-	for(i=0; i< 16; i++){
-		printf("%02x ", p[len+i]);
-	}
-	printf("\n");
-	fflush(stdout);
+    printf("Received mac:\n");
+    for(i=0; i< 16; i++){
+        printf("%02x ", p[len+i]);
+    }
+    printf("\n");
+    fflush(stdout);
 #endif
 
 #ifdef DEBUG_PARSE
-	printf("Computed mac:\n");
-	for(i=0; i< 16; i++){
-		printf("%02x ", output[i]);
-	}
-	printf("\n");
-	fflush(stdout);
+    printf("Computed mac:\n");
+    for(i=0; i< 16; i++){
+        printf("%02x ", output[i]);
+    }
+    printf("\n");
+    fflush(stdout);
 #endif
 
-	if(memcmp(p+len, output, 16)){
-		printf("MAC verification failed\n");
-		retval =  0;
-		goto end;
-	}
+    if(memcmp(p+len, output, 16)){
+        printf("MAC verification failed\n");
+        retval =  0;
+        goto end;
+    }
 
-	//decrypt body
+    //decrypt body
 #ifdef DEBUG_PARSE
-	printf("Encrypted data (%d bytes):\n", len);
-	for(i=0; i< len; i++){
-		printf("%02x ", p[i]);
-	}
-	printf("\n");
+    printf("Encrypted data (%d bytes):\n", len);
+    for(i=0; i< len; i++){
+        printf("%02x ", p[i]);
+    }
+    printf("\n");
 #endif
 
-	if(!EVP_CipherUpdate(bdy_ctx, p, &out_len, p, len)){
-		printf("Decryption failed!");
-		retval =  0;
-		goto end;
-	}
+    if(!EVP_CipherUpdate(bdy_ctx, p, &out_len, p, len)){
+        printf("Decryption failed!");
+        retval =  0;
+        goto end;
+    }
 
 #ifdef DEBUG
-	printf("Decrypted data (%d bytes):\n", out_len);
-	for(i=0; i< out_len; i++){
-		printf("%02x ", p[i]);
-	}
-	printf("\n");
-	fflush(stdout);
+    printf("Decrypted data (%d bytes):\n", out_len);
+    for(i=0; i< out_len; i++){
+        printf("%02x ", p[i]);
+    }
+    printf("\n");
+    fflush(stdout);
 #endif
 
-	p += out_len;
+    p += out_len;
 
-	retval = 1;
+    retval = 1;
 
 end:
-	if(hdr_ctx != NULL){
-		EVP_CIPHER_CTX_cleanup(hdr_ctx);
-		OPENSSL_free(hdr_ctx);
-	}
-	if(bdy_ctx != NULL){
-		EVP_CIPHER_CTX_cleanup(bdy_ctx);
-		OPENSSL_free(bdy_ctx);
-	}
-
-	return retval;
+    if(hdr_ctx != NULL){
+        EVP_CIPHER_CTX_cleanup(hdr_ctx);
+        OPENSSL_free(hdr_ctx);
+    }
+    if(bdy_ctx != NULL){
+        EVP_CIPHER_CTX_cleanup(bdy_ctx);
+        OPENSSL_free(bdy_ctx);
+    }
+
+    return retval;
 
 }
 

+ 12 - 12
client/crypto.h

@@ -10,14 +10,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 [name of library's license],
  * the licensors of this Program grant you additional permission to convey
  * the resulting work. {Corresponding Source for a non-source form of such
@@ -31,24 +31,24 @@
 #include <openssl/evp.h>
 
 # define n2s(c,s)        ((s=(((unsigned int)(c[0]))<< 8)| \
-							(((unsigned int)(c[1]))    )),c+=2)
+            (((unsigned int)(c[1]))    )),c+=2)
 
 
 int PRF(uint8_t *secret, int32_t secret_len,
-		uint8_t *seed1, int32_t seed1_len,
-		uint8_t *seed2, int32_t seed2_len,
-		uint8_t *seed3, int32_t seed3_len,
-		uint8_t *seed4, int32_t seed4_len,
-		uint8_t *output, int32_t output_len);
+        uint8_t *seed1, int32_t seed1_len,
+        uint8_t *seed2, int32_t seed2_len,
+        uint8_t *seed3, int32_t seed3_len,
+        uint8_t *seed4, int32_t seed4_len,
+        uint8_t *output, int32_t output_len);
 
 int peek_header(uint8_t *data);
 int super_decrypt(uint8_t *data);
 int generate_super_keys(uint8_t *secret);
 
 typedef struct super_data_st {
-	uint8_t *header_key;
-	uint8_t *body_key;
-	EVP_MD_CTX *body_mac_ctx;
+    uint8_t *header_key;
+    uint8_t *body_key;
+    EVP_MD_CTX *body_mac_ctx;
 } super_data;
 
 #define PRE_MASTER_LEN 256

+ 212 - 180
client/socks5proxy.c

@@ -10,14 +10,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
@@ -60,14 +60,14 @@ typedef struct {
 
 int main(void){
     int listen_socket;
-    
+
     struct sockaddr_in address;
     struct sockaddr_in remote_addr;
     socklen_t addr_size;
 
     connections = calloc(1, sizeof(connection_table));
     connections->first = NULL;
-    
+
     int32_t ous_in[2];
     if(pipe(ous_in) < 0){
         printf("Failed to create pipe\n");
@@ -137,7 +137,7 @@ int main(void){
         addr_size = sizeof(remote_addr);
         int new_socket;
         new_socket = accept(listen_socket, (struct sockaddr *) &remote_addr,
-                                        &addr_size);
+                &addr_size);
         if(new_socket < 0){
             perror("accept");
             exit(1);
@@ -147,11 +147,11 @@ int main(void){
         //assign a new stream_id and create a pipe for the session
         connection *new_conn = calloc(1, sizeof(connection));
         new_conn->stream_id = last_id++;
-        
+
         new_conn->socket = new_socket;
         new_conn->state = NEW_STREAM;
         new_conn->next = NULL;
-        
+
         if(connections->first == NULL){
             connections->first = new_conn;
             printf("Added first connection with id: %d\n", new_conn->stream_id);
@@ -234,6 +234,9 @@ void *ous_IO(void *args){
     uint8_t *buffer = emalloc(BUFSIZ);
     int32_t buffer_len = BUFSIZ;
 
+    uint8_t *input_buffer = NULL;
+    uint32_t input_buffer_len;
+
     int32_t bytes_read;
 
     /* Select on proxy pipes, demux thread, and ous to send and receive data*/
@@ -303,7 +306,7 @@ void *ous_IO(void *args){
 
         if(FD_ISSET(ous, &read_fds) && FD_ISSET(ous_out, &write_fds)){
 
-            bytes_read = recv(ous, buffer, 4, 0);
+            bytes_read = recv(ous, (uint8_t *) &input_buffer_len, 4, 0);
 #ifdef DEBUG_IO
             printf("Received %d bytes from OUS\n", bytes_read);
             for(int i=0; i< bytes_read; i++){
@@ -318,27 +321,29 @@ void *ous_IO(void *args){
                 break;
             }
 
-            uint32_t *chunk_len = (uint32_t*) buffer;
-            
-            fprintf(stderr, "Length of this chunk: %u\n", *chunk_len);
+            uint32_t chunk_len = input_buffer_len;
 
-            
-            bytes_read = recv(ous, buffer, *chunk_len, 0);
+            bytes_sent = write(ous_out, (uint8_t *) &input_buffer_len, bytes_read);
+            //TODO: check return
+
+            input_buffer = malloc(input_buffer_len);
+
+            bytes_read = recv(ous, input_buffer, chunk_len, 0);
 #ifdef DEBUG_IO
             printf("Received %d bytes from OUS\n", bytes_read);
             for(int i=0; i< bytes_read; i++){
-                printf("%02x ", buffer[i]);
+                printf("%02x ", input_buffer[i]);
             }
             printf("\n");
             fflush(stdout);
 #endif
 
             if(bytes_read > 0){
-                bytes_sent = write(ous_out, buffer, bytes_read);
+                bytes_sent = write(ous_out, input_buffer, bytes_read);
 #ifdef DEBUG_IO
                 printf("Sent %d bytes to demultiplexer\n", bytes_sent);
                 for(int i=0; i< bytes_sent; i++){
-                    printf("%02x ", buffer[i]);
+                    printf("%02x ", input_buffer[i]);
                 }
                 printf("\n");
                 fflush(stdout);
@@ -358,6 +363,9 @@ void *ous_IO(void *args){
                 fprintf(stderr, "Error reading from OUS\n");
                 break;
             }
+
+            free(input_buffer);
+            input_buffer = NULL;
         }
 
     }
@@ -560,7 +568,7 @@ void *multiplex_data(void *args){
 #ifdef DEBUG_UPSTREAM
                         printf("Received %d data bytes from sockfd (id %d):\n", bytes_read, conn->stream_id);
                         for(int i=0; i< bytes_read; i++){
-                                printf("%02x ", buffer[i]);
+                            printf("%02x ", buffer[i]);
                         }
                         printf("\n");
                         printf("%s\n", buffer);
@@ -612,8 +620,7 @@ void *multiplex_data(void *args){
 void *demultiplex_data(void *args){
     ous_pipes *pipes = (ous_pipes *) args;
 
-    int32_t buffer_len = BUFSIZ;
-    uint8_t *buffer = calloc(1, buffer_len);
+    uint8_t *buffer = NULL;
     uint8_t *p;
 
     uint8_t *partial_block = NULL;
@@ -622,208 +629,235 @@ void *demultiplex_data(void *args){
     data_block *saved_data = NULL;
 
     for(;;){
-        printf("Demux thread waiting to read\n");
-        int32_t bytes_read = read(pipes->out, buffer, buffer_len-partial_block_len);
-		
-        if(bytes_read > 0){
-            int32_t chunk_remaining = bytes_read;
-            p = buffer;
-
-            //didn't read a full slitheen block last time
-            if(partial_block_len > 0){
-                //process first part of slitheen info
-                memmove(buffer+partial_block_len, buffer, bytes_read);
-                memcpy(buffer, partial_block, partial_block_len);
-                chunk_remaining += partial_block_len;
-                free(partial_block);
-                partial_block = NULL;
-                partial_block_len = 0;
-            }
+        uint32_t chunk_len;
 
-            while(chunk_remaining > 0){
+        int32_t bytes_read = read(pipes->out, (uint8_t *) &chunk_len, 4);
 
-#ifdef DEBUG_PARSE
-                printf("Received a new chunk of len %d bytes\n", chunk_remaining);
-#endif
+        fprintf(stdout, "Length of this chunk: %u\n", chunk_len);
 
-                if(chunk_remaining < SLITHEEN_HEADER_LEN){
+        buffer = calloc(1, chunk_len);
+
+        bytes_read = read(pipes->out, buffer, chunk_len);
+
+        if(bytes_read <= 0){
+            printf("Error: read %d bytes from OUS_out\n", bytes_read);
+            goto err;
+        }
+
+        if(bytes_read < chunk_len) {
+            printf("Error: read %d out of %d bytes\n", bytes_read, chunk_len);
+        }
+
+        int32_t chunk_remaining = bytes_read;
+        p = buffer;
 
 #ifdef DEBUG_PARSE
-                    printf("Partial header: ");
-                    int i;
-                    for(i = 0; i< chunk_remaining; i++){
-                        printf("%02x ", p[i]);
-                    }
-                    printf("\n");
+        printf("Received a new chunk of len %d bytes\n", chunk_remaining);
 #endif
+        //didn't read a full slitheen block last time
+        if(partial_block_len > 0){
+            //process first part of slitheen info
+            memmove(buffer+partial_block_len, buffer, bytes_read);
+            memcpy(buffer, partial_block, partial_block_len);
+            chunk_remaining += partial_block_len;
+            free(partial_block);
+            partial_block = NULL;
+            partial_block_len = 0;
+        }
 
-                    if(partial_block != NULL) printf("UH OH (PB)\n");
-                    partial_block = calloc(1, chunk_remaining);
-                    memcpy(partial_block, p, chunk_remaining);
-                    partial_block_len = chunk_remaining;
-                    chunk_remaining = 0;
-                    break;
-                }
+        while(chunk_remaining > 0){
+            /*TODO: investigate assumption that we only ever receive chunks
+             * that contain full slitheen blocks */
 
-                //decrypt header to see if we have entire block
-                uint8_t *tmp_header = malloc(SLITHEEN_HEADER_LEN);
-                memcpy(tmp_header, p, SLITHEEN_HEADER_LEN);
+#ifdef DEBUG_PARSE
+            printf("Chunk remaining: %d bytes\n", chunk_remaining);
+#endif
 
-                if(!peek_header(tmp_header)){
-                    printf("This chunk doesn't contain a Slitheen block\n");
-                    break;
-                }
+            if(chunk_remaining < SLITHEEN_HEADER_LEN){
 
-                struct slitheen_hdr *sl_hdr = (struct slitheen_hdr *) tmp_header;
-                //first see if sl_hdr corresponds to a valid stream. If not, ignore rest of read bytes
 #ifdef DEBUG_PARSE
-                printf("Slitheen header:\n");
+                printf("Incomplete Slitheen block: ");
                 int i;
-                for(i = 0; i< SLITHEEN_HEADER_LEN; i++){
-                    printf("%02x ", tmp_header[i]);
+                for(i = 0; i< chunk_remaining; i++){
+                    printf("%02x ", p[i]);
                 }
                 printf("\n");
 #endif
-                if(ntohs(sl_hdr->len) > chunk_remaining){
-                    printf("ERROR: slitheen block doesn't fit in resource remaining!\n");
-                    printf("Saving in partial block\n");
-
-                    if(partial_block != NULL) printf("UH OH (PB)\n");
-                    partial_block = calloc(1, ntohs(sl_hdr->len));
-                    memcpy(partial_block, p, chunk_remaining);
-                    partial_block_len = chunk_remaining;
-                    chunk_remaining = 0;
-                    free(tmp_header);
-                    break;
-                }
+                /*
+                if(partial_block != NULL) printf("UH OH (PB)\n");
+
+                partial_block = calloc(1, chunk_remaining);
+                memcpy(partial_block, p, chunk_remaining);
+                partial_block_len = chunk_remaining;
+                chunk_remaining = 0;
+                */
+
+                break;
+            }
 
-                super_decrypt(p);
+            //decrypt header to see if we have entire block
+            uint8_t *tmp_header = malloc(SLITHEEN_HEADER_LEN);
+            memcpy(tmp_header, p, SLITHEEN_HEADER_LEN);
 
-                sl_hdr = (struct slitheen_hdr *) p;
+            if(!peek_header(tmp_header)){
+                printf("This chunk doesn't contain a Slitheen block\n");
+                break;
+            }
+
+            struct slitheen_hdr *sl_hdr = (struct slitheen_hdr *) tmp_header;
+            //first see if sl_hdr corresponds to a valid stream. If not, ignore rest of read bytes
+#ifdef DEBUG
+            printf("Slitheen header:\n");
+            int i;
+            for(i = 0; i< SLITHEEN_HEADER_LEN; i++){
+                printf("%02x ", tmp_header[i]);
+            }
+            printf("\n");
+#endif
+            if(ntohs(sl_hdr->len) > chunk_remaining){
+                printf("ERROR: slitheen block doesn't fit in resource remaining!\n");
+                printf("Saving in partial block\n");
+
+                if(partial_block != NULL) printf("UH OH (PB)\n");
+                partial_block = calloc(1, ntohs(sl_hdr->len));
+                memcpy(partial_block, p, chunk_remaining);
+                partial_block_len = chunk_remaining;
+                chunk_remaining = 0;
                 free(tmp_header);
+                break;
+            }
+
+            super_decrypt(p);
 
-                p += SLITHEEN_HEADER_LEN;
-                chunk_remaining -= SLITHEEN_HEADER_LEN;
+            sl_hdr = (struct slitheen_hdr *) p;
+            free(tmp_header);
 
-                if((!sl_hdr->len) && (sl_hdr->garbage)){
+            p += SLITHEEN_HEADER_LEN;
+            chunk_remaining -= SLITHEEN_HEADER_LEN;
+
+            if((!sl_hdr->len) && (sl_hdr->garbage)){
 
 #ifdef DEBUG_PARSE
-                    printf("%d Garbage bytes\n", ntohs(sl_hdr->garbage));
+                printf("%d Garbage bytes\n", ntohs(sl_hdr->garbage));
 #endif
-                    p += ntohs(sl_hdr->garbage);
-                    chunk_remaining -= ntohs(sl_hdr->garbage);
-                    continue;
-                }
 
-                int32_t sock =-1;
-                if(connections->first == NULL){
-                    printf("Error: there are no connections\n");
-                } else {
-                    connection *last = connections->first;
+                //there might be more garbage bytes than we have chunk left
+                p += ntohs(sl_hdr->garbage);
+                chunk_remaining -= ntohs(sl_hdr->garbage);
+                continue;
+            }
+
+            int32_t sock =-1;
+            if(connections->first == NULL){
+                printf("Error: there are no connections\n");
+            } else {
+                connection *last = connections->first;
+                if (last->stream_id == sl_hdr->stream_id){
+                    sock = last->socket;
+                }
+                while(last->next != NULL){
+                    last = last->next;
                     if (last->stream_id == sl_hdr->stream_id){
                         sock = last->socket;
                     }
-                    while(last->next != NULL){
-                        last = last->next;
-                        if (last->stream_id == sl_hdr->stream_id){
-                            sock = last->socket;
-                        }
-                    }
-                }
-				
-                if(sock == -1){
-                    printf("No stream id exists. Possibly invalid header\n");
-                    break;
                 }
-				
+            }
+
+            if(sock == -1){
+                printf("No stream id exists. Possibly invalid header\n");
+                break;
+            }
+
 #ifdef DEBUG_PARSE
-                printf("Received information for stream id: %d of length: %u\n", sl_hdr->stream_id, ntohs(sl_hdr->len));
+            printf("Received information for stream id: %d of length: %u\n", sl_hdr->stream_id, ntohs(sl_hdr->len));
 #endif
 
-                //figure out how much to skip
-                int32_t padding = 0;
-                if(ntohs(sl_hdr->len) %16){
-                    padding = 16 - ntohs(sl_hdr->len)%16;
-                }
-                p += 16; //IV
-
-                //check counter to see if we are missing data
-                if(sl_hdr->counter > expected_next_count){
-                    //save any future data
-                    printf("Received header with count %lu. Expected count %lu.\n",
-                                        sl_hdr->counter, expected_next_count);
-                    if((saved_data == NULL) || (saved_data->count > sl_hdr->counter)){
-                        data_block *new_block = malloc(sizeof(data_block));
-                        new_block->count = sl_hdr->counter;
-                        new_block->len = ntohs(sl_hdr->len);
-                        new_block->data = malloc(ntohs(sl_hdr->len));
-
-                        memcpy(new_block->data, p, ntohs(sl_hdr->len));
-
-                        new_block->socket = sock;
-                        new_block->next = saved_data;
-
-                        saved_data = new_block;
-
-                    } else {
-                        data_block *last = saved_data;
-                        while((last->next != NULL) && (last->next->count < sl_hdr->counter)){
-                            last = last->next;
-                        }
-                        data_block *new_block = malloc(sizeof(data_block));
-                        new_block->count = sl_hdr->counter;
-                        new_block->len = ntohs(sl_hdr->len);
-                        new_block->data = malloc(ntohs(sl_hdr->len));
-                        memcpy(new_block->data, p, ntohs(sl_hdr->len));
-                        new_block->socket = sock;
-                        new_block->next = last->next;
-
-                        last->next = new_block;
-                    }
+            //figure out how much to skip
+            int32_t padding = 0;
+            if(ntohs(sl_hdr->len) %16){
+                padding = 16 - ntohs(sl_hdr->len)%16;
+            }
+            p += 16; //IV
+
+            //check counter to see if we are missing data
+            if(sl_hdr->counter > expected_next_count){
+                //save any future data
+                printf("Received header with count %lu. Expected count %lu.\n",
+                        sl_hdr->counter, expected_next_count);
+                if((saved_data == NULL) || (saved_data->count > sl_hdr->counter)){
+                    data_block *new_block = malloc(sizeof(data_block));
+                    new_block->count = sl_hdr->counter;
+                    new_block->len = ntohs(sl_hdr->len);
+                    new_block->data = malloc(ntohs(sl_hdr->len));
+
+                    memcpy(new_block->data, p, ntohs(sl_hdr->len));
+
+                    new_block->socket = sock;
+                    new_block->next = saved_data;
+
+                    saved_data = new_block;
+
                 } else {
-                    int32_t bytes_sent = send(sock, p, ntohs(sl_hdr->len), 0);
+                    data_block *last = saved_data;
+                    while((last->next != NULL) && (last->next->count < sl_hdr->counter)){
+                        last = last->next;
+                    }
+                    data_block *new_block = malloc(sizeof(data_block));
+                    new_block->count = sl_hdr->counter;
+                    new_block->len = ntohs(sl_hdr->len);
+                    new_block->data = malloc(ntohs(sl_hdr->len));
+                    memcpy(new_block->data, p, ntohs(sl_hdr->len));
+                    new_block->socket = sock;
+                    new_block->next = last->next;
+
+                    last->next = new_block;
+                }
+            } else {
+                int32_t bytes_sent = send(sock, p, ntohs(sl_hdr->len), 0);
+                if(bytes_sent <= 0){
+                    printf("Error writing to socket for stream id %d\n", sl_hdr->stream_id);
+                }
+
+                //increment expected counter
+                expected_next_count++;
+            }
+
+            //now check to see if there is saved data to write out
+            if(saved_data != NULL){
+                data_block *current_block = saved_data;
+                while((current_block != NULL) && (expected_next_count == current_block->count)){
+                    int32_t bytes_sent = send(current_block->socket, current_block->data,
+                            current_block->len, 0);
                     if(bytes_sent <= 0){
                         printf("Error writing to socket for stream id %d\n", sl_hdr->stream_id);
                     }
-
-                    //increment expected counter
                     expected_next_count++;
+                    saved_data = current_block->next;
+                    free(current_block->data);
+                    free(current_block);
+                    current_block = saved_data;
                 }
+            }
 
-                //now check to see if there is saved data to write out
-                if(saved_data != NULL){
-                    data_block *current_block = saved_data;
-                    while((current_block != NULL) && (expected_next_count == current_block->count)){
-                        int32_t bytes_sent = send(current_block->socket, current_block->data, 
-                                current_block->len, 0);
-                        if(bytes_sent <= 0){
-                            printf("Error writing to socket for stream id %d\n", sl_hdr->stream_id);
-                        }
-                        expected_next_count++;
-                        saved_data = current_block->next;
-                        free(current_block->data);
-                        free(current_block);
-                        current_block = saved_data;
-                    }
-                }
+            p += ntohs(sl_hdr->len); //encrypted data
+            p += 16; //mac
+            p += padding;
+            p += ntohs(sl_hdr->garbage);
 
-                p += ntohs(sl_hdr->len); //encrypted data
-                p += 16; //mac
-                p += padding;
-                p += ntohs(sl_hdr->garbage);
+            chunk_remaining -= ntohs(sl_hdr->len) + 16 + padding + 16 + ntohs(sl_hdr->garbage);
 
-                chunk_remaining -= ntohs(sl_hdr->len) + 16 + padding + 16 + ntohs(sl_hdr->garbage);
+        }
 
-            }
+        free(buffer);
+        buffer = NULL;
 
-        } else {
-            printf("Error: read %d bytes from OUS_out\n", bytes_read);
-            goto err;
-        }
-		
     }
 err:
-    free(buffer);
+
+    if (buffer != NULL) {
+        free(buffer);
+    }
+
     close(pipes->out);
     pthread_exit(NULL);
 
@@ -852,5 +886,3 @@ int remove_connection(uint16_t stream_id){
 
     return 1;
 }
-
-

+ 23 - 23
client/socks5proxy.h

@@ -40,18 +40,18 @@ void *ous_IO();
 int remove_connection(uint16_t stream_id);
 
 struct __attribute__ ((__packed__)) slitheen_hdr {
-	uint64_t counter;
-	uint16_t stream_id;
-	uint16_t len;
-	uint16_t garbage;
-	uint16_t zeros;
+    uint64_t counter;
+    uint16_t stream_id;
+    uint16_t len;
+    uint16_t garbage;
+    uint16_t zeros;
 };
 
 #define SLITHEEN_HEADER_LEN 16
 
 struct __attribute__ ((__packed__)) slitheen_up_hdr{
-	uint16_t stream_id;
-	uint16_t len;
+    uint16_t stream_id;
+    uint16_t len;
 };
 
 #define NEW_STREAM 0
@@ -60,34 +60,34 @@ struct __attribute__ ((__packed__)) slitheen_up_hdr{
 
 
 typedef struct connection_st{
-	uint16_t stream_id;
-        int32_t socket;
-        uint8_t state;
-	struct connection_st *next;
+    uint16_t stream_id;
+    int32_t socket;
+    uint8_t state;
+    struct connection_st *next;
 } connection;
 
 typedef struct connection_table_st{
-	connection *first;
+    connection *first;
 } connection_table;
 
 typedef struct data_block_st {
-	uint64_t count;
-	uint8_t *data;
-        uint16_t len;
-        int32_t socket;
-	struct data_block_st *next;
+    uint64_t count;
+    uint8_t *data;
+    uint16_t len;
+    int32_t socket;
+    struct data_block_st *next;
 } data_block;
 
 struct socks_method_req {
-	uint8_t version;
-	uint8_t num_methods;
+    uint8_t version;
+    uint8_t num_methods;
 };
 
 struct socks_req {
-	uint8_t version;
-	uint8_t cmd;
-	uint8_t rsvd;
-	uint8_t addr_type;
+    uint8_t version;
+    uint8_t cmd;
+    uint8_t rsvd;
+    uint8_t addr_type;
 };
 
 #endif /* _SOCKS5PROXY_H_ */

+ 25 - 25
client/tagging.c

@@ -10,14 +10,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
@@ -47,7 +47,7 @@ byte twistpub[PTWIST_BYTES];
 
 
 static void gen_tag(byte *tag, byte stored_key[16],
-	const byte *context, size_t context_len)
+        const byte *context, size_t context_len)
 {
     byte seckey[PTWIST_BYTES];
     byte sharedsec[PTWIST_BYTES+context_len];
@@ -88,21 +88,21 @@ static void gen_tag(byte *tag, byte stored_key[16],
     value_to_hash[16+PTWIST_RESP_BYTES-1] &= PTWIST_RESP_MASK;
 
     while(1) {
-	unsigned int firstbits;
+        unsigned int firstbits;
 
-	md_map_sh256(hashout, value_to_hash, puzzle_len);
+        md_map_sh256(hashout, value_to_hash, puzzle_len);
 #if PTWIST_PUZZLE_STRENGTH < 32
-	/* This assumes that you're on an architecture that doesn't care
-	 * about alignment, and is little endian. */
-	firstbits = *(unsigned int*)hashout;
-	if ((firstbits & PTWIST_PUZZLE_MASK) == 0) {
-	    break;
-	}
-	/* Increment R and try again. */
-	for(i=0;i<PTWIST_RESP_BYTES;++i) {
-	    if (++value_to_hash[16+i]) break;
-	}
-	value_to_hash[16+PTWIST_RESP_BYTES-1] &= PTWIST_RESP_MASK;
+        /* This assumes that you're on an architecture that doesn't care
+         * about alignment, and is little endian. */
+        firstbits = *(unsigned int*)hashout;
+        if ((firstbits & PTWIST_PUZZLE_MASK) == 0) {
+            break;
+        }
+        /* Increment R and try again. */
+        for(i=0;i<PTWIST_RESP_BYTES;++i) {
+            if (++value_to_hash[16+i]) break;
+        }
+        value_to_hash[16+PTWIST_RESP_BYTES-1] &= PTWIST_RESP_MASK;
 #else
 #error "Code assumes PTWIST_PUZZLE_STRENGTH < 32"
 #endif
@@ -154,24 +154,24 @@ int generate_slitheen_id(byte *slitheen_id, byte stored_key[16])
     /* Read the public keys */
     fp = fopen("pubkey", "rb");
     if (fp == NULL) {
-		perror("fopen");
-		exit(1);
+        perror("fopen");
+        exit(1);
     }
     res = fread(mainpub, PTWIST_BYTES, 1, fp);
     if (res < 1) {
-		perror("fread");
-		exit(1);
+        perror("fread");
+        exit(1);
     }
     res = fread(twistpub, PTWIST_BYTES, 1, fp);
     if (res < 1) {
-		perror("fread");
-		exit(1);
+        perror("fread");
+        exit(1);
     }
     fclose(fp);
 
-	tag = slitheen_id;
+    tag = slitheen_id;
 
-	gen_tag(tag, stored_key, (const byte *)"context", 7);
+    gen_tag(tag, stored_key, (const byte *)"context", 7);
 
     return 0;
 }

+ 1 - 1
client/util.c

@@ -35,7 +35,7 @@ void *emalloc(size_t size){
     void *ptr = malloc(size);
     if (ptr == NULL){
         fprintf(stderr, "Memory failure. Exiting...\n");
-	exit(1);
+        exit(1);
     }
 
     return ptr;

+ 2 - 2
relay_station/Makefile

@@ -4,9 +4,9 @@ TARGETS=slitheen
 
 all: $(TARGETS)
 
-packet.o flow.o ptwist168.o crypto.o relay.o cryptothread.o util.o:: ptwist.h flow.h packet.h crypto.h relay.h cryptothread.h util.h
+webm.o packet.o flow.o ptwist168.o crypto.o relay.o cryptothread.o util.o:: ptwist.h flow.h packet.h crypto.h relay.h cryptothread.h util.h webm.h
 
-slitheen: slitheen.c packet.o flow.o ptwist168.o crypto.o relay.o cryptothread.o util.o relay.h crypto.h ptwist.h flow.h packet.h cryptothread.h util.h
+slitheen: slitheen.c packet.o flow.o ptwist168.o crypto.o relay.o cryptothread.o util.o webm.o webm.h relay.h crypto.h ptwist.h flow.h packet.h cryptothread.h util.h
 	gcc -g -ggdb -o $@ $^ -L/usr/local/lib -I/usr/local/include -lssl -lcrypto -lpcap -lpthread -ldl
 
 clean:

+ 27 - 11
relay_station/crypto.c

@@ -358,7 +358,7 @@ int extract_parameters(flow *f, uint8_t *hs){
 
         f->dh = dh;
     } else if (f->keyex_alg == 2){
-        EC_KEY *ecdh;
+        EC_KEY *ecdh = NULL;
         EC_GROUP *ngroup;
         const EC_GROUP *group;
 
@@ -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 */

+ 3 - 0
relay_station/flow.c

@@ -184,6 +184,9 @@ flow *add_flow(struct packet_info *info) {
     new_flow->remaining_record_len = 0;
     new_flow->remaining_response_len = 0;
     new_flow->httpstate = PARSE_HEADER;
+    new_flow->webmstate = 0;
+    new_flow->remaining_element = 0;
+    new_flow->element_header = 0;
     new_flow->replace_response = 0;
 
     new_flow->ecdh = NULL;

+ 5 - 0
relay_station/flow.h

@@ -167,6 +167,11 @@ typedef struct flow_st {
     uint32_t remaining_response_len;
     uint8_t replace_response;
 
+    //webm state machine
+    uint8_t webmstate;
+    uint64_t remaining_element;
+    uint32_t element_header;
+
     uint8_t *outbox;
     int32_t outbox_len;
     int32_t outbox_offset;

+ 53 - 24
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 {
@@ -92,7 +93,6 @@ typedef struct stream_table_st {
 
 static int process_downstream(flow *f, int32_t offset, struct packet_info *info);
 static int read_header(flow *f, struct packet_info *info);
-static int fill_with_downstream(flow *f, uint8_t *data, int32_t length);
 static void *proxy_covert_site(void *data);
 
 /** Called when a TLS application record is received for a
@@ -242,7 +242,7 @@ static int read_header(flow *f, struct packet_info *info){
                 last->next = new_block;
             }
 
-            f->upstream_remaining = record_length - new_block->len;
+            f->upstream_remaining = record_length + RECORD_HEADER_LEN - new_block->len;
             return 0;
         }
     }
@@ -269,7 +269,9 @@ static int read_header(flow *f, struct packet_info *info){
     }
 
     DEBUG_MSG(DEBUG_UP, "Upstream data: (%x:%d > %x:%d )\n",info->ip_hdr->src.s_addr,ntohs(info->tcp_hdr->src_port), info->ip_hdr->dst.s_addr, ntohs(info->tcp_hdr->dst_port));
-    DEBUG_MSG(DEBUG_UP, "%s\n", decrypted_data+EVP_GCM_TLS_EXPLICIT_IV_LEN);
+    DEBUG_MSG(DEBUG_UP, "Data for flow %p:\n%s\n", f, decrypted_data+EVP_GCM_TLS_EXPLICIT_IV_LEN);
+    DEBUG_MSG(DEBUG_UP, "Bytes for flow %p (%d bytes):\n", f, decrypted_len);
+    DEBUG_BYTES(DEBUG_UP, (decrypted_data + EVP_GCM_TLS_EXPLICIT_IV_LEN), decrypted_len);
 
     /* search through decrypted data for x-ignore */
     char *header_ptr = strstr((const char *) decrypted_data+EVP_GCM_TLS_EXPLICIT_IV_LEN, "X-Slitheen");
@@ -458,7 +460,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 +738,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 +802,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 +811,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 +868,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 +934,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 +1012,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->replace_response = 0;
+                            f->webmstate = WEBM_HEADER;
+                            //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 = 0;
+                                f->webmstate = WEBM_HEADER;
+                                //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 +1127,13 @@ 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->remaining_response_len - remaining_record_len == 0){
+                                fprintf(stderr, "quitting\n");
+                            }
+                        }
+
                         if(f->replace_response){
                             fill_with_downstream(f, p, remaining_record_len);
 
@@ -1122,13 +1144,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;
@@ -1227,7 +1252,7 @@ static int process_downstream(flow *f, int32_t offset, struct packet_info *info)
             }
         }
 
-        if(changed && f->replace_response){
+        if(changed && (f->replace_response || f->webmstate)){
             DEBUG_MSG(DEBUG_DOWN, "Resource is now:\n");
             DEBUG_BYTES(DEBUG_DOWN, (record_ptr + EVP_GCM_TLS_EXPLICIT_IV_LEN), n);
             DEBUG_MSG(DEBUG_DOWN, "Text:\n%s\n", record_ptr+EVP_GCM_TLS_EXPLICIT_IV_LEN);
@@ -1241,7 +1266,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 +1321,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;
         }
 
@@ -1329,7 +1358,7 @@ static int process_downstream(flow *f, int32_t offset, struct packet_info *info)
  *  	length: The length of the downstream data required
  *
  */
-static int fill_with_downstream(flow *f, uint8_t *data, int32_t length){
+int fill_with_downstream(flow *f, uint8_t *data, int32_t length){
 
     uint8_t *p = data;
     int32_t remaining = length;

+ 1 - 0
relay_station/relay.h

@@ -54,6 +54,7 @@ extern client_table *clients;
 int replace_packet(flow *f, struct packet_info *info);
 uint16_t tcp_checksum(struct packet_info *info);
 
+int fill_with_downstream(flow *f, uint8_t *data, int32_t length);
 #define BEGIN_HEADER 0x10
 #define PARSE_HEADER 0x20
 #define MID_CONTENT 0x30

+ 32 - 4
relay_station/slitheen.c

@@ -258,11 +258,39 @@ void process_packet(struct inject_args *iargs, const struct pcap_pkthdr *header,
 
             if(observed->application){
                 if(seq_num > expected_seq){
-                    //For now, enters into FORFEIT state
-                    //TODO: change upstream behaviour to try to mask slitheen hdr
-                    //printf("ERROR: future packet in app data, forfeiting flow\n");
+                    /*For now, enters into FORFEIT state
+                    fprintf(stderr,"ERROR: future packet in app data, forfeiting flow\n");
+                    fflush(stderr);
                     remove_flow(observed);
-                    goto err;
+                    goto err;*/
+
+                    //Delay and process later
+                    frame *new_frame = scalloc(1, sizeof(frame));
+                    new_frame->iargs = iargs;
+                    new_frame->packet = packet;
+                    new_frame->header = header;
+                    new_frame->seq_num = seq_num;
+                    new_frame->next = NULL;
+                    frame_queue *queue = (incoming) ? observed->ds_frame_queue : observed->us_frame_queue;
+                    printf("Delay processing of frame (seq = %u )\n", seq_num);
+
+                    //add to end of list
+                    if(queue->first_frame == NULL){
+                        queue->first_frame = new_frame;
+                    } else {
+                        frame *last = queue->first_frame;
+                        while(last->next != NULL){
+                            last = last->next;
+                        }
+                        last->next = new_frame;
+                    }
+
+                    free(info);
+                    observed->ref_ctr--;
+                    printf("Misordered packet. %p ref_ctr %d\n", observed, observed->ref_ctr);
+
+                    return; //TODO: fix terrible spaghetti returns
+
                 }
 
                 replace_packet(observed, info);

+ 9 - 3
relay_station/tests/Makefile

@@ -1,16 +1,22 @@
 CC=gcc
 CFLAGS=-g -ggdb -Wall -std=gnu99
 
-TARGETS=check_tagged check_handshake
+TARGETS=check_tagged check_handshake test_webm test_partial_aes
 
 all: $(TARGETS)
 
 test_util.o: test_util.h
 
-check_tagged: check_tagged.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
+check_tagged: check_tagged.c test_util.o ../flow.c ../crypto.o ../relay.o ../cryptothread.o ../ptwist168.o ../packet.o ../util.o ../webm.o ../flow.h ../crypto.h ../relay.h ../cryptothread.h ../ptwist.h ../packet.h ../util.h ../webm.h
 	gcc -g -ggdb -o $@ $^ -L/usr/local/lib -I/usr/local/include -lssl -lcrypto -ldl -lpthread -lpcap -lcheck_pic -lrt -lm -lsubunit
 
-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
+check_handshake: check_handshake.c test_util.o ../flow.c ../crypto.o ../relay.o ../cryptothread.o ../ptwist168.o ../packet.o ../util.o ../webm.o ../flow.h ../crypto.h ../relay.h ../cryptothread.h ../ptwist.h ../packet.h ../util.h ../webm.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 ../webm.o ../flow.h ../crypto.h ../relay.h ../cryptothread.h ../ptwist.h ../packet.h ../util.h ../webm.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
 
 clean:

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


BIN
relay_station/tests/data/webm_0x7fd590016250


+ 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;
+}

+ 25 - 0
relay_station/tests/test_util.c

@@ -58,3 +58,28 @@ int32_t read_file(const char *path, uint8_t **target){
 
     return result;
 }
+
+int32_t read_file_len(const char *path, uint8_t **target, int32_t *len){
+
+    FILE *fp;
+    int32_t fsize;
+
+    fp = fopen(path, "rb");
+    if (fp == NULL) {
+        perror("fopen");
+        return 0;
+    }
+
+    fseek(fp, 0, SEEK_END);
+    fsize = ftell(fp);
+    fseek(fp, 0, SEEK_SET);
+    *target = smalloc(fsize);
+
+    int32_t result = fread(*target, fsize, 1, fp);
+
+    *len = fsize;
+
+    fclose(fp);
+
+    return result;
+}

+ 1 - 0
relay_station/tests/test_util.h

@@ -28,6 +28,7 @@
 #define TEST_UTIL_H
 
 int32_t read_file(const char *path, uint8_t **target);
+int32_t read_file_len(const char *path, uint8_t **target, int32_t *len);
 
 #endif /* TEST_UTIL_H */
 

+ 162 - 0
relay_station/tests/test_webm.c

@@ -0,0 +1,162 @@
+/** test_webm.c
+ *
+ * Unit tests for the relay station webm parser
+ */
+
+#include <check.h>
+#include "../flow.h"
+#include "test_util.h"
+#include "../webm.h"
+#include "../webm.c"
+
+START_TEST(variable_header_parser) {
+    //set up common webm length field
+    uint8_t *p = malloc(4);
+
+    p[0] = 0x1a;
+    p[1] = 0x45;
+    p[2] = 0xdf;
+    p[3] = 0xa3;
+
+    uint8_t header_len;
+    uint32_t header = variable_header(p, &header_len);
+
+    ck_assert_int_eq(header_len, 4);
+    ck_assert_int_eq(header, 0x1a45dfa3);
+}
+END_TEST
+
+START_TEST(variable_length_parser) {
+
+    uint8_t *p = malloc(8);
+
+    p[0] = 0x9f;
+    p[1] = 0x00;
+    p[2] = 0x00;
+    p[3] = 0x00;
+
+    uint8_t int_len;
+    uint32_t len = variable_length(p, &int_len);
+
+    ck_assert_int_eq(int_len, 1);
+    ck_assert_int_eq(len, 0x1f);
+
+    p[0] = 0x21;
+    p[1] = 0x0d;
+    p[2] = 0x8c;
+    p[3] = 0x00;
+
+    len = variable_length(p, &int_len);
+
+    ck_assert_int_eq(int_len, 3);
+    ck_assert_int_eq(len, 0x10d8c);
+}
+END_TEST
+
+START_TEST(webm_parser) {
+
+    //need to create a flow for this
+    flow *f = smalloc(sizeof(flow));
+
+    //we only need to set the webmstate and remaining_element fields of the flow
+    f->webmstate = WEBM_HEADER;
+    f->remaining_element = 0;
+
+    uint8_t *data;
+    int32_t file_len;
+
+    /* Read in webm data */
+    if(!read_file_len("data/webm_0x7fd590016250", &data, &file_len)){
+        ck_abort();
+    }
+
+    uint8_t *p = data;
+    parse_webm(f, p, 8);
+
+    //The remaining element length should be the element length (31) - the extra
+    //three bytes we parsed (28)
+    ck_assert_int_eq(f->remaining_element, 28);
+
+    ck_assert_int_eq(f->webmstate, MID_ELEMENT);
+
+    p += 8;
+    file_len -= 8;
+
+    //Parse the rest of the header
+    parse_webm(f, p, 28);
+
+    ck_assert_int_eq(f->remaining_element, 0);
+
+    ck_assert_int_eq(f->webmstate, WEBM_HEADER);
+
+    p+= 28;
+    file_len -= 28;
+
+    //Now parse segment header
+    parse_webm(f, p, 16);
+
+    //ck_assert_int_eq(f->webmstate, MID_ELEMENT);
+
+    p+= 16;
+    file_len -= 16;
+
+    parse_webm(f, p, 185);
+    ck_assert_int_eq(f->webmstate, WEBM_HEADER);
+
+    //Detect cluster element ID
+    p += 185;
+    file_len -= 185;
+
+    ck_assert_int_eq(p[0], 0x1f);
+    ck_assert_int_eq(p[1], 0x43);
+    ck_assert_int_eq(p[2], 0xb6);
+    ck_assert_int_eq(p[3], 0x75);
+
+    //Parse into media element
+    //parse_webm(f, p, 8);
+
+    //ck_assert_int_eq(f->webmstate, MEDIA);
+
+    //parse to end of file
+    //p += 8;
+    //file_len -= 8;
+
+    parse_webm(f, p, file_len);
+
+    free(data);
+
+}
+END_TEST
+
+Suite *webm_suite(void) {
+    Suite *s;
+    TCase *tc_core;
+
+    s = suite_create("WebM Parser");
+
+    tc_core = tcase_create("Core");
+    tcase_add_test(tc_core, variable_header_parser);
+    tcase_add_test(tc_core, variable_length_parser);
+    tcase_add_test(tc_core, webm_parser);
+    suite_add_tcase(s, tc_core);
+
+    return s;
+}
+
+int main(void){
+
+    int number_failed;
+    Suite *s;
+    SRunner *sr;
+
+    s = webm_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);
+
+    return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}

+ 225 - 0
relay_station/webm.c

@@ -0,0 +1,225 @@
+/* Name: webm.c
+ *
+ * This file contains functions for manipulating tagged flows.
+ *
+ * Slitheen - a decoy routing system for censorship resistance
+ * Copyright (C) 2018 Cecylia Bocovich (cbocovic@uwaterloo.ca)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * 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),
+ * 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
+ * non-source form of such a combination shall include the source code
+ * for the parts of the OpenSSL library used as well as that of the covered
+ * work.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+
+#include "webm.h"
+#include "flow.h"
+#include "relay.h"
+
+static uint64_t variable_length(uint8_t *p, uint8_t *int_length);
+static uint32_t variable_header(uint8_t *p, uint8_t *int_length);
+
+/**
+ * Parses the webm content type
+ *
+ * Returns 0 on success 1 on failure
+ */
+int32_t parse_webm(flow *f, uint8_t *ptr, uint32_t len) {
+
+    if(!f->webmstate){
+        //make sure this is a webm resource
+        return 1;
+    }
+
+    uint8_t *p = ptr;
+    uint32_t remaining_len = len;
+
+    while (remaining_len){
+        switch (f->webmstate){
+            uint8_t header_len, int_len;
+            case WEBM_HEADER:
+                if(remaining_len < 8){
+                    //TODO:right now this assumes we'll have the header + size
+                    // but later we should make it work with just the header
+                    // also the size should be 8 bytes max
+                    //this will be difficult to parse
+                    printf("PARSE FAIL: too little len remaining\n");
+                    return 1;
+                }
+
+                //Parse header:
+                f->element_header = variable_header(p, &header_len);
+
+                printf("Received header: %x\n", f->element_header);
+
+                if((f->element_header == 0xa3) &&
+                        (remaining_len >= (SLITHEEN_HEADER_LEN + 9))){
+                    //we want to replace this block
+                    printf("Replaced simple block!\n");
+                    p[0] = 0xef;
+                }
+
+                p += header_len;
+                remaining_len -= header_len;
+
+                //parse length of header
+                f->remaining_element = variable_length(p, &int_len);
+
+                p += int_len;
+                remaining_len -= int_len;
+
+                printf("element length: %lu\n", f->remaining_element);
+
+                f->webmstate = PARSE_ELEMENT;
+
+                break;
+            case PARSE_ELEMENT:
+
+                switch(f->element_header) {
+
+                    case  0x18538067: //segment
+                    case 0x1f43b675: //cluster
+                    // do nothing. Move on to parsing sub-element
+                    f->webmstate = WEBM_HEADER;
+
+                    break;
+                    case 0xa3: //simple block
+
+                    f->webmstate = BLOCK_HEADER;
+
+                    break;
+                    default:
+                    //we want to skip this element
+                    f->webmstate = MID_ELEMENT;
+                    break;
+
+                }
+                break;
+            case MID_ELEMENT: {
+
+                uint32_t parse_len = (f->remaining_element <= remaining_len) ?
+                    f->remaining_element : remaining_len;
+
+                if (f->element_header == 0xa3) {
+                    //replace content
+
+                    fill_with_downstream(f, p, parse_len);
+
+                    printf("Replaced data (%d bytes):\n", parse_len);
+                    for(int i=0; i< parse_len; i++){
+                        printf("%02x ", p[i]);
+                    }
+                    printf("\n");
+                }
+
+                p += parse_len;
+                remaining_len -= parse_len;
+                f->remaining_element -= parse_len;
+
+                if (f->remaining_element == 0) {
+                    f->webmstate = WEBM_HEADER;
+                }
+                break;
+            }
+            case BLOCK_HEADER:
+                //TODO: expand to handle lacing, non-simple blocks
+                if(remaining_len < 4){
+                    //TODO: fix this somehow
+                    printf("PARSE FAIL: too little len remaining\n");
+                    return 1;
+                }
+
+                p += 4;
+                f->remaining_element -= 4;
+                remaining_len -= 4;
+
+                f->webmstate = MID_ELEMENT;
+
+                break;
+        }
+    }
+
+    printf("Remaining element: %lu\n", f->remaining_element);
+
+    return 0;
+}
+
+static uint64_t variable_length(uint8_t *p, uint8_t *int_length){
+
+    //first check for length of int
+    uint8_t count = 1;
+    uint32_t mask = 1 << 7;
+
+    uint64_t len;
+
+    while (count < 8) {
+        if ((p[0] & mask) != 0) {
+            break;
+        }
+
+        mask >>= 1;
+        count += 1;
+    }
+
+    *int_length = count;
+
+    //now calculate the integer
+    len = p[0] & ~mask;
+
+    for(int i=1; i< count; i++){
+        len <<= 8;
+        len |= p[i];
+    }
+
+    return len;
+}
+
+static uint32_t variable_header(uint8_t *p, uint8_t *int_length){
+
+    //first check for length of int
+    uint8_t count = 1;
+    uint32_t mask = 1 << 7;
+
+    uint32_t len;
+
+    while (count < 4) {
+        if ((p[0] & mask) != 0) {
+            break;
+        }
+
+        mask >>= 1;
+        count += 1;
+    }
+
+    *int_length = count;
+
+    //now calculate the integer
+    len = p[0];
+
+    for(int i=1; i< count; i++){
+        len <<= 8;
+        len |= p[i];
+    }
+
+    return len;
+}

+ 42 - 0
relay_station/webm.h

@@ -0,0 +1,42 @@
+/* Slitheen - a decoy routing system for censorship resistance
+ * Copyright (C) 2018 Cecylia Bocovich (cbocovic@uwaterloo.ca)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * 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),
+ * 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
+ * non-source form of such a combination shall include the source code
+ * for the parts of the OpenSSL library used as well as that of the covered
+ * work.
+ */
+#ifndef WEBM_H
+#define WEBM_H
+
+#include "flow.h"
+
+int32_t parse_webm(flow *f, uint8_t *ptr, uint32_t len);
+
+/* WebM states */
+
+#define WEBM_HEADER 0x01
+#define PARSE_ELEMENT 0x02
+#define MID_ELEMENT 0x03
+#define BLOCK_HEADER 0x04
+
+#endif /* WEBM_H */
+