diff --git a/Makefile b/Makefile index 0c038bb..c47ba57 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ INC=. LIBS=-lcrypto -lssl -CFLAGS=-g +CFLAGS=-g -fno-inline SRC_C_FILES := $(wildcard src/*.c) SRC_CPP_FILES := $(wildcard src/*.cpp) diff --git a/prj/Matasano.sublime-workspace b/prj/Matasano.sublime-workspace index a8ebec7..430c7f7 100644 --- a/prj/Matasano.sublime-workspace +++ b/prj/Matasano.sublime-workspace @@ -539,7 +539,7 @@ "file": "/home/flowher/repos/MatasanoCrypto/sol/set2.c", "settings": { - "buffer_size": 14912, + "buffer_size": 15030, "line_ending": "Unix" } }, @@ -547,7 +547,7 @@ "file": "/home/flowher/repos/MatasanoCrypto/src/enc_modes.c", "settings": { - "buffer_size": 6097, + "buffer_size": 6483, "line_ending": "Unix" } }, @@ -1438,7 +1438,7 @@ "groups": [ { - "selected": 2, + "selected": 3, "sheets": [ { @@ -1505,15 +1505,15 @@ "semi_transient": false, "settings": { - "buffer_size": 14912, + "buffer_size": 15030, "regions": { }, "selection": [ [ - 1293, - 1293 + 7854, + 7854 ] ], "settings": @@ -1523,10 +1523,10 @@ "translate_tabs_to_spaces": true }, "translation.x": 0.0, - "translation.y": 0.0, + "translation.y": 2856.0, "zoom_level": 1.0 }, - "stack_index": 0, + "stack_index": 1, "type": "text" }, { @@ -1535,15 +1535,15 @@ "semi_transient": false, "settings": { - "buffer_size": 6097, + "buffer_size": 6483, "regions": { }, "selection": [ [ - 2901, - 2901 + 6003, + 6003 ] ], "settings": @@ -1553,10 +1553,10 @@ "translate_tabs_to_spaces": true }, "translation.x": 0.0, - "translation.y": 753.0, + "translation.y": 1821.0, "zoom_level": 1.0 }, - "stack_index": 1, + "stack_index": 0, "type": "text" }, { diff --git a/sol/set2.c b/sol/set2.c index e4d5df4..37d5c77 100644 --- a/sol/set2.c +++ b/sol/set2.c @@ -10,42 +10,38 @@ #include #include #include +#include "set2.h" -struct OpenSSL +Result_t OpenSSL::Cbc(CryptoAttribs_t* i_attribs, + const Key_t* const i_key) { - static Result_t Cbc(CryptoAttribs_t* i_attribs, - const Key_t* const i_key) + if(NULL==i_attribs->output) { - if(NULL==i_attribs->output) - { - i_attribs->output = (uint8_t*) malloc(i_attribs->input_len) + 1; - } - - int ret=0; - EVP_CIPHER_CTX ctx; - EVP_CIPHER_CTX_init(&ctx); - OP_CHECK( - EVP_CipherInit_ex(&ctx, EVP_aes_128_cbc(), NULL, i_key->key, i_attribs->iv, - i_attribs->operation==kEncrypt ? 1 : 0)); - EVP_CIPHER_CTX_set_padding(&ctx, 0); - EVP_CIPHER_CTX_set_key_length(&ctx, i_key->len); - - OP_CHECK( - EVP_CipherUpdate(&ctx, &i_attribs->output[ret], &ret, i_attribs->input, - i_attribs->input_len)); - i_attribs->output_len = ret; - OP_CHECK( - EVP_CipherFinal_ex(&ctx, &i_attribs->output[ret], &ret)); - i_attribs->output_len += ret; - EVP_CIPHER_CTX_cleanup(&ctx); - return Result_OK; - - end: - return Result_Error; + i_attribs->output = (uint8_t*) malloc(i_attribs->input_len); } -}; + int ret=0; + EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init(&ctx); + OP_CHECK( + EVP_CipherInit_ex(&ctx, EVP_aes_128_cbc(), NULL, i_key->key, i_attribs->iv, + i_attribs->operation==kEncrypt ? 1 : 0)); + EVP_CIPHER_CTX_set_padding(&ctx, 0); + EVP_CIPHER_CTX_set_key_length(&ctx, i_key->len); + + OP_CHECK( + EVP_CipherUpdate(&ctx, i_attribs->output, &ret, i_attribs->input, + i_attribs->input_len)); + i_attribs->output_len = ret; + OP_CHECK( + EVP_CipherFinal_ex(&ctx, &i_attribs->output[ret], &ret)); + i_attribs->output_len += ret; + EVP_CIPHER_CTX_cleanup(&ctx); + return Result_OK; +end: + return Result_Error; +} TCASE(ecb_encrypt_decrypt_single_block) { @@ -101,7 +97,7 @@ TCASE(pkcs7_test) } size_t unpad_len = 0; - CHECK( true == pkcs7_unpad(&buff1[0], 32, &p_unpadded, &unpad_len) ); + CHECK( pkcs7_unpad(&buff1[0], 32, &p_unpadded, &unpad_len) ); CHECK(unpad_len == 5, (const uint8_t*) "Unpadded length wrong"); CHECK( 0==memcmp(text1, unpadded, unpad_len) ); } @@ -189,11 +185,6 @@ TCASE(encode_decode_openssl) uint8_t concatenated_blocks[16*3]; uint8_t iv1[16] = {0}; uint8_t key[17] = "YELLOW SUBMARINE"; // 16+'\0' = 17 - uint8_t* ciphertext = NULL; - size_t ciphertext_len = 0; - uint8_t* out = NULL; - size_t out_len = 0; - Result_t res = Result_Error; memset(concatenated_blocks, 2, 16); memset(&concatenated_blocks[16], 5, 16); memset(&concatenated_blocks[32], 9, 16); @@ -215,8 +206,7 @@ TCASE(encode_decode_openssl) attribs_openssl_enc.iv_len = sizeof(iv1); attribs_openssl_enc.operation = kEncrypt; CHECK(OpenSSL::Cbc(&attribs_openssl_enc, &keyObj)==Result_OK); - CHECK(attribs_openssl_enc.output_len==48, (uint8_t*)"Ciphertext has wrong size"); - + CHECK(attribs_openssl_enc.output_len==48, (uint8_t*)"Ciphertext has wrong size");// CryptoAttribs_t cbc_attribs; CryptoAttribs_t::Init(&cbc_attribs); cbc_attribs.input = attribs_openssl_enc.output; @@ -242,6 +232,8 @@ TCASE(encode_decode_openssl) attribs_enc.iv_len = sizeof(iv1); attribs_enc.operation = kEncrypt; CHECK( Result_OK == cbc_encrypt(&attribs_enc, &keyObj) ); + CHECK( 48 == attribs_enc.output_len ); + CHECK( NULL != attribs_enc.output ); CryptoAttribs_t attribs_openssl_dec; CryptoAttribs_t::Init(&attribs_openssl_dec); @@ -286,12 +278,11 @@ uint8_t check_ciphertext(const uint8_t* ciphertext, uint32_t len ) return 0; // All checked blocks are the same -> ECB } -Result_t encryption_oracle( - const uint8_t* pt, - uint32_t pt_len, - uint8_t* ct, - uint32_t* ct_len, - uint8_t* mode) +Result_t encryption_oracle( const uint8_t* pt, + uint32_t pt_len, + uint8_t* ct, + uint32_t* ct_len, + uint8_t* mode) { uint8_t iv1[16] = {0}; uint8_t key[16] = {0}; @@ -303,7 +294,7 @@ Result_t encryption_oracle( CryptoAttribs_t attribs; Key_t keyObj; - // seed randomnes + // get seed for good randomnes clock_gettime(CLOCK_MONOTONIC, &tv); srand((unsigned int)tv.tv_nsec); @@ -319,9 +310,9 @@ Result_t encryption_oracle( // initialize encryption attribs CryptoAttribs_t::Init(&attribs); attribs.operation = kEncrypt; - attribs.input_len = (5*16) + prepend_byte_size + append_byte_size; - attribs.input = (uint8_t*)malloc(attribs.input_len); - attribs.output_len = 7*16; + attribs.input_len = 0; + attribs.input = (uint8_t*)malloc(7*16); + attribs.output_len = 0; attribs.output = (uint8_t*)malloc(7*16); attribs.padding = kPadding_PKCS7; @@ -335,54 +326,71 @@ Result_t encryption_oracle( RAND_bytes(random_bytes, append_byte_size); memcpy(attribs.input+tmplen, random_bytes, append_byte_size); tmplen+=append_byte_size; + attribs.input_len = tmplen; // key Key_t::Init(&keyObj); keyObj.key = key; keyObj.len = 16; - if(encryption_mode) - { - attribs.iv = (uint8_t*)malloc(16); - attribs.iv_len = 16; - RAND_bytes(attribs.iv, 16); - if( Result_OK!=cbc_encrypt(&attribs, &keyObj) ) - return Result_Error; - } - else + Result_t ret = Result_OK; + do { - if( Result_OK!=ecb_encrypt(&attribs, &keyObj) ) - return Result_Error; - } + if(encryption_mode) + { + attribs.iv = (uint8_t*)malloc(16); + attribs.iv_len = 16; + RAND_bytes(attribs.iv, 16); + if( Result_OK!=cbc_encrypt(&attribs, &keyObj) ) + { + ret = Result_Error; + break; + } + } + else + { + if( Result_OK!=ecb_encrypt(&attribs, &keyObj) ) + { + ret = Result_Error; + break; + } + } - // Copy results - memcpy(ct, attribs.output, attribs.output_len); - *ct_len = attribs.output_len; - *mode = encryption_mode; + // Copy results + memcpy(ct, attribs.output, attribs.output_len); + *ct_len = attribs.output_len; + *mode = encryption_mode; + + ret = Result_OK; + } while(false); CryptoAttribs_t::Free(&attribs); - return Result_OK; + return ret; } TCASE(encode_oracle_test) { - uint8_t plaintext[5*16] = {0}; - uint8_t ciphertext[7*16] = {0}; - uint8_t mode = 0xFF; - uint8_t guessed_mode = 0xFF; - uint32_t ciphertext_len = 7*16; - - // set data in blocks so that - // first block will be filled with 111... - // second block with 2222... - // ... - memset(plaintext, 1, 5*16); - Result_t ret = encryption_oracle(plaintext, 5*16, ciphertext, &ciphertext_len, &mode); - CHECK(ret == Result_OK, (uint8_t*)"Error occured on encryption"); - CHECK(mode != 0xFF); - - guessed_mode = check_ciphertext(ciphertext, ciphertext_len); - CHECK(mode == guessed_mode); + for(size_t i=0; i<100; ++i) + { + printf("Round: %u\n",i); + uint8_t plaintext[5*16] = {0}; + uint8_t ciphertext[7*16] = {0}; + uint8_t mode = 0xFF; + uint8_t guessed_mode = 0xFF; + uint32_t ciphertext_len = 7*16; + + // set data in blocks so that + // first block will be filled with 111... + // second block with 2222... + // ... + memset(plaintext, 1, 5*16); + Result_t ret = encryption_oracle(plaintext, 5*16, ciphertext, &ciphertext_len, &mode); + CHECK(ret == Result_OK, (uint8_t*)"Error occured on encryption"); + CHECK(mode != 0xFF); + + guessed_mode = check_ciphertext(ciphertext, ciphertext_len); + CHECK(mode == guessed_mode); + } } TCASE_E diff --git a/sol/set2.h b/sol/set2.h index e1b3c0f..7e334e5 100644 --- a/sol/set2.h +++ b/sol/set2.h @@ -1,6 +1,9 @@ #ifndef __set2_runner__ #define __set2_runner__ +#include "src/common.h" + + void pkcs7_test(); void cbc_decrypt_test(); void cbc_enc_dec_test(); @@ -9,17 +12,23 @@ void encode_decode_openssl(); void encode_oracle_test(); void encrypt_padding_pkcs7(); +struct OpenSSL +{ + static Result_t Cbc(CryptoAttribs_t* i_attribs, + const Key_t* const i_key); +}; + struct SET2 { static void run() { + encode_oracle_test(); ecb_encrypt_decrypt_single_block(); pkcs7_test(); encode_decode_openssl(); - //cbc_decrypt_test(); - //cbc_enc_dec_test(); - //encode_oracle_test(); - //encrypt_padding_pkcs7(); + cbc_decrypt_test(); + cbc_enc_dec_test(); + encrypt_padding_pkcs7(); } }; diff --git a/src/common.h b/src/common.h index bd4b47b..e1e3119 100644 --- a/src/common.h +++ b/src/common.h @@ -25,7 +25,7 @@ void __CheckFunc__(bool iFlag, const char* const file, int line, const uint8_t* #define OP_CHECK(exp) \ do { \ if(!exp) { \ - printf("Error with expression %s %d\n", #exp, exp); \ + printf("%s:%d Error with expression %s %d\n", __FILE__, __LINE__, #exp, exp); \ goto end; \ } \ } \ diff --git a/src/enc_modes.c b/src/enc_modes.c index 4941a3f..03cc1a4 100644 --- a/src/enc_modes.c +++ b/src/enc_modes.c @@ -16,7 +16,7 @@ static Result_t crypt( CryptoAttribs_t* attribs, assert(attribs != NULL); assert(key->len == 16); size_t max_size = ROUNDUP_16_BYTES(attribs->input_len) ; - + Result_t res = Result_OK; // if output is NULL then allocate same size as input rounded to block size if(attribs->output == NULL) { @@ -36,15 +36,21 @@ static Result_t crypt( CryptoAttribs_t* attribs, if(ret > max_size ) { printf("ERROR %d %lu \n", ret, attribs->output_len); + res = Result_Error; goto end; } OP_CHECK( EVP_CipherFinal_ex(&ctx, &attribs->output[ret], &ret) ); attribs->output_len += ret; - EVP_CIPHER_CTX_cleanup(&ctx); - return Result_OK; + if(attribs->output_len > max_size ) + { + printf("ERROR %d %lu \n", ret, attribs->output_len); + res = Result_Error; + goto end; + } end: - return Result_Error; + EVP_CIPHER_CTX_cleanup(&ctx); + return res; } Result_t cbc_decrypt( @@ -80,7 +86,7 @@ Result_t cbc_decrypt( CryptoAttribs_t ecb_attribs; CryptoAttribs_t::Init(&ecb_attribs); ecb_attribs.output = (uint8_t*) malloc(key->len); - ecb_attribs.output_len = key->len; + ecb_attribs.output_len = 0; for(int i=0; ioutput_len += key->len; + ecb_attribs.output_len = 0; } ::free(ecb_attribs.output); @@ -112,6 +119,7 @@ Result_t cbc_decrypt( pkcs7_unpad(attribs->output, attribs->output_len, &unpadded, &length); memcpy(attribs->output, unpadded, length); attribs->output_len = length; + ::free(unpadded); } return Result_OK; @@ -148,7 +156,8 @@ Result_t cbc_encrypt( } const size_t bc = (size_t)( local_input_len / key->len ); - const size_t bs = key->len; + const size_t bs = attribs->iv_len; + assert(bs == 16); if( attribs->output == NULL) { @@ -184,7 +193,7 @@ Result_t cbc_encrypt( ret = Result_Error; break; } - + assert(ecb_attribs.output != NULL); // Encrypted block is my new IV iv = ecb_attribs.output; @@ -192,7 +201,9 @@ Result_t cbc_encrypt( memcpy((attribs->output)+(bs*i), ecb_attribs.output, ecb_attribs.output_len); + assert(ecb_attribs.output_len == 16); attribs->output_len += ecb_attribs.output_len; + ecb_attribs.output_len = 0; } CryptoAttribs_t::Free(&ecb_attribs); ::free(local_input); @@ -202,11 +213,61 @@ Result_t cbc_encrypt( Result_t ecb_encrypt( CryptoAttribs_t* attribs, const Key_t* const key ) { attribs->operation = kEncrypt; - return crypt(attribs, key); + Result_t res = Result_OK; + + if( kPadding_PKCS7==attribs->padding ) + { + CryptoAttribs_t padded_attribs; + CryptoAttribs_t::Init(&padded_attribs); + do + { + // TODO: it should round up to key length not necsairlly 16 + padded_attribs.input_len = ROUNDUP_16_BYTES(attribs->input_len); + + // one block extra if size aligned + if(padded_attribs.input_len == attribs->input_len) + padded_attribs.input_len += 16; + if( !pkcs7_pad(attribs->input, attribs->input_len, &padded_attribs.input, padded_attribs.input_len) ) + { + res = Result_Error; + break; + } + + padded_attribs.padding = kPadding_None; + res = crypt(&padded_attribs, key); + if(NULL==attribs->output) + { + attribs->output = (uint8_t*)malloc(padded_attribs.output_len); + } + + memcpy(attribs->output, padded_attribs.output, padded_attribs.output_len); + attribs->output_len = padded_attribs.output_len; + } while(false); + CryptoAttribs_t::Free(&padded_attribs); + } + else + { + res = crypt(attribs, key); + } + return res; } Result_t ecb_decrypt( CryptoAttribs_t* attribs, const Key_t* const key ) { + Result_t res = Result_OK; attribs->operation = kDecrypt; - return crypt(attribs, key); + + res = crypt(attribs, key); + if( kPadding_PKCS7==attribs->padding ) + { + size_t output_len=0; + uint8_t* output=NULL; + if(!pkcs7_unpad(attribs->output, attribs->output_len, &output, &output_len)) + { + return Result_Error; + } + memcpy(attribs->output, output, output_len); + attribs->output_len=output_len; + } + return res; } diff --git a/src/main.cpp b/src/main.cpp index 0848b71..0407a8a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,10 +14,9 @@ int main() OpenSSL_add_all_algorithms(); - // UTILS::run(); - SET1::run(); SET2::run(); - + SET1::run(); + UTILS::run(); /* Clean up */ EVP_cleanup(); diff --git a/src/pkcs7.c b/src/pkcs7.c index 41c7787..a86e0ae 100644 --- a/src/pkcs7.c +++ b/src/pkcs7.c @@ -73,7 +73,7 @@ bool pkcs7_unpad( const uint8_t* i_padded_buf, } *unpad_len = i_len - pad_val; - if(*o_unpad_buf == NULL) + if(NULL==*o_unpad_buf) { *o_unpad_buf = (uint8_t*) malloc(*unpad_len); }