繁体   English   中英

使用openssl进行AES加密

[英]AES encryption using openssl

我正在尝试使用openssl AES加密功能进行加密。

这是我的代码:

#include <stdio.h>
#include <openssl/aes.h>
#include <string.h>

const static unsigned char aes_key[]={"passwordpasswor"}; //15 characters + \0
void print_data(const char *tittle, const void* data, int len);

int main() {
unsigned char aes_input[]="#!/bin/bash\necho hello world";
unsigned char iv[AES_BLOCK_SIZE];
memset (iv,0x00,AES_BLOCK_SIZE);
unsigned char enc_out[sizeof(aes_input)];
unsigned char dec_out[sizeof(aes_input)];
AES_KEY enc_key,dec_key;
AES_set_encrypt_key(aes_key,sizeof(aes_key)*8,&enc_key);
AES_cbc_encrypt(aes_input,enc_out,sizeof(aes_input),&enc_key,iv,AES_ENCRYPT);
//decryption
memset(iv,0x00,AES_BLOCK_SIZE);
AES_set_decrypt_key(aes_key,sizeof(aes_key)*8,&dec_key);
AES_cbc_encrypt(enc_out,dec_out,sizeof(aes_input),&dec_key,iv,AES_DECRYPT);
//verify
printf("original %s\n",aes_input);
printf("encrypted %s\n",enc_out);
printf("decrypted %s\n",dec_out);
return 0;
}

该代码产生以下输出(为清楚起见,在每个输出之间都有一个额外的换行符):

original #!/bin/bash
echo hello world

encrypted ���jv�.)��$I���b�:dmPvTQޜ�#!/bin/bash
echo hello world

decrypted #!/bin/bash
echo hello world

我尝试了其他消息,如果与printf一起使用,则加密消息似乎将显示原始消息。

您正在尝试将不可打印的数据转储到终端设备,特别是使用需要空终止的库调用。 AES加密的输出可以包含任何值的字节(包括嵌入式nullchar值)

您需要以下内容:

  • 适当调整输出缓冲区的大小。 默认情况下, AES_cbc_encrypt使用pkcs填充,并将最多使用一个完整的附加块来填充数据。
  • 使用其他机制转储输出,例如普通的hexdump例程。

以上两项都在下面完成:

#include <stdio.h>
#include <openssl/aes.h>
#include <string.h>

static hex_print(const void *pv, size_t len)
{
    static const char alpha[] = "0123456789abcdef";
    const unsigned char *beg = pv, *end = beg+len;

    for (; beg != end; ++beg)
    {
        putc(alpha[(*beg >> 4) & 0xF], stdout);
        putc(alpha[*beg & 0xF], stdout);
    }
    putc('\n', stdout);
}

const static unsigned char aes_key[]={"passwordpasswor"}; //15 characters + \0
void print_data(const char *tittle, const void* data, int len);

int main() {
    unsigned char aes_input[]="#!/bin/bash\necho hello world";
    unsigned char enc_out[AES_BLOCK_SIZE * ((sizeof(aes_input) + AES_BLOCK_SIZE)/AES_BLOCK_SIZE)];
    unsigned char dec_out[sizeof(aes_input)];
    unsigned char iv[AES_BLOCK_SIZE] = {0};

    AES_KEY enc_key,dec_key;
    AES_set_encrypt_key(aes_key,sizeof(aes_key)*8,&enc_key);
    AES_cbc_encrypt(aes_input,enc_out,sizeof(aes_input),&enc_key,iv,AES_ENCRYPT);

    //decryption
    memset(iv,0x00,AES_BLOCK_SIZE);
    AES_set_decrypt_key(aes_key,sizeof(aes_key)*8,&dec_key);
    AES_cbc_encrypt(enc_out,dec_out,sizeof(aes_input),&dec_key,iv,AES_DECRYPT);

    //verify
    printf("original %s\n",aes_input);
    hex_print(enc_out, sizeof enc_out);
    printf("decrypted %s\n",dec_out);
    return 0;
}

输出量

original #!/bin/bash
echo hello world
e389c96a76d708b42e29b4b4052449f1ffc762db3a646d1650765451de9c1dd0
decrypted #!/bin/bash
echo hello world

特别要注意加密的最后一个字节。 不是00 ,这意味着您错误地使用的printf调用正在越过该缓冲区进入未定义行为的领域 事实上,也有在该字符串没有 nullchar字节(这是一个不同,但密切相关的问题时, 一个嵌入式00在你的数据中间 ,在这种情况下printf提前停止。

在这种情况下,我可以推测 (值很小;这是未定义行为的性质)行军将printf带入堆栈上的下一个自动变量,该变量是解密后的数组。

修改输出顺序以使用所有十六进制输出将证明纯文本和加密数据之间的区别。 例如,将程序的最后三个功能行更改为:

//verify
hex_print(aes_input, sizeof(aes_input));
hex_print(enc_out, sizeof enc_out);
hex_print(dec_out, sizeof(dec_out));

将提供以下输出:

23212f62696e2f626173680a6563686f2068656c6c6f20776f726c6400
e389c96a76d708b42e29b4b4052449f1ffc762db3a646d1650765451de9c1dd0
23212f62696e2f626173680a6563686f2068656c6c6f20776f726c6400

这是有道理的。 如果您遍历原始和解密的字符串中的字节(每个两位),您会发现它们是(a)相等,(b)不等于密文,以及(c),在ascii表中待一会儿向您展示它们确实是原始短信。

祝你好运。

您已使用参数加密了字符串的终止nul

sizeof(aes_input)

您是一致的,因此也将其解密。 不幸的是,加密的字符串不再具有nul终止符,因为它也被加密了。 所以我推荐

strlen(aes_input)

用于参数(但不用于字符串分配)。 您还必须终止两个字符串enc_out[]dec_out[]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM