对于ECB和CBC,OpenSSL EVP解密失败,但对于OFB有效

时间:2018-12-09 08:52:20

标签: c encryption openssl

对于具有OFB模式的AES-128,我的代码可以解密并正常工作,但是对于ECB和CBC,即使我使用相同的密钥和相同的IV,它也只能提供随机输出。

这是我的代码:

#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>
#include <stdio.h>
#define BUFFER_SIZE 4096
#define KEY_SIZE 16


int failed = 0;

void print_hex(char *s){
    while(*s){
        printf("%02x" , (unsigned int) *s++);
    }
}

int min(int a , int b){
    return a < b ? a : b;
}

void set_padding(unsigned char* array){
    for(int i= 0 ; i < KEY_SIZE; ++i){
        array[i] = ' ';
    }
}

int handleErrors(void)
{
    // ERR_print_errors_fp(stderr);
    // abort();
    failed = 1;
    return -1;
}

int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
  unsigned char *iv, unsigned char *ciphertext , char* mode)
{
  EVP_CIPHER_CTX *ctx;

  int len;

  int ciphertext_len;

  if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();

  if(strcmp(mode , "OFB") == 0){
    if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_ofb(), NULL, key, iv))
        handleErrors();
  }
  else{
    if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, NULL))
        handleErrors();
  }
  if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
    handleErrors();
  ciphertext_len = len;

  if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
  ciphertext_len += len;

  EVP_CIPHER_CTX_free(ctx);

  return ciphertext_len;
}

int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
  unsigned char *iv, unsigned char *plaintext , char* mode)
{
  EVP_CIPHER_CTX *ctx;

  int len;

  int plaintext_len;

  if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();

  if(strcmp(mode , "OFB") == 0){
    if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_ofb(), NULL, key, iv))
        handleErrors();
  }
  else{
    if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, NULL))
        handleErrors();
  }
  if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
    handleErrors();
  plaintext_len = len;

  if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors();
  plaintext_len += len;

  EVP_CIPHER_CTX_free(ctx);

  return plaintext_len;
}


void write_to_file(FILE* fd , unsigned char * hash , int size){
    for(int i = 0; i < size; ++i){
        fprintf(fd , "%02x" , hash[i]);
    }
}

void encrypt_and_write(unsigned char *plaintext, int plaintext_len, unsigned char *key,
  unsigned char *iv, char* mode , FILE *fd){
    unsigned char buffer[2 * BUFFER_SIZE];
    int size = 0;
    size = encrypt(plaintext , plaintext_len , key , iv , buffer , mode);
    write_to_file(fd , buffer , size);
}

int main(int argc , char** argv){
    FILE *plain_text , *crypto_text , *dictionary;
    unsigned char plain_text_buffer[BUFFER_SIZE];
    unsigned char crypto_text_buffer[2 * BUFFER_SIZE];
    unsigned int plain_text_size = 0;
    unsigned int crypto_text_size = 0;
    unsigned char iv[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
    unsigned char key[] = "\x73\x65\x63\x69\x6E\x66\x6F\x20\x20\x20\x20\x20\x20\x20\x20\x20";
    memset(plain_text_buffer, 0, sizeof(plain_text_buffer));
    memset(crypto_text_buffer, 0, sizeof(crypto_text_buffer));
    if(argc < 4){
        printf("Wrong number of arguments!\n");
        return 0;
    }
    if(strcmp(argv[3] , "OFB") != 0 && strcmp(argv[3] , "ECB") != 0){
        printf("Use OFB or ECB mode only!\n");
        return 0;
    }
    plain_text = fopen(argv[1] , "r");
    crypto_text = fopen(argv[2] , "r");
    dictionary = fopen("word_dict.txt" , "r");
    char c;
    while((c = fgetc(plain_text)) != EOF){
        plain_text_buffer[plain_text_size] = c;
        ++plain_text_size;
    }
    // encrypt_and_write(plain_text_buffer , plain_text_size , key , iv , argv[3] , crypto_text);
    unsigned int hexa = 0;
    while(fscanf(crypto_text , "%02x" , &hexa) != EOF){
        crypto_text_buffer[crypto_text_size] = hexa;
        ++crypto_text_size;
    }
    char * line = NULL;
    int attempts = 0;
    int len = 0;
    unsigned char decrypt_buffer[BUFFER_SIZE];
    size_t size = 0;
    while(getline(&line , &size , dictionary) != -1){
        set_padding(key);
        for(int i = 0; i < strlen(line); ++i){
            if(line[i] != '\n' && line[i] != '\0'){
                key[i] = line[i];
            }
        }
        key[KEY_SIZE] = '\0';
        decrypt(crypto_text_buffer , crypto_text_size , key , iv , decrypt_buffer , argv[3]);
        if(failed == 0){
            if(strcmp(plain_text_buffer , decrypt_buffer) == 0){
                printf("%i " , attempts);
                print_hex(key);
                printf(" %s" , line);
                break;
            }
            else
                ++attempts;
        }
        else
            ++attempts;
    }
    return 0;
}

我试图找出问题所在,但是没有运气。它甚至适用于OFB模式下的DES,但对于ECB和CBC,它再次失败。

word_dict.txt只是用于暴力破解密钥的文件。

1 个答案:

答案 0 :(得分:2)

您将EVP_EncryptInit_ex用于解密例程;您应该使用EVP_DecryptInit_ex。 OFB是流密码,这意味着加密/解密例程非常相似。 ECB / CBC并非如此,因为它们需要填充/去填充例程。

请注意,您不应按键盘上的按键。如果使用密码,则应该使用密码哈希,也称为基于密码的密钥派生功能。 OpenPB内置了对PBKDF2的支持。