3

I'm in the process of coding some stuff around common-encryption which require AES Ctr 128. So I'm digging a bit with crypto stuff.

Currently I test a code (find here) which work (encrypt/decrypt a file):

#include <openssl/aes.h> #include <openssl/rand.h> #include <openssl/hmac.h> #include <openssl/buffer.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> struct ctr_state { unsigned char ivec[AES_BLOCK_SIZE]; unsigned int num; unsigned char ecount[AES_BLOCK_SIZE]; }; void print_hex(unsigned char *c) { for(int i = 0; i < 16; i++) { printf("%02X.", c[i]); } printf("\n"); } void init_ctr(struct ctr_state *state, const unsigned char iv[16]) { state->num = 0; memset(state->ecount, 0, 16); memset(state->ivec + 8, 0, 8); memcpy(state->ivec, iv, 8); } void fencrypt(char* read, char* write, const unsigned char* enc_key) { FILE *readFile; FILE *writeFile; AES_KEY key; int bytes_read; unsigned char indata[AES_BLOCK_SIZE]; unsigned char outdata[AES_BLOCK_SIZE]; unsigned char iv[AES_BLOCK_SIZE]; struct ctr_state state; RAND_bytes(iv, AES_BLOCK_SIZE); print_hex(iv); readFile = fopen(read,"rb"); writeFile = fopen(write,"wb"); AES_set_encrypt_key(enc_key, 128, &key); init_ctr(&state, iv); fwrite(state.ivec, 1, AES_BLOCK_SIZE, writeFile); print_hex(state.ivec); while(1) { bytes_read = fread(indata, 1, AES_BLOCK_SIZE, readFile); AES_ctr128_encrypt(indata, outdata, bytes_read, &key, state.ivec, state.ecount, &state.num); print_hex(state.ivec); fwrite(outdata, 1, bytes_read, writeFile); if (bytes_read < AES_BLOCK_SIZE) { break; } } fclose(writeFile); fclose(readFile); } void fdecrypt(char* read, char* write, const unsigned char* enc_key) { FILE *readFile; FILE *writeFile; AES_KEY key; int bytes_read; unsigned char indata[AES_BLOCK_SIZE]; unsigned char outdata[AES_BLOCK_SIZE]; unsigned char iv[AES_BLOCK_SIZE]; struct ctr_state state; readFile=fopen(read,"rb"); writeFile=fopen(write,"wb"); fread(iv, 1, AES_BLOCK_SIZE, readFile); AES_set_encrypt_key(enc_key, 128, &key); init_ctr(&state, iv); while(1) { bytes_read = fread(indata, 1, AES_BLOCK_SIZE, readFile); AES_ctr128_encrypt(indata, outdata, bytes_read, &key, state.ivec, state.ecount, &state.num); print_hex(state.ivec); fwrite(outdata, 1, bytes_read, writeFile); if (bytes_read < AES_BLOCK_SIZE) { break; } } fclose(writeFile); fclose(readFile); } int main(int argc, char *argv[]) { char* secret = "supersecret"; fencrypt("encme.txt", "enced.enc", (const unsigned char*)secret); fdecrypt("enced.enc", "unenced.txt", (const unsigned char*)secret); } 

This work well. But It seems that the standard is to to use EVP functions now with openssl. So I try to adapt my code but something is clearly wrong with my implementations. I don't understand on how properly update/increment the IV vector.

Here my new code with EVP (work but not increment/counter):

