实施 openssl evp 加密
implementing openssl evp encryption
我目前正在使用 C 中的 EVP 对一些简单文本进行暴力破解测试。
提供了明文、密文、密钥大小、加密方法和方法论。我们只需要尝试不同的键,这是一个已知的字典词。
主要问题是如果我尝试像这样直接从 main 调用 EVP 方法:
int main(int argc, char const *argv[]) {
evp((unsigned char *)"This is a top secret.");
return 0;
}
找不到密钥(无法生成相同的密码)
但是 clock();
调用的是:
int main(int argc, char const *argv[])
{
clock_t begin = clock();
evp((unsigned char *)"This is a top secret.");
return 0;
}
效果很好!为什么会这样?我究竟做错了什么?谁能解释一下问题出在哪里?
加密采用aes-128-cbc加密明文,iv为16字节NULL,key为单个字典词,长度小于16,填空space当它的长度小于 16.
以下代码用于执行整个过程:
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);
}
add_space
方法简单地用空的 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, '[=13=]', 0);
return 0;
}
read_word
方法从字典中读取单个单词:
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;
}
而encrypt
方法是加密明文的主要过程:
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);
}
您实际上从未将 iv
设置为任何内容。因为 iv
是一个局部变量,它的内容是未初始化的,随后读取它会导致未定义的行为。
当您调用 clock
时可能发生的事情是,此函数使用的堆栈 space 可能在堆栈的某处留下了一些空字节,恰好在 iv
将在调用 encrypt
函数时驻留。但是,您不能依赖这种行为。
将 iv
初始化为全零。然后你会得到你期望的行为。
unsigned char iv[16] = { 0 };
我目前正在使用 C 中的 EVP 对一些简单文本进行暴力破解测试。
提供了明文、密文、密钥大小、加密方法和方法论。我们只需要尝试不同的键,这是一个已知的字典词。
主要问题是如果我尝试像这样直接从 main 调用 EVP 方法:
int main(int argc, char const *argv[]) {
evp((unsigned char *)"This is a top secret.");
return 0;
}
找不到密钥(无法生成相同的密码)
但是 clock();
调用的是:
int main(int argc, char const *argv[])
{
clock_t begin = clock();
evp((unsigned char *)"This is a top secret.");
return 0;
}
效果很好!为什么会这样?我究竟做错了什么?谁能解释一下问题出在哪里?
加密采用aes-128-cbc加密明文,iv为16字节NULL,key为单个字典词,长度小于16,填空space当它的长度小于 16.
以下代码用于执行整个过程:
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);
}
add_space
方法简单地用空的 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, '[=13=]', 0);
return 0;
}
read_word
方法从字典中读取单个单词:
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;
}
而encrypt
方法是加密明文的主要过程:
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);
}
您实际上从未将 iv
设置为任何内容。因为 iv
是一个局部变量,它的内容是未初始化的,随后读取它会导致未定义的行为。
当您调用 clock
时可能发生的事情是,此函数使用的堆栈 space 可能在堆栈的某处留下了一些空字节,恰好在 iv
将在调用 encrypt
函数时驻留。但是,您不能依赖这种行为。
将 iv
初始化为全零。然后你会得到你期望的行为。
unsigned char iv[16] = { 0 };