#include "src/common.h" #include "src/pkcs7.h" #include "src/enc_modes.h" #include "src/base64.h" #include #include #include #include #include #include #include #include #include #include "set2.h" Result_t OpenSSL::Cbc(CryptoAttribs_t* i_attribs, const Key_t* const i_key) { if(NULL==i_attribs->output) { 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) { static const uint8_t expected_result[17] = "0123456789123456"; CryptoAttribs_t encode, decode; Key_t key1; CryptoAttribs_t::Init(&encode); CryptoAttribs_t::Init(&decode); Key_t::Init(&key1); uint8_t input[16]; uint8_t output[16]; uint8_t key[16]; encode.input = input; encode.input_len= sizeof(input); decode.input = output; decode.input_len= sizeof(output); key1.key = key; key1.len = sizeof(key); memcpy(key1.key, "YELLOW SUBMARINE", 16); memcpy(encode.input, expected_result, 16); CHECK(ecb_encrypt(&encode, &key1) == Result_OK); CHECK(encode.output_len==16); memcpy(decode.input, encode.output, 16); ecb_decrypt(&decode, &key1); CHECK(decode.output_len == 16); CHECK(memcmp(decode.output, expected_result, 16) == 0); free(encode.output); free(decode.output); } TCASE_E TCASE(set2_challange9) { const uint8_t text1[] = "Text1"; uint8_t unpadded[32] = {0}; uint8_t* p_unpadded = &unpadded[0]; int ret; uint8_t buff1[32]; uint8_t* p_buff1 = &buff1[0]; char buff2[10]; ret = pkcs7_pad(text1, 5, &p_buff1, 32); CHECK(ret==true, (const unsigned char* const) "Padding operation failed"); ret = memcmp(text1, buff1, 5); CHECK(ret==0, (const unsigned char* const) "Content differs"); for(int i=5; i<32; i++) { CHECK(buff1[i] == 27, (const unsigned char* const) "Wrong padding"); } size_t unpad_len = 0; 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) ); } TCASE_E TCASE(set2_challange10) { static const uint8_t expected_result[34] = "I'm back and I'm ringin' the bell"; CryptoAttribs_t attribs; Key_t key; Result_t res = Result_Error; Key_t::Init(&key); key.len = 16; key.key = (uint8_t*) malloc(key.len); memcpy(key.key,"YELLOW SUBMARINE",key.len); CryptoAttribs_t::Init(&attribs); attribs.iv = (uint8_t*) malloc(key.len); attribs.iv_len = key.len; memset(attribs.iv, 0, attribs.iv_len); res = load_base64_to_hex( "sol/etc/set2_t2.txt", &(attribs.input), &(attribs.input_len)); CHECK(res == Result_OK, (const uint8_t*) "Problem when loading input file"); cbc_decrypt(&attribs, &key); CHECK( memcmp(expected_result, attribs.output, 33) == 0, (const uint8_t*) "Wrong plaintext decrypted"); // cleanup CryptoAttribs_t::Free(&attribs); Key_t::Free(&key); } TCASE_E TCASE(cbc_enc_dec_test) { static const uint8_t test_text[49] = "The quick brown fox jumps over the lazy mad dog."; CryptoAttribs_t enc_attribs; CryptoAttribs_t dec_attribs; Key_t key; CryptoAttribs_t::Init(&enc_attribs); CryptoAttribs_t::Init(&dec_attribs); Key_t::Init(&key); // Setup key key.len = 16; key.key = (uint8_t*) malloc(key.len); memcpy(key.key, "0123456789123456", key.len); // Encrypt enc_attribs.input_len = sizeof(test_text)-1; enc_attribs.input = (uint8_t*) malloc(enc_attribs.input_len); enc_attribs.operation = kEncrypt; memcpy( enc_attribs.input, test_text, enc_attribs.input_len); enc_attribs.iv_len = key.len; enc_attribs.iv = (uint8_t*)malloc(enc_attribs.iv_len); memset(enc_attribs.iv, 0, enc_attribs.iv_len); cbc_encrypt(&enc_attribs, &key); // Setup decryption object. dec_attribs.iv = (uint8_t*)malloc( enc_attribs.iv_len ); dec_attribs.iv_len = enc_attribs.iv_len; dec_attribs.operation = kDecrypt; memset(dec_attribs.iv, 0, dec_attribs.iv_len); dec_attribs.input = (uint8_t*)malloc(enc_attribs.output_len); dec_attribs.input_len = enc_attribs.output_len; memcpy(dec_attribs.input, enc_attribs.output, enc_attribs.output_len); // Decrypt cbc_decrypt(&dec_attribs, &key); CHECK( dec_attribs.output_len+1 == sizeof(test_text), (uint8_t*) "wrong size of ouptut"); CHECK(memcmp(dec_attribs.output, test_text, dec_attribs.output_len) == 0, dec_attribs.output); end: CryptoAttribs_t::Free(&enc_attribs); CryptoAttribs_t::Free(&dec_attribs); Key_t::Free(&key); } TCASE_E TCASE(encode_decode_openssl) { uint8_t concatenated_blocks[16*3]; uint8_t iv1[16] = {0}; uint8_t key[17] = "YELLOW SUBMARINE"; // 16+'\0' = 17 memset(concatenated_blocks, 2, 16); memset(&concatenated_blocks[16], 5, 16); memset(&concatenated_blocks[32], 9, 16); RAND_bytes(iv1, 16); Key_t keyObj; keyObj.key = &key[0]; keyObj.len = 16; // 1. decryption test { CryptoAttribs_t attribs_openssl_enc; CryptoAttribs_t::Init(&attribs_openssl_enc); attribs_openssl_enc.input = concatenated_blocks; attribs_openssl_enc.input_len = sizeof(concatenated_blocks); attribs_openssl_enc.output = (uint8_t*)malloc(attribs_openssl_enc.input_len); attribs_openssl_enc.output_len; attribs_openssl_enc.iv = &iv1[0]; 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");// CryptoAttribs_t cbc_attribs; CryptoAttribs_t::Init(&cbc_attribs); cbc_attribs.input = attribs_openssl_enc.output; cbc_attribs.input_len = attribs_openssl_enc.output_len; cbc_attribs.iv = &iv1[0]; cbc_attribs.iv_len = sizeof(iv1); CHECK( Result_OK == cbc_decrypt(&cbc_attribs, &keyObj) ); CHECK( memcmp( concatenated_blocks, cbc_attribs.output, cbc_attribs.output_len) == 0, (uint8_t*)"Input/Output differs"); ::free(attribs_openssl_enc.output); ::free(cbc_attribs.output); } // 2. encryption test { CryptoAttribs_t attribs_enc; CryptoAttribs_t::Init(&attribs_enc); attribs_enc.input = concatenated_blocks; attribs_enc.input_len = sizeof(concatenated_blocks); attribs_enc.iv = &iv1[0]; 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); attribs_openssl_dec.input = attribs_enc.output; attribs_openssl_dec.input_len = attribs_enc.output_len; attribs_openssl_dec.iv = &iv1[0]; attribs_openssl_dec.iv_len = sizeof(iv1); attribs_openssl_dec.operation = kDecrypt; CHECK(OpenSSL::Cbc(&attribs_openssl_dec, &keyObj)==Result_OK); CHECK(attribs_openssl_dec.output_len==48, (uint8_t*)"Ciphertext has wrong size"); CHECK( memcmp( concatenated_blocks, attribs_openssl_dec.output, attribs_openssl_dec.output_len) == 0, (uint8_t*)"Input/Output differs"); ::free(attribs_enc.output); ::free(attribs_openssl_dec.output); } } TCASE_E /* ------------------------------------------------------------------------- Checks if ciphertext is encrypted with ECB or CBC. Requirement: In order to work, plaintext must encrypt up to 6 blocks (with padding) and all the letters in the PT must be exactly the same. Returns: * 0 : if ciphertext encrypted with ECB * 1 : if ciphertext encrypted with CBC * 0xFF: in case wrong input parameters provided -------------------------------------------------------------------------*/ uint8_t check_ciphertext(const uint8_t* ciphertext, uint32_t len ) { uint32_t bs = 16; if( (len < 6*bs) || (len>7*bs) ) return 0xFF; // check blocks 2,3,4 as first have prepaned bytes, 5th also, 6th can have padding // eventually 7th may be fully padded. for(uint32_t i=1; i<4; ++i) { if( memcmp(ciphertext+(bs*i), ciphertext+(bs*(i+1)), bs) != 0) return 1; // Two blocks differ -> must be CBC } 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) { uint8_t iv1[16] = {0}; uint8_t key[16] = {0}; uint8_t prepend_byte_size; uint8_t append_byte_size; uint8_t random_bytes[10]; uint8_t encryption_mode = 0xFF; struct timespec tv; CryptoAttribs_t attribs; Key_t keyObj; // get seed for good randomnes clock_gettime(CLOCK_MONOTONIC, &tv); srand((unsigned int)tv.tv_nsec); // choose random sizes and enc mode (0 ECB, 1 CBC) prepend_byte_size = 5+(rand() % 6); append_byte_size = 5+(rand() % 6); encryption_mode = rand() % 2; // generate rando data RAND_bytes(iv1, 16); RAND_bytes(key, 16); // initialize encryption attribs CryptoAttribs_t::Init(&attribs); attribs.operation = kEncrypt; 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; // copy input to the input buffer RAND_bytes(random_bytes, prepend_byte_size); int tmplen=0; memcpy(attribs.input+tmplen, random_bytes, prepend_byte_size); tmplen+=prepend_byte_size; memcpy(attribs.input+tmplen, pt, pt_len); tmplen+=pt_len; 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; Result_t ret = Result_OK; do { 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; ret = Result_OK; } while(false); CryptoAttribs_t::Free(&attribs); return ret; } TCASE(set2_challange11) { // let's run it 1000 times for(size_t i=0; i<1000; ++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 5 blocks is 11111... 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 TCASE(encrypt_padding_pkcs7) { uint8_t text[3] = {'D', 'E', 'F'}; uint8_t expected_no_padding_dec[16] = {0}; uint8_t iv[16] = {0}; uint8_t key[16] = {0}; // "ABC" must be padded with 13,13,13.... memcpy(expected_no_padding_dec, text, 3); memset(expected_no_padding_dec+3, 13, 13); // key Key_t keyObj = {0}; Key_t::Init(&keyObj); keyObj.key = key; keyObj.len = 16; CryptoAttribs_t attribs_enc; CryptoAttribs_t::Init(&attribs_enc); attribs_enc.input = &text[0]; attribs_enc.input_len = 3; attribs_enc.iv = &iv[0]; attribs_enc.iv_len = sizeof(iv); attribs_enc.operation = kEncrypt; attribs_enc.padding = kPadding_PKCS7; CHECK( Result_OK == cbc_encrypt(&attribs_enc, &keyObj) ); CHECK( attribs_enc.output_len == 16, (uint8_t*) "Wrong out size"); // Decrypt with openssl and no padding. Check padding value { CryptoAttribs_t attribs_openssl_dec; CryptoAttribs_t::Init(&attribs_openssl_dec); attribs_openssl_dec.input = attribs_enc.output; attribs_openssl_dec.input_len = attribs_enc.output_len; attribs_openssl_dec.iv = &iv[0]; attribs_openssl_dec.iv_len = sizeof(iv); attribs_openssl_dec.operation = kDecrypt; attribs_openssl_dec.padding = kPadding_None; CHECK(OpenSSL::Cbc(&attribs_openssl_dec, &keyObj)==Result_OK); CHECK(attribs_openssl_dec.output_len==16, (uint8_t*)"Ciphertext has wrong size"); CHECK( 0==memcmp( attribs_openssl_dec.output, expected_no_padding_dec, 16), (uint8_t*)"Wrong padding decrypted" ); ::free(attribs_openssl_dec.output); } // Decrypt padding { CryptoAttribs_t attribs_dec; CryptoAttribs_t::Init(&attribs_dec); attribs_dec.input = attribs_enc.output; attribs_dec.input_len = attribs_enc.output_len; attribs_dec.iv = &iv[0]; attribs_dec.iv_len = sizeof(iv); attribs_dec.operation = kDecrypt; attribs_dec.padding = kPadding_PKCS7; CHECK( Result_OK == cbc_decrypt(&attribs_dec, &keyObj) ); CHECK(attribs_dec.output_len==3, (uint8_t*)"Ciphertext has wrong size"); CHECK( 0==memcmp( attribs_dec.output, expected_no_padding_dec, 3), (uint8_t*)"Wrong padding decrypted" ); ::free(attribs_dec.output); } ::free(attribs_enc.output); } TCASE_E TCASE(set2_challange12_not_finished) { uint8_t CIPHERTEXT[] = "Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkg" "aGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBq" "dXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUg" "YnkK"; uint8_t HEX_STRING[sizeof CIPHERTEXT]; uint8_t CONCAT_STRING[sizeof(CIPHERTEXT)*2]; CryptoAttribs_t EncryptForBS; Key_t key; uint32_t hex_len = 0; hex_len = base64_to_hex(CIPHERTEXT, sizeof(CIPHERTEXT), HEX_STRING); } TCASE_E