diff options
| -rw-r--r-- | lib/lib2.c | 121 | ||||
| -rw-r--r-- | lib/lib2.h | 7 | ||||
| -rw-r--r-- | set2/task12.c | 66 | ||||
| -rw-r--r-- | set2/task14.c | 45 |
4 files changed, 216 insertions, 23 deletions
@@ -214,44 +214,51 @@ int detect_blocksize_ecb(char *text, int length_text, char *key) return i-1; } -/** - * cracks one AES-ECB block - */ -int crack_aes_ecb(char *text, int length_text, char *plaintext, char *key, int blocksize) + +int crack_aes_ecb(char **plaintext, int blocksize, int offset) { - char *to_encrypt_block = malloc(length_text + 17); + int prepend_data = offset ? 1 : 0; + int fill_in = offset % blocksize; + if(fill_in) { + fill_in = blocksize-fill_in; + offset += fill_in; + } + printf("offset must now be multiple of 16: %i\n", offset % blocksize); + char *attacker_data = malloc(17+fill_in); + int length_plaintext; char **ciphertexts= malloc(sizeof(char*)*blocksize); + int *ciphertext_length = malloc(sizeof(char*)*blocksize); char *cipher_block = malloc(blocksize+1); char *prefix = malloc(blocksize+1); int i,j; - + // encrypt text prepended with A, AA, AAA, ... + memset(attacker_data, 0, 17+fill_in); for(i=0;i<blocksize;i++) { - ciphertexts[i] = malloc(length_text + 17); - memcpy(&to_encrypt_block[i],text, length_text); // fill it with our controlled input - memset(to_encrypt_block, 0x54, i); - // encrypt the block - aes_ecb(to_encrypt_block, blocksize, ciphertexts[i], key, 16, 1); + memset(attacker_data, 0x54, i+fill_in); + // encrypt the text + ciphertext_length[i] = challenge12_and_14_oracle(attacker_data, i+fill_in,&ciphertexts[i], prepend_data); + //aes_ecb(to_encrypt_block, (length_plaintext+17), ciphertexts[i], key, 16, 1); } + length_plaintext = ciphertext_length[0]; // we have all ciphertexts now to crack the whole plaintext - // let's go! + // let's go! + *plaintext = malloc(length_plaintext); - memset(plaintext, 0, length_text); + memset(*plaintext, 0, length_plaintext); // for every block - for(i=1;i<2;i++) { + for(i=0;i<=(length_plaintext-offset)/blocksize;i++) { for(j=blocksize-1;j>=0;j--) { if(i==0) memset(prefix, 0x54, blocksize); else - memcpy(prefix, &text[((i-1)*blocksize)+blocksize-j], blocksize); - memcpy(&prefix[j], &text[i*blocksize], blocksize-j); - printf("prefix:%s\nendprefix\n", prefix); - memcpy(cipher_block, &(ciphertexts[j][i*blocksize]), blocksize); - plaintext[i*blocksize+blocksize-1-j] = create_dictionary_and_match(prefix, cipher_block, key, blocksize); + memcpy(prefix, &((*plaintext)[((i-1)*blocksize)+blocksize-j]), blocksize); + + memcpy(&prefix[j], &((*plaintext)[i*blocksize]), blocksize-j); + memcpy(cipher_block, &(ciphertexts[j][i*blocksize+offset]), blocksize); + (*plaintext)[i*blocksize+blocksize-1-j] = create_dictionary_and_match(prefix, cipher_block, key, blocksize); } - printf("plaintext so far: %s\n", plaintext); } - } char create_dictionary_and_match(char *prefix, char *match, char *key, int blocksize_bytes) @@ -265,7 +272,7 @@ char create_dictionary_and_match(char *prefix, char *match, char *key, int block memcpy(dict_string, prefix, blocksize_bytes); for(i=0;i<255;i++) { dict_string[blocksize_bytes-1] = (char) i; - printf("%s\n", dict_string); + //printf("%s\n", dict_string); aes_ecb(dict_string, blocksize_bytes, cipher_block, key, blocksize_bytes, 1); hex_binary_to_string(cipher_block, hex_tmp, blocksize_bytes); // printf("%s\n", hex_tmp); @@ -276,6 +283,76 @@ char create_dictionary_and_match(char *prefix, char *match, char *key, int block } } + +int challenge12_and_14_oracle(char *attacker_data, int attacker_data_length, char **ciphertext, int prepend_data) +{ + // target data + char *base64_task_string = "Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkgaGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBqdXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUgYnkK"; + + char *target_data= malloc(strlen(base64_task_string)); + // unbases it + int length_cleartext = decode_base64(base64_task_string, target_data); + + static char *prepend = ""; + static int prepend_length = 0; + + // generate random prefix only the first time + if(prepend_length == 0 && prepend_data) { + prepend_length = random_number_between(17,200); + printf("prepend %i bytes (%i full blocks)\n", prepend_length, prepend_length/16); + prepend = malloc(prepend_length); + generate_random_bytes(prepend, prepend_length); + } + + //target_data = ""; + + // mix to one big string and encrypt + int plaintext_length = prepend_length+attacker_data_length+strlen(target_data); + char *plaintext = malloc(plaintext_length); + *ciphertext = malloc(plaintext_length); + memcpy(plaintext, prepend, prepend_length); + memcpy(&plaintext[prepend_length], attacker_data, attacker_data_length); + memcpy(&plaintext[prepend_length+attacker_data_length], target_data, strlen(target_data)); + + aes_ecb(plaintext, plaintext_length, *ciphertext, key, 16, 1); + return plaintext_length; +} + +#define BLOCKSIZE 16 +int aes_ecb_detect_prepended_data() +{ + int i; + int prepend_bytes; + char *ciphertext_round; + char *ciphertext_without; + char a_block[2*BLOCKSIZE+1]; + char a_block_enc[BLOCKSIZE+1]; + + memset(a_block, 'A', 2*BLOCKSIZE); + a_block[2*BLOCKSIZE+1] = '\0'; + + int number_equal_blocks = 0; + int ciphertext_without_len = challenge12_and_14_oracle(a_block,0, &ciphertext_without, 1); + int ciphertext_round_len = challenge12_and_14_oracle(a_block, 2*BLOCKSIZE, &ciphertext_round, 1); + + // count equal blocks + for(i=0;i<(ciphertext_round_len/BLOCKSIZE);i++) { + if(memcmp(&ciphertext_without[i*BLOCKSIZE], &ciphertext_round[i*BLOCKSIZE], BLOCKSIZE)) + break; + } + prepend_bytes = i*BLOCKSIZE; + aes_ecb(a_block, BLOCKSIZE, a_block_enc, key, BLOCKSIZE, 1); + for(i=BLOCKSIZE*2;i>0;i--) { + a_block[i] = '\0'; + challenge12_and_14_oracle(a_block, i, &ciphertext_round, 1); + if(memcmp(a_block_enc, &ciphertext_round[prepend_bytes+16], BLOCKSIZE)) + break; + } + + prepend_bytes += (2*BLOCKSIZE-i-1); + return prepend_bytes; +} + struct key_value_pair *parse_key_value(char *string, int length_string) { char *str1, *str2, *tmp, *tmp2; @@ -13,6 +13,7 @@ struct key_value_pair { char key[17]; char iv[17]; +char nonce[17]; char *pkcs7_padding(char *string, int length_string, int blocksize); char *__pkcs7_padding(char *string, int length_string, int blocksize, int *padding); @@ -25,10 +26,14 @@ int random_number_between(int min, int max); char *encrypt_with_random_bytes(char *toencrypt, int length, int ecb); char create_dictionary_and_match(char *prefix, char *match, char *key, int blocksize_bytes); int detect_blocksize_ecb(char*,int,char*); -int crack_aes_ecb(char *text, int length_text, char *plaintext_block, char *key, int blocksize); +int crack_aes_ecb(char **plaintext, int blocksize, int offset); struct key_value_pair *parse_key_value(char *string, int length_string); char *profile_for(char *email); void send_user(char *encrypted_user, int length); int challenge16_encrypt(char *input, char **encrypted); void challenge16_decrypt(char *encrypted, int length); +int challenge12_and_14_oracle(char *attacker_data, int attacker_data_lengthn, char **ciphertext, int prepend_data); +int aes_ecb_detect_prepended_data(); + + #endif diff --git a/set2/task12.c b/set2/task12.c new file mode 100644 index 0000000..de6bba5 --- /dev/null +++ b/set2/task12.c @@ -0,0 +1,66 @@ +#include "../lib/lib.h" +#include "../lib/lib2.h" +#include <time.h> +/** + * So what are we doing here? + * We do not know the key. But we can ask Alice to encrypt with here key + * an arbritrary plaintext we give here. From the ciphertext she gives us + * we can infer the original plaintext. A is attacker controlled plaintext. + * P stands for plaintext we don't now. + * K is plaintext we alredy know. + * + * with block size 16 we do: + * AAAAAAAAAAAAAAAP + * in the next round we know P, + * AAAAAAAAAAAAAAKP + * and next round: + * AAAAAAAAAAAAAKKP + * and so one until we know the complete block + * + * crack the second block: you now already the first block: + * AAAAAAAAAAAAAAAK KKKKKKKKKKKKKKKP + * you are not interested in the first block now, but in the P of + * the last block. Since you now all the other K's in the second block + * already you can crak P now. And so on. + * + * It is sufficient to make BLOCKSIZE encryption request to Alice to break + * a plaintext of arbitrary length. + */ + + +int main(int argc, char **argv) +{ + + int i; + + srand(time(NULL)); + char *base64_task_string = "Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkgaGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBqdXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUgYnkK"; + + // generate random key once + generate_random_bytes(key, 16); + + char *task_string = malloc(strlen(base64_task_string)); + char *plaintext; + // unbases it + int length_cleartext = decode_base64(base64_task_string, task_string); + // cleartext + maybe an additional block + char *ciphertext = malloc(length_cleartext+17); + // encrypt + aes_ecb(task_string, length_cleartext, ciphertext, key, 16, 1); + + // discover the block size of the cipher + int blocksize = detect_blocksize_ecb(task_string, length_cleartext, key); + printf("Detected blocksize: %i\n", blocksize); + + // detect if it uses ECB + printf("REAL PLAINTEXT:\n%s\n", task_string); + char *test_string = "Benedict ist ein wirklicher, echter Mensch mit Wurzeln im Boden"; + crack_aes_ecb(&plaintext, blocksize, 0); + + printf("Recovered plaintext:\n%s\n", plaintext); + // make dictionary of every possible last byte by feedind different + // string to the oracle function, e.g. AAAAAAAA, AAAAAAAB, AAAAAAAC + //Match the output of the one-byte-short input to one of the + // entries in your dictionary. + return 0; +} diff --git a/set2/task14.c b/set2/task14.c new file mode 100644 index 0000000..586d174 --- /dev/null +++ b/set2/task14.c @@ -0,0 +1,45 @@ +#include "../lib/lib.h" +#include "../lib/lib2.h" +#include <time.h> + +/** + * This time there is a random amount of random data before our + * data. This is that annoys us. If we would one where our data + * would begin all would be fine, we would do the same as in task12 + * But since we are using ECB blocks din't change with the random data. + * So we make a first request with our data empty and than make a second + * request with one byte. Than we compere the results. The blocks which + * contain the random data keep the same, exceot the last, because we + * probably append our byte into that block instead of the first byte of + * our target string. Now we now how many blocks of random data are before + * our data. + * To get the excat number of bytes, we add two blocksof A's. So one block is + * for sure filled just with A's. Than we remove A's until the block of A's + * change because our traget data get into it. Then blocksize-Removed A's + * is the offset block where our data start. + * 16*unchanged_blocks + BLOKCSIZE-RemovedA's + * + * +**/ +#define BLOCKSIZE 16 +int main(int argc, char **argv) +{ + srand(time(NULL)); + generate_random_bytes(key, 16); + // cleartext + maybe an additional block + + int prepended_data_len = aes_ecb_detect_prepended_data(); + + printf("prepended data len: %i\n", prepended_data_len); + + // so now we now the offset where our data get inserted + // ignoring everything befor offset we now have to do the same + // as in task12 + // well in task13 we make the assumtion that we start at a fresh block + // so maybe at some garbage to fill the rest block + + char *plaintext; + crack_aes_ecb(&plaintext, 16, prepended_data_len); + + printf("recovered data:\n%s\n", plaintext); +} |