#include <openssl/aes.h> #include <openssl/rand.h> #include <openssl/evp.h> #include <stdio.h> #include <string.h> #include <stdlib.h> struct ctr_state { EVP_CIPHER_CTX* cipher; int num; }; void print_hex(unsigned char *c) { for(int i = 0; i < 16; i++) { printf("%02X.", c[i]); } printf("\n"); } void init_ctr(struct ctr_state *state, unsigned char iv[16], unsigned char* key) { state->num = 0; state->cipher = EVP_CIPHER_CTX_new(); EVP_EncryptInit_ex(state->cipher, EVP_aes_128_ctr(), NULL, key, iv); } void fencrypt(char* read, char* write, unsigned char* enc_key) { FILE *readFile; FILE *writeFile; int bytes_read; unsigned char indata[AES_BLOCK_SIZE]; unsigned char outdata[AES_BLOCK_SIZE]; unsigned char iv[AES_BLOCK_SIZE]; struct ctr_state state; RAND_bytes(iv, AES_BLOCK_SIZE); readFile = fopen(read,"rb"); writeFile = fopen(write,"wb"); fwrite(iv, 1, AES_BLOCK_SIZE, writeFile); init_ctr(&state, iv, enc_key); print_hex(iv); while(1) { bytes_read = fread(indata, 1, AES_BLOCK_SIZE, readFile); EVP_EncryptUpdate(state.cipher, outdata, &state.num, indata, bytes_read); EVP_EncryptUpdate(state.cipher, outdata, &state.num, indata, bytes_read); fwrite(outdata, 1, bytes_read, writeFile); if (bytes_read < AES_BLOCK_SIZE) { break; } } fclose(writeFile); fclose(readFile); } void fdecrypt(char* read, char* write, unsigned char* enc_key) { FILE *readFile; FILE *writeFile; int bytes_read; unsigned char indata[AES_BLOCK_SIZE]; unsigned char outdata[AES_BLOCK_SIZE]; unsigned char iv[AES_BLOCK_SIZE]; struct ctr_state state; readFile = fopen(read,"rb"); writeFile = fopen(write,"wb"); fread(iv, 1, AES_BLOCK_SIZE, readFile); init_ctr(&state, iv, enc_key); print_hex(iv); while(1) { bytes_read = fread(indata, 1, AES_BLOCK_SIZE, readFile); EVP_EncryptUpdate(state.cipher, outdata, &state.num, indata, bytes_read); printf("Pass %d ",state.num); fwrite(outdata, 1, bytes_read, writeFile); if (bytes_read < AES_BLOCK_SIZE) { break; } } fclose(writeFile); fclose(readFile); } int main(int argc, char *argv[]) { char* secret = "supersecret"; fencrypt("encme.txt", "enced.enc", (unsigned char*)secret); fdecrypt("enced.enc", "unenced.txt", (unsigned char*)secret); } 

Any help appreciated. Thank you.

2

3 Answers 3

2

OK I think I got it.

I will copy here my two program example:

AES_CTR_128 (without EVP) :

#include <openssl/aes.h> #include <stdio.h> #include <stdlib.h> #include <string.h> struct ctr_state { unsigned int num; unsigned char ivec[AES_BLOCK_SIZE]; unsigned char ecount[AES_BLOCK_SIZE]; }; void init_ctr(struct ctr_state *state, const unsigned char iv[16]) { state->num = 0; memset(state->ecount, 0, 16); memset(state->ivec + 8, 0, 8); memcpy(state->ivec, iv, 8); } void fencrypt(char* read, char* write, const unsigned char* enc_key) { FILE *readFile; FILE *writeFile; AES_KEY key; int bytes_read; unsigned char indata[AES_BLOCK_SIZE]; unsigned char outdata[AES_BLOCK_SIZE]; struct ctr_state state; unsigned char *iv = (unsigned char *)"0123456789012345"; readFile = fopen(read,"rb"); writeFile = fopen(write,"wb"); fwrite(iv, 1, AES_BLOCK_SIZE, writeFile); AES_set_encrypt_key(enc_key, 128, &key); init_ctr(&state, iv); while(1) { bytes_read = fread(indata, 1, AES_BLOCK_SIZE, readFile); AES_ctr128_encrypt(indata, outdata, bytes_read, &key, state.ivec, state.ecount, &state.num); fwrite(outdata, 1, bytes_read, writeFile); if (bytes_read < AES_BLOCK_SIZE) { break; } } fclose(writeFile); fclose(readFile); } void fdecrypt(char* read, char* write, const unsigned char* enc_key) { FILE *readFile; FILE *writeFile; AES_KEY key; int bytes_read; unsigned char indata[AES_BLOCK_SIZE]; unsigned char outdata[AES_BLOCK_SIZE]; unsigned char iv[AES_BLOCK_SIZE]; struct ctr_state state; readFile=fopen(read,"rb"); writeFile=fopen(write,"wb"); fread(iv, 1, AES_BLOCK_SIZE, readFile); AES_set_encrypt_key(enc_key, 128, &key); init_ctr(&state, iv); while(1) { bytes_read = fread(indata, 1, AES_BLOCK_SIZE, readFile); AES_ctr128_encrypt(indata, outdata, bytes_read, &key, state.ivec, state.ecount, &state.num); fwrite(outdata, 1, bytes_read, writeFile); if (bytes_read < AES_BLOCK_SIZE) { break; } } fclose(writeFile); fclose(readFile); } int main(int argc, char *argv[]) { unsigned char *secret = (unsigned char *)"0123456789012345"; fencrypt("encme.txt", "enced.enc", secret); fdecrypt("enced.enc", "unenced.txt", secret); } 

