Browse Source

extra encryption layer (minus header encryption)

cecylia 7 years ago
parent
commit
e0e938f982
6 changed files with 549 additions and 26 deletions
  1. 300 12
      client/socks5proxy.c
  2. 177 1
      relay_station/crypto.c
  3. 7 0
      relay_station/crypto.h
  4. 57 12
      relay_station/relay.c
  5. 6 0
      relay_station/relay.h
  6. 2 1
      relay_station/slitheen.h

+ 300 - 12
client/socks5proxy.c

@@ -22,6 +22,9 @@
 #include <openssl/buffer.h>
 
 #define SLITHEEN_ID_LEN 10
+#define SLITHEEN_SUPER_SECRET_SIZE 10
+#define SLITHEEN_SUPER_CONST "SLITHEEN_SUPER_ENCRYPT"
+#define SLITHEEN_SUPER_CONST_SIZE 22
 
 #define NEW
 
@@ -32,7 +35,8 @@ struct __attribute__ ((__packed__)) slitheen_hdr {
 	uint64_t counter;
 	uint16_t stream_id;
 	uint16_t len;
-	uint32_t garbage;
+	uint16_t garbage;
+	uint16_t zeros;
 };
 
 #define SLITHEEN_HEADER_LEN 16
@@ -54,6 +58,16 @@ typedef struct connection_table_st{
 
 static connection_table *connections;
 
+typedef struct super_data_st {
+	//EVP_CIPHER_CTX *header_ctx;
+	//EVP_CIPHER_CTX *body_ctx;
+	uint8_t *header_key;
+	uint8_t *body_key;
+	EVP_MD_CTX *body_mac_ctx;
+} super_data;
+
+static super_data *super;
+
 int main(void){
 	int listen_socket;
 	
@@ -73,6 +87,9 @@ int main(void){
 	}
 	printf("\n");
 
+	// Calculate super encryption keys
+	generate_super_keys(slitheen_id);
+
 	//b64 encode slitheen ID
 	const char *encoded_bytes;
 	BUF_MEM *buffer_ptr;
@@ -107,7 +124,7 @@ int main(void){
 		return 1;
 	}
 	uint8_t *message = calloc(1, BUFSIZ);
-	sprintf(message, "POST / HTTP/1.1\r\nContent-Length: %d\r\n\r\n%s ", strlen(encoded_bytes), encoded_bytes);
+	sprintf(message, "POST / HTTP/1.1\r\nContent-Length: %zd\r\n\r\n%s ", strlen(encoded_bytes), encoded_bytes);
 	int32_t bytes_sent = send(ous_in, message, strlen(message), 0);
 	printf("Wrote %d bytes to OUS_in: %s\n", bytes_sent, message);
 	free(message);
@@ -214,6 +231,170 @@ int main(void){
 	return 0;
 }
 
+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){
+
+    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 *out = output;
+
+    EVP_MD_CTX_init(&ctx);
+    EVP_MD_CTX_init(&ctx_tmp);
+    EVP_MD_CTX_init(&ctx_init);
+    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_cleanup(&ctx);
+    EVP_MD_CTX_cleanup(&ctx_tmp);
+    EVP_MD_CTX_cleanup(&ctx_init);
+    OPENSSL_cleanse(A, sizeof(A));
+    return 0;
+}
+/*
+ * Generate the keys for the super encryption layer, based on the slitheen ID
+ */
+int generate_super_keys(uint8_t *secret){
+
+	super = calloc(1, sizeof(super_data));
+	
+	//need 2 encryption keys, 2 ivs, and a mac
+	//EVP_CIPHER_CTX *hdr_ctx;
+    //EVP_CIPHER_CTX *bdy_ctx;
+    EVP_MD_CTX *mac_ctx;
+
+    const EVP_MD *md = EVP_sha256();
+
+    /* Generate Keys */
+    uint8_t *hdr_key, *hdr_iv;
+    uint8_t *bdy_key, *bdy_iv;
+    uint8_t *mac_secret;
+    EVP_PKEY *mac_key;
+    int32_t mac_len, key_len, iv_len;
+
+    key_len = EVP_CIPHER_key_length(EVP_aes_256_cbc());
+    iv_len = EVP_CIPHER_iv_length(EVP_aes_256_cbc());
+    mac_len = EVP_MD_size(md);
+    int32_t total_len = 2*key_len + 2*iv_len + mac_len;
+    uint8_t *key_block = calloc(1, total_len);
+
+    PRF(secret, SLITHEEN_SUPER_SECRET_SIZE,
+            (uint8_t *) SLITHEEN_SUPER_CONST, SLITHEEN_SUPER_CONST_SIZE,
+            NULL, 0,
+            NULL, 0,
+            NULL, 0,
+            key_block, total_len);
+
+//#ifdef DEBUG
+	int i;
+    printf("secret: \n");
+    for(i=0; i< SLITHEEN_SUPER_SECRET_SIZE; i++){
+        printf("%02x ", secret[i]);
+    }
+    printf("\n");
+    printf("keyblock: \n");
+    for(i=0; i< total_len; i++){
+        printf("%02x ", key_block[i]);
+    }
+    printf("\n");
+//#endif
+
+    hdr_key = key_block;
+    bdy_key = key_block + key_len;
+    hdr_iv = key_block + 2*key_len;
+    bdy_iv = key_block + 2*key_len + iv_len;
+    mac_secret = key_block + 2*key_len + 2*iv_len;
+
+    /* Initialize Cipher Contexts */
+    //hdr_ctx = EVP_CIPHER_CTX_new();
+    //bdy_ctx = EVP_CIPHER_CTX_new();
+
+    //EVP_CipherInit_ex(hdr_ctx, EVP_aes_128_ecb(), NULL, hdr_key, NULL, 0);
+    //EVP_CipherInit_ex(bdy_ctx, EVP_aes_256_cbc(), NULL, bdy_key, bdy_iv, 0);
+
+    /* Initialize MAC Context */
+    mac_ctx = EVP_MD_CTX_create();
+
+    EVP_DigestInit_ex(mac_ctx, md, NULL);
+    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_ctx = hdr_ctx;
+    //super->body_ctx = bdy_ctx;
+	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;
+}
+
 struct socks_method_req {
 	uint8_t version;
 	uint8_t num_methods;
@@ -374,7 +555,7 @@ int proxy_data(int sockfd, uint16_t stream_id, int32_t ous_out){
 
 #ifdef NEW
 	uint8_t *message = calloc(1, BUFSIZ);
-	sprintf(message, "POST / HTTP/1.1\r\nContent-Length: %d\r\n\r\n%s ", strlen(encoded_bytes)+1, encoded_bytes);
+	sprintf(message, "POST / HTTP/1.1\r\nContent-Length: %zd\r\n\r\n%s ", strlen(encoded_bytes)+1, encoded_bytes);
 	bytes_sent = send(ous_in, message, strlen(message), 0);
 	printf("Wrote %d bytes to OUS_in: %s\n", bytes_sent, message);
 #endif
@@ -478,7 +659,7 @@ int proxy_data(int sockfd, uint16_t stream_id, int32_t ous_out){
 					goto err;
 				}
 
-				sprintf(message, "POST / HTTP/1.1\r\nContent-Length: %d\r\n\r\n%s ", strlen(encoded_bytes)+1, encoded_bytes);
+				sprintf(message, "POST / HTTP/1.1\r\nContent-Length: %zd\r\n\r\n%s ", strlen(encoded_bytes)+1, encoded_bytes);
 				bytes_sent = send(ous_in, message, strlen(message), 0);
 				close(ous_in);
 
@@ -541,7 +722,7 @@ int proxy_data(int sockfd, uint16_t stream_id, int32_t ous_out){
 					return 1;
 				}
 
-				sprintf(message, "POST / HTTP/1.1\r\nContent-Length: %d\r\n\r\n%s ", strlen(encoded_bytes)+1, encoded_bytes);
+				sprintf(message, "POST / HTTP/1.1\r\nContent-Length: %zd\r\n\r\n%s ", strlen(encoded_bytes)+1, encoded_bytes);
 				bytes_sent = send(ous_in, message, strlen(message), 0);
 				printf("Sent to OUS (%d bytes):%s\n",bytes_sent, message);
 				close(ous_in);
@@ -684,6 +865,8 @@ void *demultiplex_data(){
 					break;
 				}
 
+				super_decrypt(p);
+
 				struct slitheen_hdr *sl_hdr = (struct slitheen_hdr *) p;
 				//first see if sl_hdr corresponds to a valid stream. If not, ignore rest of read bytes
 //#ifdef DEBUG
@@ -707,12 +890,12 @@ void *demultiplex_data(){
 				p += SLITHEEN_HEADER_LEN;
 				bytes_remaining -= SLITHEEN_HEADER_LEN;
 
-				if(sl_hdr->garbage){
+				if((!sl_hdr->len) && (sl_hdr->garbage)){
 //#ifdef DEBUG
-					printf("Garbage bytes\n");
+					printf("%d Garbage bytes\n", ntohs(sl_hdr->garbage));
 //#endif
-					p += ntohs(sl_hdr->len);
-					bytes_remaining -= ntohs(sl_hdr->len);
+					p += ntohs(sl_hdr->garbage);
+					bytes_remaining -= ntohs(sl_hdr->garbage);
 					continue;
 				}
 
@@ -743,13 +926,29 @@ void *demultiplex_data(){
 				
 				printf("Received information for stream id: %d of length: %u\n", sl_hdr->stream_id, ntohs(sl_hdr->len));
 
-				int32_t bytes_sent = write(pipe_fd, p, ntohs(sl_hdr->len));
+				//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
+
+				int32_t bytes_sent = write(pipe_fd, p, ntohs(sl_hdr->len) - padding);
 				if(bytes_sent <= 0){
 					printf("Error reading to pipe for stream id %d\n", sl_hdr->stream_id);
 				}
 
-				p += ntohs(sl_hdr->len);
-				bytes_remaining -= ntohs(sl_hdr->len);
+				p += ntohs(sl_hdr->len); //encrypted data
+				p += 16; //mac
+				p += padding;
+				p += ntohs(sl_hdr->garbage);
+				printf("Skipped %d garbage bytes\n", ntohs(sl_hdr->garbage));
+				fflush(stdout);
+				bytes_remaining -= 
+					ntohs(sl_hdr->len) + 16 + padding + 16 + ntohs(sl_hdr->garbage);
+				printf("Bytes remaining: %d, padding: %d\n", bytes_remaining, padding);
 			}
 
 		} else {
@@ -765,3 +964,92 @@ void *demultiplex_data(){
 	close(ous_fd);
 
 }
+
+int super_decrypt(uint8_t *data){
+
+	EVP_CIPHER_CTX *bdy_ctx;
+
+	uint8_t *p = data;
+	int32_t out_len, len;
+	uint8_t output[EVP_MAX_MD_SIZE];
+	size_t mac_len;
+	int i;
+
+	/*decrypt header
+	printf("Encrypted header:\n");
+	for(i=0; i< SLITHEEN_HEADER_LEN; i++){
+		printf("%02x ", p[i]);
+	}
+	printf("\n");
+
+	if(!EVP_CipherUpdate(super->header_ctx, p, &out_len, p, SLITHEEN_HEADER_LEN)){
+		printf("Decryption failed!");
+		return 0;
+	}
+	*/
+
+	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);
+	
+	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
+		return 1;
+	}
+
+	p += SLITHEEN_HEADER_LEN;
+
+	//compute mac
+	EVP_DigestSignUpdate(super->body_mac_ctx, p, len);
+
+    EVP_DigestSignFinal(super->body_mac_ctx, output, &mac_len);
+
+#ifdef DEBUG
+	printf("Received mac:\n");
+	for(i=0; i< 16; i++){
+		printf("%02x ", p[len+i]);
+	}
+	printf("\n");
+	fflush(stdout);
+	if(memcmp(p+len, output, 16)){
+		printf("MAC verification failed\n");
+		return 0;
+	}
+#endif
+
+	//decrypt body
+    bdy_ctx = EVP_CIPHER_CTX_new();
+
+    EVP_CipherInit_ex(bdy_ctx, EVP_aes_256_cbc(), NULL, super->body_key, p, 0);
+
+	p+=16;//skip IV
+
+	printf("Encrypted data (%d bytes):\n", len);
+	for(i=0; i< len; i++){
+		printf("%02x ", p[i]);
+	}
+	printf("\n");
+
+	if(!EVP_CipherUpdate(bdy_ctx, p, &out_len, p, len+16)){
+		printf("Decryption failed!");
+		return 0;
+	}
+
+	EVP_CIPHER_CTX_free(bdy_ctx);
+
+	printf("Decrypted data (%d bytes):\n", out_len);
+	for(i=0; i< out_len; i++){
+		printf("%02x ", p[i]);
+	}
+	printf("\n");
+	fflush(stdout);
+
+	p += out_len;
+
+	return 1;
+
+}

+ 177 - 1
relay_station/crypto.c

@@ -28,6 +28,7 @@
 #include "flow.h"
 #include "slitheen.h"
 #include "util.h"
+#include "relay.h"
 
 #define NID_sect163k1           721
 #define NID_sect163r1           722
@@ -737,7 +738,12 @@ int PRF(flow *f, uint8_t *secret, int32_t secret_len,
 
 	EVP_MD_CTX ctx, ctx_tmp, ctx_init;
 	EVP_PKEY *mac_key;
-	const EVP_MD *md = f->message_digest;
+	const EVP_MD *md;
+	if(f == NULL){
+		md = EVP_sha256();
+	} else {
+		md = f->message_digest;
+	}
 
 	uint8_t A[EVP_MAX_MD_SIZE];
 	size_t len, A_len;
@@ -987,6 +993,176 @@ void update_context(flow *f, uint8_t *input, int32_t len, int32_t incoming, int3
 	free(output);
 }
 
+/* Generate the keys for a client's super encryption layer
+ * 
+ * The header of each downstream slitheen data chunk is 16 bytes and encrypted with
+ * a 256 bit AES key
+ *
+ * The body of each downstream chunk is CBC encrypted with a 256 bit AES key
+ *
+ * The last 16 bytes of the body is a MAC over the body
+ *
+ */
+void generate_client_super_keys(uint8_t *secret, client *c){
+
+	//EVP_CIPHER_CTX *hdr_ctx;
+	//EVP_CIPHER_CTX *bdy_ctx;
+	EVP_MD_CTX *mac_ctx;
+
+	const EVP_MD *md = EVP_sha256();
+
+	/* Generate Keys */
+	uint8_t *hdr_key, *bdy_key;
+	uint8_t *mac_secret;
+	EVP_PKEY *mac_key;
+	int32_t mac_len, key_len;
+
+	key_len = EVP_CIPHER_key_length(EVP_aes_256_cbc());
+	mac_len = EVP_MD_size(md);
+	int32_t total_len = 2*key_len + mac_len;
+	uint8_t *key_block = ecalloc(1, total_len);
+
+	PRF(NULL, secret, SLITHEEN_SUPER_SECRET_SIZE,
+			(uint8_t *) SLITHEEN_SUPER_CONST, SLITHEEN_SUPER_CONST_SIZE,
+			NULL, 0,
+			NULL, 0,
+			NULL, 0,
+			key_block, total_len);
+
+//#ifdef DEBUG
+	printf("secret: \n");
+	for(int i=0; i< SLITHEEN_SUPER_SECRET_SIZE; i++){
+		printf("%02x ", secret[i]);
+	}
+	printf("\n");
+
+	printf("keyblock: \n");
+	for(int i=0; i< total_len; i++){
+		printf("%02x ", key_block[i]);
+	}
+	printf("\n");
+//#endif
+
+	hdr_key = key_block;
+	bdy_key = key_block + key_len;
+	mac_secret = key_block + 2*key_len;
+
+	/* Initialize Cipher Contexts */
+	//hdr_ctx = EVP_CIPHER_CTX_new();
+	//bdy_ctx = EVP_CIPHER_CTX_new();
+
+	//EVP_CipherInit_ex(hdr_ctx, EVP_aes_128_ecb(), NULL, hdr_key, NULL, 1);
+	//EVP_CipherInit_ex(bdy_ctx, EVP_aes_256_cbc(), NULL, bdy_key, bdy_iv, 1);
+
+	/* Initialize MAC Context */
+	mac_ctx = EVP_MD_CTX_create();
+	
+	EVP_DigestInit_ex(mac_ctx, md, NULL);
+	mac_key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, mac_secret, mac_len);
+	EVP_DigestSignInit(mac_ctx, NULL, md, NULL, mac_key);
+
+	//c->header_ctx = hdr_ctx;
+	//c->body_ctx = bdy_ctx;
+	c->header_key = emalloc(key_len);
+	c->body_key = emalloc(key_len);
+
+	memcpy(c->header_key, hdr_key, key_len);
+	memcpy(c->body_key, bdy_key, key_len);
+
+	c->mac_ctx = mac_ctx;
+
+	//Free everything
+	free(key_block);
+	EVP_PKEY_free(mac_key);
+
+	return;
+
+}
+
+int super_encrypt(client *c, uint8_t *data, uint32_t len){
+
+	//EVP_CIPHER_CTX *hdr_ctx;
+	EVP_CIPHER_CTX *bdy_ctx;
+	
+	int32_t out_len;
+	size_t mac_len;
+	uint8_t *p = data;
+
+	uint8_t output[EVP_MAX_MD_SIZE];
+
+	/*first encrypt the header	
+	printf("Plaintext Header:\n");
+	for(int i=0; i< SLITHEEN_HEADER_LEN; i++){
+		printf("%02x ", p[i]);
+	}
+	printf("\n");
+
+	if(!EVP_CipherUpdate(c->header_ctx, p, &out_len, p, SLITHEEN_HEADER_LEN)){
+		printf("Failed!\n");
+		return 0;
+	}
+
+	printf("Encrypted Header (%d bytes)\n", out_len);
+	for(int i=0; i< out_len; i++){
+		printf("%02x ", p[i]);
+	}
+	printf("\n");
+	*/
+
+	//encrypt the body
+	p += SLITHEEN_HEADER_LEN;
+
+	//generate IV
+	RAND_bytes(p, 16);
+
+	//set up cipher ctx
+	bdy_ctx = EVP_CIPHER_CTX_new();
+
+	EVP_CipherInit_ex(bdy_ctx, EVP_aes_256_cbc(), NULL, c->body_key, p, 1);
+	
+	p+= 16;
+
+	printf("Plaintext:\n");
+	for(int i=0; i< len; i++){
+		printf("%02x ", p[i]);
+	}
+	printf("\n");
+
+	if(!EVP_CipherUpdate(bdy_ctx, p, &out_len, p, len)){
+		printf("Failed!\n");
+		return 0;
+	}
+
+	printf("Encrypted %d bytes\n", out_len);
+	printf("Encrypted data:\n");
+	for(int i=0; i< out_len; i++){
+		printf("%02x ", p[i]);
+	}
+	printf("\n");
+	
+	//MAC at the end
+	EVP_DigestSignUpdate(c->mac_ctx, p, out_len);
+
+	EVP_DigestSignFinal(c->mac_ctx, output, &mac_len);
+	printf("Produced a %zd byte mac:\n", mac_len);
+	for(int i=0; i< mac_len; i++){
+		printf("%02x ", output[i]);
+	}
+	printf("\n");
+
+	p += out_len;
+	memcpy(p, output, 16);
+
+	printf("Copied 16 bytes:\n");
+	for(int i=0; i< 16; i++){
+		printf("%02x ", p[i]);
+	}
+	printf("\n");
+	EVP_CIPHER_CTX_free(bdy_ctx);
+
+	return 1;
+}
+
 /** Checks a handshake message to see if it is tagged or a
  *  recognized flow. If the client random nonce is tagged,
  *  adds the flow to the flow table to be tracked.

+ 7 - 0
relay_station/crypto.h

@@ -7,6 +7,7 @@
 #define n2s(c,s)        ((s=(((unsigned int)(c[0]))<< 8)| \
 							(((unsigned int)(c[1]))    )),c+=2)
 
+
 /* Curves */
 
 
@@ -26,6 +27,8 @@ int update_finish_hash(flow *f, uint8_t *hs);
 int verify_finish_hash(flow *f, uint8_t *p, int32_t incoming);
 int init_ciphers(flow *f);
 void update_context(flow *f, uint8_t *input, int32_t len, int32_t incoming, int32_t type, int32_t enc);
+void generate_client_super_keys(uint8_t *secret, client *c);
+int super_encrypt(client *c, uint8_t *data, uint32_t len);
 void check_handshake(struct packet_info *info);
 
 int check_tag(byte key[16], const byte privkey[PTWIST_BYTES],
@@ -36,4 +39,8 @@ int check_tag(byte key[16], const byte privkey[PTWIST_BYTES],
 #define SLITHEEN_KEYGEN_CONST "SLITHEEN_KEYGEN"
 #define SLITHEEN_KEYGEN_CONST_SIZE 15
 
+#define SLITHEEN_SUPER_SECRET_SIZE 10 //TODO: make this larger/different (Right now SLITHEEN_ID_LEN)
+#define SLITHEEN_SUPER_CONST "SLITHEEN_SUPER_ENCRYPT"
+#define SLITHEEN_SUPER_CONST_SIZE 22
+
 #endif

+ 57 - 12
relay_station/relay.c

@@ -331,6 +331,7 @@ int read_header(flow *f, struct packet_info *info){
 				if(!memcmp(last->slitheen_id, p, output_len)){
 					f->streams = last->streams;
 					f->downstream_queue = last->downstream_queue;
+					f->client_ptr = last; //TODO: clean this up
 					break;
 #ifdef DEBUG
 				} else {
@@ -362,6 +363,9 @@ int read_header(flow *f, struct packet_info *info){
 	
 				new_client->next = NULL;
 
+				/* Now generate super encryption keys */ //TODO: use tagging trick
+				generate_client_super_keys(new_client->slitheen_id, new_client);
+
 				//add to client table
 				if(clients->first == NULL){
 					clients->first = new_client;
@@ -1205,7 +1209,7 @@ int process_downstream(flow *f, int32_t offset, struct packet_info *info){
  *  	length: The length of the downstream data required
  *
  */
-
+//TODO: change hard-coded values to depend on cipher
 int fill_with_downstream(flow *f, uint8_t *data, int32_t length){
 
 	uint8_t *p = data;
@@ -1215,10 +1219,19 @@ int fill_with_downstream(flow *f, uint8_t *data, int32_t length){
 	data_queue *downstream_queue = f->downstream_queue;
 	client *client_ptr = f->client_ptr;
 
+	printf("Filling with %d bytes\n", length);
+
 	//Fill as much as we can from the censored_queue
 	//Note: need enough for the header and one block of data (16 byte IV, 16 byte
 	//		block, 16 byte MAC) = header_len + 48.
 	while((remaining > (SLITHEEN_HEADER_LEN + 48)) && downstream_queue != NULL && downstream_queue->first_block != NULL){
+
+		//amount of data we'll actualy fill with (16 byte IV and 16 byte MAC)
+		int32_t fill_amount = remaining - SLITHEEN_HEADER_LEN - 32;
+		fill_amount -= fill_amount % 16; //rounded down to nearest block size
+
+		printf("Fill amount: %d\n", fill_amount);
+
 		queue_block *first_block = downstream_queue->first_block;
 		int32_t block_length = first_block->len;
 		int32_t offset = first_block->offset;
@@ -1229,21 +1242,27 @@ int fill_with_downstream(flow *f, uint8_t *data, int32_t length){
 		printf("We need %d bytes\n", remaining - SLITHEEN_HEADER_LEN);
 #endif
 		
+		uint8_t *encrypted_data = p;
 		sl_hdr = (struct slitheen_header *) p;
 		sl_hdr->counter = ++(client_ptr->encryption_counter);
 		sl_hdr->stream_id = first_block->stream_id;
 		sl_hdr->len = 0x0000;
 		sl_hdr->garbage = 0x0000;
+		sl_hdr->zeros = 0x0000;
 		p += SLITHEEN_HEADER_LEN;
 		remaining -= SLITHEEN_HEADER_LEN;
 
-		if(block_length > offset + remaining){
+		p += 16; //iv length
+		remaining -= 16;
+
+
+		if(block_length > offset + fill_amount){
 			//use part of the block, update offset
-			memcpy(p, first_block->data+offset, remaining);
-			first_block->offset += remaining;
-			p += remaining;
-			sl_hdr->len = remaining;
-			remaining -= remaining;
+			memcpy(p, first_block->data+offset, fill_amount);
+			first_block->offset += fill_amount;
+			p += fill_amount;
+			sl_hdr->len = fill_amount;
+			remaining -= fill_amount;
 		} else {
 			//use all of the block and free it
 			memcpy(p, first_block->data+offset, block_length - offset);
@@ -1256,6 +1275,31 @@ int fill_with_downstream(flow *f, uint8_t *data, int32_t length){
 			sl_hdr->len = (block_length - offset);
 			remaining -= (block_length - offset);
 		}
+
+		//pad to 16 bytes if necessary
+		uint8_t padding = 0;
+		if(sl_hdr->len %16){
+			padding = 16 - (sl_hdr->len)%16;
+			memset(p, padding, padding);
+			remaining -= padding;
+			p += padding;
+		}
+
+		//now encrypt
+		printf("Filled with %d bytes\n", sl_hdr->len);
+		super_encrypt(client_ptr, encrypted_data, sl_hdr->len + padding);
+		p += 16;
+		remaining -= 16;
+
+		//fill rest of packet with padding, if needed
+		if(remaining < SLITHEEN_HEADER_LEN){
+			printf("Padding with %d garbage bytes\n", remaining);
+			RAND_bytes(p, remaining);
+			sl_hdr->garbage = htons(remaining);
+			p += remaining;
+			remaining -= remaining;
+		}
+
 		sl_hdr->len = htons(sl_hdr->len);
 
 //#ifdef DEBUG
@@ -1265,7 +1309,7 @@ int fill_with_downstream(flow *f, uint8_t *data, int32_t length){
 		}
 		printf("\n");
 		printf("Sending %d downstream bytes:", ntohs(sl_hdr->len));
-		for(int i=0; i< ntohs(sl_hdr->len); i++){
+		for(int i=0; i< ntohs(sl_hdr->len)+16+16 + ntohs(sl_hdr->garbage); i++){
 			printf("%02x ", ((uint8_t *) sl_hdr)[i+SLITHEEN_HEADER_LEN]);
 		}
 		printf("\n");
@@ -1278,8 +1322,9 @@ int fill_with_downstream(flow *f, uint8_t *data, int32_t length){
 		sl_hdr->counter = 0x00;
 		sl_hdr->stream_id = 0x00;
 		remaining -= SLITHEEN_HEADER_LEN;
-		sl_hdr->len = htons(remaining);
-		sl_hdr->garbage = htons(remaining);//TODO: change this to a bit
+		sl_hdr->len = 0x00;
+		sl_hdr->garbage = htons(remaining);
+		sl_hdr->zeros = 0x0000;
 
 //#ifdef DEBUG
 		printf("DWNSTRM: slitheen header: ");
@@ -1291,9 +1336,9 @@ int fill_with_downstream(flow *f, uint8_t *data, int32_t length){
 
 		p += SLITHEEN_HEADER_LEN;
 		RAND_bytes(p, remaining);
-	} else {
+	} else if(remaining > 0){
 		//fill with random data
-		printf("Less than 16 bytes remaining, had to fill with random\n");
+		printf("UH OH! Less than 16 bytes remaining, had to fill with random\n");
 		RAND_bytes(p, remaining);
 	}
 

+ 6 - 0
relay_station/relay.h

@@ -19,6 +19,12 @@ typedef struct client_st {
 	data_queue *downstream_queue;
 	uint16_t encryption_counter;
 	struct client_st *next;
+	uint8_t *header_key;
+	uint8_t *body_key;
+	//uint8_t *mac_key
+	//EVP_CIPHER_CTX *header_ctx;
+	//EVP_CIPHER_CTX *body_ctx;
+	EVP_MD_CTX *mac_ctx;
 } client;
 
 typedef struct client_table_st {

+ 2 - 1
relay_station/slitheen.h

@@ -78,7 +78,8 @@ struct __attribute__((__packed__)) slitheen_header {
 	uint64_t counter;
 	uint16_t stream_id; /* determines which stream the data is from */
 	uint16_t len;
-	uint32_t garbage;
+	uint16_t garbage;
+	uint16_t zeros;
 };
 
 #define SLITHEEN_HEADER_LEN 16