使用 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 + [=10=]
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加密消息会显示原来的消息。
您已使用参数
对字符串的终止 nul
进行了加密
sizeof(aes_input)
你是一致的,所以它也被解密了。不幸的是,加密的字符串不再有 nul
终止符,因为它也被加密了。所以我推荐
strlen(aes_input)
用于参数(但不用于字符串分配)。您还必须终止两个字符串 enc_out[]
和 dec_out[]
.
您正在尝试将不可打印的数据转储到终端设备,具体来说是使用期望空终止的库调用来执行此操作。 AES 加密的输出可以包含 any 值的字节(包括嵌入的 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 + [=10=]
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
请特别注意加密的 last 字节。它不是 00
,这意味着您错误使用的 printf
调用正在超出该缓冲区并进入 未定义行为 的领域。事实上,该字符串中 no nullchar 字节(这是一个不同但密切相关的问题,当 是 一个嵌入的 00
在数据的中间,在这种情况下,printf
会过早。
在这种情况下,我可以推测(价值不大;这就是未定义行为的本质)行军printf
进入栈上的下一个自动变量,即解密后的数组。
修改输出序列以使用 all 十六进制输出将演示明文和加密数据之间的区别。例如,将程序的最后三个功能行更改为:
//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 table 将向您显示它们确实是原始短信。
祝你好运。
我正在尝试使用 openssl AES 加密功能进行加密。
这是我的代码:
#include <stdio.h>
#include <openssl/aes.h>
#include <string.h>
const static unsigned char aes_key[]={"passwordpasswor"}; //15 characters + [=10=]
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加密消息会显示原来的消息。
您已使用参数
对字符串的终止nul
进行了加密
sizeof(aes_input)
你是一致的,所以它也被解密了。不幸的是,加密的字符串不再有 nul
终止符,因为它也被加密了。所以我推荐
strlen(aes_input)
用于参数(但不用于字符串分配)。您还必须终止两个字符串 enc_out[]
和 dec_out[]
.
您正在尝试将不可打印的数据转储到终端设备,具体来说是使用期望空终止的库调用来执行此操作。 AES 加密的输出可以包含 any 值的字节(包括嵌入的 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 + [=10=]
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
请特别注意加密的 last 字节。它不是 00
,这意味着您错误使用的 printf
调用正在超出该缓冲区并进入 未定义行为 的领域。事实上,该字符串中 no nullchar 字节(这是一个不同但密切相关的问题,当 是 一个嵌入的 00
在数据的中间,在这种情况下,printf
会过早。
在这种情况下,我可以推测(价值不大;这就是未定义行为的本质)行军printf
进入栈上的下一个自动变量,即解密后的数组。
修改输出序列以使用 all 十六进制输出将演示明文和加密数据之间的区别。例如,将程序的最后三个功能行更改为:
//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 table 将向您显示它们确实是原始短信。
祝你好运。