Everything classic as in another example. The IV(or nonce) is constant to make the debugging easier (don't do that).

And below my code with EVP:

#include <openssl/aes.h> #include <openssl/evp.h> #include <stdio.h> #include <string.h> #include <stdlib.h> struct ctr_state { EVP_CIPHER_CTX* cipher; unsigned int num; unsigned char ivec[AES_BLOCK_SIZE]; unsigned char ecount[AES_BLOCK_SIZE]; }; static void AES_ctr128_inc(unsigned char *counter) { unsigned char* cur_pos; for (cur_pos = counter + 15; cur_pos >= counter; cur_pos--) { (*cur_pos)++; if (*cur_pos != 0) { break; } } } void AES_ctr128_EVPencrypt(EVP_CIPHER_CTX* cipher, const unsigned char *in, unsigned char *out, const unsigned long length, unsigned char counter[AES_BLOCK_SIZE], unsigned char ecount_buf[AES_BLOCK_SIZE], unsigned int *num) { int nb; unsigned int n; unsigned long l=length; n = *num; while (l--) { if (n == 0) { EVP_EncryptUpdate(cipher, ecount_buf, &nb, counter, AES_BLOCK_SIZE); AES_ctr128_inc(counter); } *(out++) = *(in++) ^ ecount_buf[n]; n = (n+1) % AES_BLOCK_SIZE; } *num=n; } void init_ctr(struct ctr_state *state, unsigned char iv[16], unsigned char* key) { state->num = 0; memset(state->ecount, 0, 16); memset(state->ivec + 8, 0, 8); memcpy(state->ivec, iv, 8); state->cipher = EVP_CIPHER_CTX_new(); EVP_EncryptInit_ex(state->cipher, EVP_aes_128_ecb(), NULL, key, NULL); } void fencrypt(char* read, char* write, unsigned char* enc_key) { FILE *readFile; FILE *writeFile; int bytes_read; unsigned char indata[AES_BLOCK_SIZE]; unsigned char outdata[AES_BLOCK_SIZE]; struct ctr_state state; unsigned char *iv = (unsigned char *)"0123456789012345"; readFile = fopen(read,"rb"); writeFile = fopen(write,"wb"); fwrite(iv, 1, AES_BLOCK_SIZE, writeFile); init_ctr(&state, iv, enc_key); while(1) { bytes_read = fread(indata, 1, AES_BLOCK_SIZE, readFile); AES_ctr128_EVPencrypt(state.cipher, indata, outdata, bytes_read, state.ivec, state.ecount, &state.num); fwrite(outdata, 1, bytes_read, writeFile); if (bytes_read < AES_BLOCK_SIZE) { break; } } fclose(writeFile); fclose(readFile); } void fdecrypt(char* read, char* write, unsigned char* enc_key) { FILE *readFile; FILE *writeFile; int bytes_read; unsigned char indata[AES_BLOCK_SIZE]; unsigned char outdata[AES_BLOCK_SIZE]; unsigned char iv[AES_BLOCK_SIZE]; struct ctr_state state; readFile = fopen(read,"rb"); writeFile = fopen(write,"wb"); fread(iv, 1, AES_BLOCK_SIZE, readFile); init_ctr(&state, iv, enc_key); while(1) { bytes_read = fread(indata, 1, AES_BLOCK_SIZE, readFile); AES_ctr128_EVPencrypt(state.cipher, indata, outdata, bytes_read, state.ivec, state.ecount, &state.num); fwrite(outdata, 1, bytes_read, writeFile); if (bytes_read < AES_BLOCK_SIZE) { break; } } fclose(writeFile); fclose(readFile); } int main(int argc, char *argv[]) { unsigned char *secret = (unsigned char *)"0123456789012345"; fencrypt("encme.txt", "enced.enc", (unsigned char*)secret); fdecrypt("enced.enc", "unenced.txt", secret); } 

So I basically copy the AES_ctr_encrypt function to use EVP, and adapt it.

It work for me, as I can use both implementation to encrypt/decrypt the same program.

Comments are welcome. Questions remain that what do the aes_ctr_128 in EVP ? and how to use it? I think I have reinvented the wheel.

Sign up to request clarification or add additional context in comments.

1 Comment

Nicely done -- I tested both code snippets to work -- however I've noticed an important omission: at the end of BOTH fencrypt() and fdecrypt() you also need to call "EVP_CIPHER_CTX_free(state.cipher);" so that the structures allocated by "EVP_CIPHER_CTX_new();" are properly freed after all encryption/decryption is done... -- also one thing I found out the hard way is that every single time EVP_EncryptUpdate() is to be called one must explicitly call EVP_EncryptInit_ex() with the proper context pointer and ALL NULL parameters except for the key -- otherwise EVP_EncryptUpdate() crashes...
1

In {EVP_aes_N_ctr()} the counter state is kept in {ctx->iv}, treated as an 128 big-endian integer, counting the crypto blocks, starting from the IV given to the Init function. This counter tells the number of the next crypto block to be encrypted/decrypted. This works with random access, i.e. ctx->iv can be computed manually before an *Update call, if on crypto block boundary. As soon as at least one byte is returned from a cipher op, the counter is updated to hold the next crypto block to be processed. If byte-level random access is wanted, there is also {ctx->num} that holds the byte offset into the current crypto block. For this to work, the block must have been started on, i.e. a cipher op where {ctx->num} was equal to zero must have been issued, in order to correctly setup the internal state.

Below is a stupid, but still working example of how CTR mode can be used for random access decryption.

#include <openssl/evp.h> #include <stddef.h> #include <stdio.h> #include <string.h> static void add_be_128(uint8_t *ctr, ptrdiff_t delta) { for (int n = 15; delta != 0 && n >= 0; n--) { // The risk of overflow can safely be neglected. ptrdiff_t nval = ctr[n] + delta; ctr[n] = nval & 0xff; delta = nval >> 8; } } int main() { uint8_t in[] = "0123456789abcdeffedcba9876543210fedcba98765432100123456789abcdef"; uint8_t out[64]; int sz; uint8_t cmp[33]; uint8_t key[] = { 0xde, 0xad, 0xbe, 0xef, 0xc0, 0x01, 0xd0, 0x0d, 0xde, 0xad, 0xbe, 0xef, 0xc0, 0x01, 0xd0, 0x0d }; uint8_t iv[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); EVP_EncryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, key, iv); EVP_CIPHER_CTX_set_padding(ctx, 0); EVP_EncryptUpdate(ctx, out, &sz, in, sizeof in); EVP_EncryptFinal_ex(ctx, out + sz, &sz); EVP_DecryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, key, iv); EVP_CIPHER_CTX_set_padding(ctx, 0); add_be_128(ctx->iv, 1); EVP_DecryptUpdate(ctx, cmp, &sz, out + 16, 32); EVP_DecryptFinal_ex(ctx, cmp + sz, &sz); cmp[32] = 0; printf("%s %d\n", cmp, strncmp(in + 16, cmp, 32)); EVP_DecryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, key, iv); EVP_CIPHER_CTX_set_padding(ctx, 0); int new = ctx->num + 8; add_be_128(ctx->iv, (new - 1) / 16); ctx->num = 0; EVP_DecryptUpdate(ctx, cmp, &sz, out, 1); ctx->num = new; EVP_DecryptUpdate(ctx, cmp, &sz, out + 8, 32); EVP_DecryptFinal_ex(ctx, cmp + sz, &sz); cmp[32] = 0; printf("%s %d\n", cmp, strncmp(in + 8, cmp, 32)); } 

Comments

0

Here is my solution when I had to use the EVP openssl functions. Should work with every available cipher

/*! @file s70357.c * IS_Beleg by Markus Klemm * */ #include <stdlib.h> #include <string.h> #include <stdio.h> #include <stdbool.h> #include <stdint.h> #include <openssl/evp.h> #include <errno.h> #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> /*! * @param cipher_text Buffer, at least (plain_len + cipher_block_size - 1) bytes big, * where the encrypted data will be stored. * @param cipher_text_len Actual length of encrypted data in cipher_text in bytes */ bool mk_evp_encrypt(const unsigned char *plain_text, const int plain_text_len, unsigned char *cipher_text, int *cipher_text_len, const EVP_CIPHER *cipher, unsigned char *key, unsigned char *iv) { EVP_CIPHER_CTX *context = EVP_CIPHER_CTX_new(); if (!context) { return false; } if (!EVP_EncryptInit_ex(context, cipher, NULL, key, iv)) { EVP_CIPHER_CTX_free(context); return false; } *cipher_text_len = 0; if (!EVP_EncryptUpdate(context, cipher_text, cipher_text_len, plain_text, plain_text_len)) { EVP_CIPHER_CTX_free(context); return false; } int final_block_len = 0; if (!EVP_EncryptFinal_ex(context, cipher_text + *cipher_text_len, &final_block_len)) { EVP_CIPHER_CTX_free(context); return false; } *cipher_text_len += final_block_len; EVP_CIPHER_CTX_free(context); return true; } /*! @param plain_text Buffer that must at least be cipher_text_len + cipher_block_size big * */ bool mk_evp_decrypt(const unsigned char *cipher_text, const int cipher_text_len, unsigned char *plain_text, int *plain_text_len, const EVP_CIPHER *cipher, unsigned char *key, unsigned char *iv) { EVP_CIPHER_CTX *context = EVP_CIPHER_CTX_new(); if (!context) { return false; } if (!EVP_DecryptInit_ex(context, cipher, NULL, key, iv)) { EVP_CIPHER_CTX_free(context); return false; } *plain_text_len = 0; if (!EVP_DecryptUpdate(context, plain_text, plain_text_len, cipher_text, cipher_text_len)) { EVP_CIPHER_CTX_free(context); return false; } int final_block_size = 0; if (!EVP_DecryptFinal_ex(context, plain_text + *plain_text_len, &final_block_size)) { EVP_CIPHER_CTX_free(context); return false; } *plain_text_len += final_block_size; EVP_CIPHER_CTX_free(context); return true; } struct file_memory_map_meta { int file_desc; struct stat file_info; }; /*! @param digest Must be big engough to hold at least EVP_MAX_MD_SIZE * */ bool mk_evp_digest(const unsigned char *text, const size_t text_len, unsigned char *digest, unsigned int *digest_len, const EVP_MD *digest_type) { EVP_MD_CTX *context = EVP_MD_CTX_create(); if (!context) { return false; } if (!EVP_DigestInit_ex(context, digest_type, NULL)) { return false; } if (!EVP_DigestUpdate(context, text, text_len)) { return false; } if (!EVP_DigestFinal_ex(context, digest, digest_len)) { return false; } EVP_MD_CTX_destroy(context); return true; } void open_file_memory_mapped_read(char *file_path, void **file_memory, struct file_memory_map_meta *meta) { meta->file_desc = open(file_path, O_RDONLY); if (meta->file_desc == -1) { fprintf(stderr, "Can't open read file %s", file_path); perror(" "); exit(EXIT_FAILURE); } if (stat(file_path, &meta->file_info) != 0) { perror("Can't get source file infos"); exit(EXIT_FAILURE); } void *source_mem = mmap(NULL, meta->file_info.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, meta->file_desc, 0); if (source_mem == MAP_FAILED) { perror("Mapping read file failed"); exit(EXIT_FAILURE); } *file_memory = source_mem; } void open_file_memory_mapped_write(char *file_path, void **file_memory, struct file_memory_map_meta *meta, size_t size) { meta->file_desc = open(file_path, O_TRUNC | O_CREAT | O_RDWR, 744); if (meta->file_desc == -1) { fprintf(stderr, "Can't open write file %s", file_path); perror(" "); exit(EXIT_FAILURE); } if (stat(file_path, &meta->file_info) != 0) { perror("Can't get source file infos"); exit(EXIT_FAILURE); } void *source_mem = mmap(NULL, size, PROT_WRITE, MAP_FILE | MAP_SHARED, meta->file_desc, 0); if (source_mem == MAP_FAILED) { perror("Mapping write file failed"); exit(EXIT_FAILURE); } *file_memory = source_mem; } void close_file_memory_mapped(void **file_memory, struct file_memory_map_meta *meta) { munmap(*file_memory, meta->file_info.st_size); close(meta->file_desc); } void create_key_iv_from_file(char *key_iv_path, unsigned char **key, unsigned char **iv, const EVP_CIPHER *cipher) { FILE *f = fopen(key_iv_path, "rb"); if (!f) { fprintf(stderr, "Could not open file %s", key_iv_path); perror(" "); exit(EXIT_FAILURE); } *key = malloc(EVP_CIPHER_key_length(cipher)); if (*key == NULL) { perror("Could not alloc for key"); exit(EXIT_FAILURE); } if (EVP_CIPHER_iv_length(cipher) != 0) { *iv = malloc(EVP_CIPHER_iv_length(cipher)); if (*iv == NULL) { perror("Could not alloc for iv"); exit(EXIT_FAILURE); } } else { *iv = NULL; } if (fread(*key, 1, EVP_CIPHER_key_length(cipher), f) != EVP_CIPHER_key_length(cipher)) { fprintf(stderr, "Error while reading key\n"); exit(EXIT_FAILURE); } if (*iv != NULL) { if (fread(*iv, 1, EVP_CIPHER_iv_length(cipher), f) != EVP_CIPHER_iv_length(cipher)) { fprintf(stderr, "Error while reading iv\n"); exit(EXIT_FAILURE); } } fclose(f); } unsigned char *permutate_key(unsigned char *key, unsigned corrupt_byte_pos) { key[corrupt_byte_pos] = key[corrupt_byte_pos] + 1; //although in DES, we could reduce to half because of parity bit return key; } bool is_pdf(unsigned char *data) { unsigned char pdf_start[] = {"%PDF"}; unsigned char pdf_end[] = {"%%EOF"}; return !memcmp(pdf_start, data, sizeof(pdf_start) - 1); //TODO check pdf_end, but cutaway the padding } void decrypt_mode(char *cipher_text_path, char *plain_text_path, char *key_iv, unsigned corrupt_byte_pos, char *cipher) { OpenSSL_add_all_algorithms();//Needed for older versions to use EVP_get_cipherbyname const EVP_CIPHER *evp_cipher = EVP_get_cipherbyname(cipher); EVP_cleanup(); //cleanup for OpenSSL_add_all_algorithms if (evp_cipher == NULL) { fprintf(stderr, "Cipher %s not found\n", cipher); exit(EXIT_FAILURE); } void *cipher_text_mem; struct file_memory_map_meta cipher_text_meta; open_file_memory_mapped_read(cipher_text_path, &cipher_text_mem, &cipher_text_meta); void *plain_text_mem; struct file_memory_map_meta plain_text_meta; open_file_memory_mapped_write(plain_text_path, &plain_text_mem, &plain_text_meta, cipher_text_meta.file_info.st_size); if (chmod(plain_text_path, cipher_text_meta.file_info.st_mode) != 0) { perror("Can't copy file permissions"); } if (lseek(plain_text_meta.file_desc, cipher_text_meta.file_info.st_size - 1 + EVP_CIPHER_block_size(evp_cipher), SEEK_SET) == -1) { perror("Can't seek to new end of destination file"); } unsigned char dummy = 0; if (write(plain_text_meta.file_desc, &dummy, 1) == -1) { perror("Couldn't write dummy byte"); } unsigned char *key; unsigned char *iv; create_key_iv_from_file(key_iv, &key, &iv, evp_cipher); //now lets try the keys const unsigned key_len = EVP_CIPHER_key_length(evp_cipher); int plain_len = 0; bool decrypt_return = mk_evp_decrypt(cipher_text_mem, cipher_text_meta.file_info.st_size, plain_text_mem, &plain_len, evp_cipher, key, iv); while (!decrypt_return || !is_pdf(plain_text_mem)) { fprintf(stderr, "Key 0x"); for (unsigned i = 0; i < key_len; ++i) { fprintf(stderr, "%02X", key[i]); } fprintf(stderr, " didn't catch it trying the next one\n"); plain_len = 0; decrypt_return = mk_evp_decrypt(cipher_text_mem, cipher_text_meta.file_info.st_size, plain_text_mem, &plain_len, evp_cipher, permutate_key(key, corrupt_byte_pos), iv); } if (ftruncate(plain_text_meta.file_desc, plain_len) != 0) { perror("Trimming of final plain text failed"); exit(EXIT_FAILURE); } free(key); free(iv); close_file_memory_mapped(&plain_text_mem, &plain_text_meta); close_file_memory_mapped(&cipher_text_mem, &cipher_text_meta); } void hash_mode(char *text_path, char *opt_hash_path, char *digest_name) { OpenSSL_add_all_digests();//Needed for older versions to use EVP_get_cipherbyname const EVP_MD *digest = EVP_get_digestbyname(digest_name); EVP_cleanup(); //cleanup for OpenSSL_add_all_algorithms if (digest == NULL) { fprintf(stderr, "Digest %s not found\n", digest_name); exit(EXIT_FAILURE); } void *text_mem; struct file_memory_map_meta text_meta; open_file_memory_mapped_read(text_path, &text_mem, &text_meta); unsigned char hash[EVP_MAX_MD_SIZE]; unsigned hash_len = 0; mk_evp_digest(text_mem, text_meta.file_info.st_size, hash, &hash_len, digest); if (strlen(opt_hash_path) == 0) { for (unsigned i = 0; i < hash_len; ++i) { printf("%02X", hash[i]); } printf("\n"); } else { FILE *out_file = fopen(opt_hash_path, "wb"); if (!out_file) { perror("Could not open output file"); exit(EXIT_FAILURE); } if (fwrite(hash, hash_len, 1, out_file) != 1) { fprintf(stderr, "Could not write the hash correctly\n"); exit(EXIT_FAILURE); } fclose(out_file); } close_file_memory_mapped(&text_mem, &text_meta); } void encrypt_mode(char *plain_text_path, char *cipher_text_path, char *key_iv, char *cipher) { OpenSSL_add_all_algorithms();//Needed for older versions to use EVP_get_cipherbyname const EVP_CIPHER *evp_cipher = EVP_get_cipherbyname(cipher); EVP_cleanup(); //cleanup for OpenSSL_add_all_algorithms if (evp_cipher == NULL) { fprintf(stderr, "Cipher %s not found\n", cipher); exit(EXIT_FAILURE); } void *plain_text_mem; struct file_memory_map_meta plain_text_meta; open_file_memory_mapped_read(plain_text_path, &plain_text_mem, &plain_text_meta); void *cipher_text_mem; struct file_memory_map_meta cipher_text_meta; open_file_memory_mapped_write(cipher_text_path, &cipher_text_mem, &cipher_text_meta, plain_text_meta.file_info.st_size); if (chmod(cipher_text_path, plain_text_meta.file_info.st_mode) != 0) { perror("Can't copy file permissions"); } if (lseek(cipher_text_meta.file_desc, plain_text_meta.file_info.st_size + EVP_CIPHER_block_size(evp_cipher), SEEK_SET) == -1) { perror("Can't seek to new end of destination file"); } unsigned char dummy = 0; if (write(cipher_text_meta.file_desc, &dummy, 1) == -1) { perror("Couldn't write dummy byte"); } unsigned char *key; unsigned char *iv; create_key_iv_from_file(key_iv, &key, &iv, evp_cipher); int cipher_text_len = 0; if (!mk_evp_encrypt(plain_text_mem, plain_text_meta.file_info.st_size, cipher_text_mem, &cipher_text_len, evp_cipher, key, iv)) { fprintf(stderr, "Encryption went wrong\n"); exit(EXIT_FAILURE); } if (ftruncate(cipher_text_meta.file_desc, cipher_text_len) != 0) { perror("Trimming of final plain text failed"); exit(EXIT_FAILURE); } free(key); free(iv); close_file_memory_mapped(&plain_text_mem, &plain_text_meta); close_file_memory_mapped(&cipher_text_mem, &cipher_text_meta); } int main(int argc, char *argv[]) { enum mode { none, decrypt, encrypt, hash } mode = none; char in_path[512]; memset(in_path, '\0', sizeof(in_path)); char out_path[512]; memset(out_path, '\0', sizeof(out_path)); char key_path[512]; memset(key_path, '\0', sizeof(key_path)); char cipher[512]; memset(cipher, '\0', sizeof(cipher)); unsigned corrupt_byte_pos = -1; int flag; while ((flag = getopt(argc, argv, "deh i:o:c:k:b:")) != -1) { switch (flag) { case 'e': mode = encrypt; break; case 'd': mode = decrypt; break; case 'h': mode = hash; break; case 'i': strncpy(in_path, optarg, sizeof(in_path) - 1); break; case 'o': strncpy(out_path, optarg, sizeof(out_path) - 1); break; case 'k': strncpy(key_path, optarg, sizeof(key_path) - 1); break; case 'c': strncpy(cipher, optarg, sizeof(cipher) - 1); break; case 'b': errno = 0; corrupt_byte_pos = strtol(optarg, NULL, 10); if (errno != 0) { perror("Could not read byte position, assuming key is ok"); corrupt_byte_pos = -1; } break; default: return EXIT_FAILURE; break; } } switch (mode) { case decrypt: decrypt_mode(in_path, out_path, key_path, corrupt_byte_pos, cipher); break; case encrypt: encrypt_mode(in_path, out_path, key_path, cipher); break; case hash: hash_mode(in_path, out_path, cipher); break; case none: default: fprintf(stderr, "No mode was specified\n"); printf("Usage %s -<MODE> -<PARAMETERS>\n", argv[0]); printf("\t<MODE>:\n"); printf("\t\t e Encrypt aka Aufgabe 3\n"); printf("\t\t d Decrypt aka Aufgabe 1\n"); printf("\t\t h Hash aka Aufgabe 2\n"); printf("\t<PARAMETERS>: \n"); printf("\t\t i Input file path\n"); printf("\t\t o Output file path, optional for hash mode\n"); printf("\t\t k Key/IV file path, optional for hash mode\n"); printf("\t\t c EVP Cipher/Digest to be used\n"); printf("\t\t b Corrupt byte position, counted from 0, optional for hash mode\n"); exit(EXIT_FAILURE); break; } return EXIT_SUCCESS; } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.