Search code examples
caesencryption-symmetric

Unable to find aes-128-encryption key


I am not able to find any bugs..

What I want to do:

  • read the key(from common word list) from a file
  • try all possible key for encryption
  • get a key that able to produce preferred ciphertext

Remark:

  • encrpytion use AES-128-CBC
  • the key has been read that has less 16 characters will be padded with "#"(hex: 0x23)
  • wordList is correct

Here is my code:

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/evp.h>

void pad(char *s,int length);
int strcicmp(char const *a, char const *b);

int main(){


    int i;

    char words[16],t;
    FILE *key;
    unsigned char outbuf[1024 + EVP_MAX_BLOCK_LENGTH];
    unsigned char iv[] = {0xaa,0xbb,0xcc,0xdd,0xee,0xff,0x00,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,0x11};

    int outlen, tmplen;


    EVP_CIPHER_CTX ctx;
    EVP_CIPHER_CTX_init(&ctx);
    char inText[] = "This is a top secret.";
    char cipherTextGiven[] = "764aa26b55a4da654df6b19e4bce00f4ed05e09346fb0e762583cb7da2ac93a2";
    key = fopen("wordList.txt","r");


    while(fgets(words,16, key)) {

        i=strlen(words);
        words[i-1]='\0';
        i=strlen(words);

        if(i<16){
            pad(words,16);
        }
        EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(),NULL, words, iv);
        if(!EVP_EncryptUpdate(&ctx, outbuf, &outlen, inText, strlen(inText))){
            EVP_CIPHER_CTX_cleanup(&ctx);
            return 0;
        }
        if(!EVP_EncryptFinal_ex(&ctx, outbuf + outlen, &tmplen)){
            EVP_CIPHER_CTX_cleanup(&ctx);
            return 0;
        }
        outlen += tmplen;

        int i;
        char* buf_str = (char*) malloc (2*outlen + 1);
        char* buf_ptr = buf_str;
        for(i=0;i<outlen;i++)
            buf_ptr += sprintf(buf_ptr, "%02X", outbuf[i]);

        *(buf_ptr + 1) = '\0';

        printf("%s\n",buf_str);
        if(strcicmp(cipherTextGiven, buf_str) == 0){

            printf("Key: %s\nwith corresponding cipher: ", words);
            for(i=0; i < outlen; i++)
                printf("%02x",outbuf[i]);
            printf("\n");

        }

    }
    fclose(key);

    return 1;
}

//provide padding function to key
void pad(char *s,int length){

    int l;
    l = strlen(s);

    while(l<length){
        s[l] = 0x23;
        l++;
    }
    s[l] = '\0'; //add termination char for the array

}

int strcicmp(char const *a, char const *b){

    for(;;a++,b++){
        int d = tolower(*a) - tolower(*b);
        if(d != 0 || !*a)
            return d;
    }

}

Solution

  • Errors

    Change char words[16] to char words[18]. You need 18 elements in words because you want to handle keys of up to 16 characters, because fgets will read a key plus a new-line character, and the buffer will contain a null character after that.

    Change fgets(word,16, key) to fgets(word, sizeof word, key). fgets needs to know the full size of the available buffer, including space for the new-line character and the terminating null character, not just the number of key characters you want.

    Delete *(buf_ptr + 1) = '\0';. It is unnecessary because sprintf writes a terminating null character and because the correct location for it would be buf_ptr, not buf_ptr+1. So this statement is writing beyond the space allocated for buf_str.

    Bad code

    The following code is not causing whatever problem you are observing, but it could be written better.

    Declare main as int main(void) or int main(int argc, char *argv[]), not int main().

    Do not write s[l] = 0x23; unless you need to write a program that uses a character set different from the character set of the C implementation it is compiled and executed with. To set a character to “#“, use s[l] = '#';.

    If, in sprintf(buf_ptr, "%02X", outbuf[i]);, you change %02X to %02x, then it will use lowercase for the hexadecimal, and you can use the standard strcmp to compare the buffer to cipherTextGiven instead of needing a custom strcicmp function. Better yet, when the program starts, convert cipherTextGiven from hexadecimal to raw binary and, when testing candidate keys, compare that raw binary to the computed cipher text using memcmp.

    In this:

    i=strlen(words);
    words[i-1]='\0';
    i=strlen(words);
    

    Change the last line to i = i-1;, because we know that the previous line decreased the length by one, so we can set the length directly without calling strlen again. Many programmers would write these lines as something like:

    i = strlen(words);
    words[--i] = '\0';