I am currently doing some testing on brute forcing some simple text using EVP in C.
The plaintext, ciphertext, key size, encryption method and methodology are provided. We simply need to try different key which is a known dictionary word.
THE MAIN ISSUE IS IF I TRY TO CALL THE EVP METHOD DIRECTLY FROM MAIN LIKE THIS:
int main(int argc, char const *argv[]) {
evp((unsigned char *)"This is a top secret.");
return 0;
}
It fails to find the key(cannot generate the same cipher)
But the call with clock();
called:
int main(int argc, char const *argv[])
{
clock_t begin = clock();
evp((unsigned char *)"This is a top secret.");
return 0;
}
It works fine! Why is this happening? What am I doing wrong? Can someone explain what the problem is?
The encryption using aes-128-cbc to encrypt the plaintext, while the iv is 16 bytes NULL and the key is a single dictionary word with the length smaller than 16 and will be feed with empty space when its length is smaller than 16.
The Following code is used to perform the whole process:
void evp(unsigned char * plaintext) {
FILE *fp = fopen("words.txt", "r");
const char cipher[] ="8d20e5056a8d24d0462ce74e4904c1b513e10d1df4a2ef2ad4540fae1ca0aaf9";
unsigned char iv[16];
unsigned char ciphertext[256];
/**Init OpenSSL**/
ERR_load_crypto_strings();
OPENSSL_config(NULL);
OpenSSL_add_all_algorithms();
unsigned char word[17];
while(read_word(fp, word)==0) {
if(strlen((char *)word) < 16) {
add_space(word, sizeof(word));
encrypt(plaintext, strlen((char *)plaintext), word, iv, ciphertext);
if(strcmp((char *)ciphertext, cipher) == 0 ) {
printf("The key is : %s\n", word);
fclose(fp);
exit(0);
};
}
}
fclose(fp);
}
The add_space
method simply feed the key with empty space:
int add_space(unsigned char *str, size_t len) {
int eol_pos = strlen((char *)str);
int empty_space = len - eol_pos - 1 ;
//set space and eol
memset(str+eol_pos, ' ', empty_space);
memset(str+len, '\0', 0);
return 0;
}
The read_word
method read a single word from the dictionary:
int read_word(FILE *file, unsigned char * word) {
//Using fscanf
unsigned char word_buf[255];
if(fscanf(file, "%s", word_buf) != EOF) {
if( strlen( (char *)word_buf ) < 15 ) {
strcpy((char *)word,(char *) word_buf);
}
return 0;
}
return 1;
}
And the encrypt
method is the main process to encrypt the plaintext:
void encrypt(unsigned char *plaintext, int plain_len ,unsigned char *key, unsigned char * iv, unsigned char * ciphertext) {
EVP_CIPHER_CTX *ctx;
int out_len;
int ciphertext_len;
char *buff;
if(! (ctx = EVP_CIPHER_CTX_new()) ) {
handleErrors();
}
if( EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1 )
handleErrors();
if( EVP_EncryptUpdate(ctx, ciphertext, &out_len, plaintext, plain_len ) != 1 ) {
handleErrors();
}
ciphertext_len = out_len;
if( EVP_EncryptFinal_ex(ctx, ciphertext+out_len, &out_len) != 1 ) {
handleErrors();
}
ciphertext_len += out_len;
EVP_CIPHER_CTX_cleanup(ctx);
buff = malloc(ciphertext_len*2+1);
memset(buff, 0, ciphertext_len*2+1);
for (int i = 0; i < ciphertext_len; ++i)
{
char tmp[3];
sprintf(tmp, "%02x", ciphertext[i]);
strcat(buff, tmp);
}
strcpy((char *)ciphertext, buff);
free(buff);
}
You're never actually setting iv
to anything. Because iv
is a local variable, its contents are uninitialized, and subsequently reading it results in undefined behavior.
What's probably happening when you call clock
is that the stack space that was used by this function probably left some null bytes somewhere on the stack that just so happens to be where iv
will reside when the encrypt
function is called. You can't depend on this behavior, however.
Initialize iv
to all zeros. Then you'll get the behavior you expect.
unsigned char iv[16] = { 0 };