使用 OpenSSL AES 命令行工具和 OpenSSL AES API 时密文不同?
为什么我使用 openssl aes 命令工具和 openssl AES api 时得到不同的密文?
我使用了三种类型的加密:
- a) openssl 命令行工具
- b) javax.cryto 中的
- 类 c) OpenSSL C api。
使用类型(a)和(b),我得到了相同的密文。但使用(c)时我得到了不同的密文。
我想在使用方法c和方法a/b时得到相同的密文。 我认为type c有问题,但我找不到它。请注意,我在上述三种方法中使用了相同的 KEY,IV 对。
键入 a:
openssl enc -aes-128-cbc -e -a -in pt.txt -out ct.txt -K 01010101010101010101010101010101 -iv 01010101010101010101010101010101 -p
键入 b:
使用 javax.crypto 的 Java 代码。我不会粘贴代码,因为这样我得到了与 Type a 相同的密文。
类型 c: 使用 OpenSSL API 的 C 代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/aes.h>
int main(int argc, char** argv) {
AES_KEY aes;
unsigned char key[AES_BLOCK_SIZE]; // AES_BLOCK_SIZE = 16
unsigned char iv[AES_BLOCK_SIZE]; // init vector
unsigned char* input_string;
unsigned char* encrypt_string;
unsigned char* decrypt_string;
unsigned int len; // encrypt length (in multiple of AES_BLOCK_SIZE)
unsigned int i;
// check usage
if (argc != 2) {
fprintf(stderr, "%s <plain text>\n", argv[0]);
exit(-1);
}
// set the encryption length
len = 0;
if ( strlen(argv[1])>=AES_BLOCK_SIZE ||
(strlen(argv[1]) + 1) % AES_BLOCK_SIZE == 0) {
len = strlen(argv[1]) + 1;
} else {
len = ((strlen(argv[1]) + 1) / AES_BLOCK_SIZE + 1) * AES_BLOCK_SIZE;
}
// set the input string
input_string = (unsigned char*)calloc(len, sizeof(unsigned char));
if (input_string == NULL) {
fprintf(stderr, "Unable to allocate memory for input_string\n");
exit(-1);
}
strncpy((char*)input_string, argv[1], strlen(argv[1]));
// Generate AES 128-bit key
memset(key, 0x01, AES_BLOCK_SIZE);
// Set encryption key
memset(iv, 0x01, AES_BLOCK_SIZE);
if (AES_set_encrypt_key(key, 128, &aes) < 0) {
fprintf(stderr, "Unable to set encryption key in AES\n");
exit(-1);
}
// alloc encrypt_string
encrypt_string = (unsigned char*)calloc(len, sizeof(unsigned char));
if (encrypt_string == NULL) {
fprintf(stderr, "Unable to allocate memory for encrypt_string\n");
exit(-1);
}
// encrypt (iv will change)
AES_cbc_encrypt(input_string, encrypt_string, len, &aes, iv, AES_ENCRYPT);
/////////////////////////////////////
// alloc decrypt_string
decrypt_string = (unsigned char*)calloc(len, sizeof(unsigned char));
if (decrypt_string == NULL) {
fprintf(stderr, "Unable to allocate memory for decrypt_string\n");
exit(-1);
}
// Set decryption key
memset(iv, 0x01, AES_BLOCK_SIZE);
if (AES_set_decrypt_key(key, 128, &aes) < 0) {
fprintf(stderr, "Unable to set decryption key in AES\n");
exit(-1);
}
// decrypt
AES_cbc_encrypt(encrypt_string, decrypt_string, len, &aes, iv,
AES_DECRYPT);
// print
printf("input_string =%s\n", input_string);
printf("encrypted string =");
for (i=0; i<len; ++i) {
printf("%u ", encrypt_string[i]);
}
printf("\n");
printf("decrypted string =%s\n", decrypt_string);
return 0;
}
不同输出的原因可能是什么?
Why do i got different ciphertexts when i used openssl aes command tools and openssl AES apis ?
I have used three types of encryption:
- Type a) openssl command line tool
- Type b) classes in javax.cryto
- Type c) OpenSSL C api.
Using type (a) and (b), I got the same ciphertext. But I got different ciphertext when using (c).
I want to get the same ciphertexts when using method c and method a/b.
I think there's something wrong in type c, but I can't find it. Note that I used the same KEY,IV pair in the above three methods.
Type a:
openssl enc -aes-128-cbc -e -a -in pt.txt -out ct.txt -K 01010101010101010101010101010101 -iv 01010101010101010101010101010101 -p
Type b:
Java code using javax.crypto. I won't paste the code, because this way I got the same ciphertext with Type a.
Type c:
C code using OpenSSL API:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/aes.h>
int main(int argc, char** argv) {
AES_KEY aes;
unsigned char key[AES_BLOCK_SIZE]; // AES_BLOCK_SIZE = 16
unsigned char iv[AES_BLOCK_SIZE]; // init vector
unsigned char* input_string;
unsigned char* encrypt_string;
unsigned char* decrypt_string;
unsigned int len; // encrypt length (in multiple of AES_BLOCK_SIZE)
unsigned int i;
// check usage
if (argc != 2) {
fprintf(stderr, "%s <plain text>\n", argv[0]);
exit(-1);
}
// set the encryption length
len = 0;
if ( strlen(argv[1])>=AES_BLOCK_SIZE ||
(strlen(argv[1]) + 1) % AES_BLOCK_SIZE == 0) {
len = strlen(argv[1]) + 1;
} else {
len = ((strlen(argv[1]) + 1) / AES_BLOCK_SIZE + 1) * AES_BLOCK_SIZE;
}
// set the input string
input_string = (unsigned char*)calloc(len, sizeof(unsigned char));
if (input_string == NULL) {
fprintf(stderr, "Unable to allocate memory for input_string\n");
exit(-1);
}
strncpy((char*)input_string, argv[1], strlen(argv[1]));
// Generate AES 128-bit key
memset(key, 0x01, AES_BLOCK_SIZE);
// Set encryption key
memset(iv, 0x01, AES_BLOCK_SIZE);
if (AES_set_encrypt_key(key, 128, &aes) < 0) {
fprintf(stderr, "Unable to set encryption key in AES\n");
exit(-1);
}
// alloc encrypt_string
encrypt_string = (unsigned char*)calloc(len, sizeof(unsigned char));
if (encrypt_string == NULL) {
fprintf(stderr, "Unable to allocate memory for encrypt_string\n");
exit(-1);
}
// encrypt (iv will change)
AES_cbc_encrypt(input_string, encrypt_string, len, &aes, iv, AES_ENCRYPT);
/////////////////////////////////////
// alloc decrypt_string
decrypt_string = (unsigned char*)calloc(len, sizeof(unsigned char));
if (decrypt_string == NULL) {
fprintf(stderr, "Unable to allocate memory for decrypt_string\n");
exit(-1);
}
// Set decryption key
memset(iv, 0x01, AES_BLOCK_SIZE);
if (AES_set_decrypt_key(key, 128, &aes) < 0) {
fprintf(stderr, "Unable to set decryption key in AES\n");
exit(-1);
}
// decrypt
AES_cbc_encrypt(encrypt_string, decrypt_string, len, &aes, iv,
AES_DECRYPT);
// print
printf("input_string =%s\n", input_string);
printf("encrypted string =");
for (i=0; i<len; ++i) {
printf("%u ", encrypt_string[i]);
}
printf("\n");
printf("decrypted string =%s\n", decrypt_string);
return 0;
}
What could be the reason for different outputs?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在您的 C 代码中,您本质上是在使用零填充:您分配一个由零填充的内存区域(通过
calloc
),然后将纯文本复制到此区域,保留末尾的零不变。openssl enc
使用与 C 代码不同的填充。openssl enc
的文档说(强调我):此外,openssl enc 命令默认使用盐,这会随机化密文。盐的用途与每消息初始化向量 (IV) 类似。但是您使用的是显式 IV,因此盐不会随机化密文。
javax.crypto.Cipher 的文档 (我想你用过)说:
因此,如果您只是使用
AES
或ARS/CBC
而不指示填充模式,它将使用它认为合适的任何内容,其中您的情况恰好与 OpenSSL 使用的情况相同(即 PKCS#5 填充)。要更改您的 C 程序,您必须自己进行相同的填充(本质上,它是用 x 字节填充块,所有字节的值都与该数字相同,同时附加填充了 16 个字节的整个块当最后一个块已经满时) - 或使用更高级别的 EVP 函数,这应该为您提供一种指定密码的填充模式的方法。
In your C code, you are essentially using zero-padding: You allocate a memory area filled by zeros (by
calloc
), and then copy the plain text into this area, leaving the zeros at the end intact.The
openssl enc
uses different padding than your C code. The documentation foropenssl enc
says (emphasis by me):In addition, the
openssl enc
command uses a salt by default, which randomizes the ciphertext. The salt serves a similar purpose as a per-message Initialization Vector (IV). But you are using an explicit IV, so the salt is not randomizing the ciphertext.The documentation for javax.crypto.Cipher (which I suppose you used) says:
So if you simply are using
AES
orARS/CBC
without indicating the padding mode, it uses whatever it finds fitting, which in your case happened to be the same as what OpenSSL used (i.e. PKCS#5 padding).To change your C program, you'll have to do the same padding yourself (essentially, it is filling the block with a number x of bytes, all of which have the same value as this number, while appending a whole block filled with 16 when the last block is already full) - or use the higher level EVP-functions, which should provide you with a way to specify the padding mode to the cipher.