OpenSSL库中的SMIME_read_PKCS7方法具有输入长度1200的限制
SMIME_read_PKCS7 method in OpenSSL library has input length 1200 restriction?
我正在尝试使用OpenSSL提供的高级API进行加密工作。
在这里,它通常工作得很好。
/**
* Instructions for generating private key file and self signed certificate file.
*
* openssl genrsa -des3 -out keys.pem 2048
* openssl rsa -in keys.pem -out rsa.pem
* openssl req -new -x509 -key rsa.pem -out rsa-cert.pem -days 9999
*
* Compile
* g++ -ggdb -o exe.bex src.cpp -lcrypto
*/
//c standard library
#include <stdio.h>
#include <string.h>
//openssl library
#include <openssl/pem.h>
#include <openssl/pkcs7.h>
#include <openssl/x509.h>
//c++ standard library
#include <iostream>
#include <string>
int main(int argc, char* argv[]) {
FILE* fd = fopen("rsa.pem", "r");
X509* x509;
STACK_OF(X509)* x509_stack = sk_X509_new_null();
EVP_PKEY* key;
if (NULL != fd)
{
key = PEM_read_PrivateKey(fd, NULL, NULL, NULL);
}
fd = fopen("rsa-cert.pem", "r");
if (NULL != fd)
{
while (NULL != (x509 = PEM_read_X509(fd, NULL, NULL, NULL)))
{
sk_X509_push(x509_stack, x509);
}
fclose(fd);
}
OpenSSL_add_all_algorithms();
while (!std::cin.eof()) {
std::string msg;
//get input text
printf("Message to PKCS7 encrypt: ");
fflush(stdout);
std::getline(std::cin, msg);
if (223 < msg.length())
{
// SMIME_read_PKCS7 bug, need to be fixed.
//
// bt:
//#0 asn1_d2i_read_bio (in=0x60bc40, pb=0x7fffffffe238) at a_d2i_fp.c:286
//#1 0x00007ffff7aeb762 in ASN1_item_d2i_bio (it=0x7ffff7dc2da0, in=0x60bc40, x=0x0) at a_d2i_fp.c:113
//#2 0x00007ffff7b0201c in b64_read_asn1 (bio=0x60bc40, it=0x7ffff7dc2da0) at asn_mime.c:191
//#3 0x00007ffff7b02dd0 in SMIME_read_ASN1 (bio=0x60af00, bcont=0x7fffffffe350, it=0x7ffff7dc2da0) at asn_mime.c:527
//#4 0x00007ffff7b39db2 in SMIME_read_PKCS7 (bio=0x60af00, bcont=0x7fffffffe350) at pk7_mime.c:96
//#5 0x0000000000401668 in main (argc=1, argv=0x7fffffffe4b8) at ./crypto-pkcs.cpp:99
//
std::cout << "string too long " << msg.length() << std::endl;
continue;
}
if (msg.empty())
{
std::cout << "string too short" << std::endl;
continue;
}
//save input
BIO* bio_input_plain_text = BIO_new(BIO_s_mem());
BIO_write(bio_input_plain_text, msg.c_str(), msg.length());
BIO_flush(bio_input_plain_text);
//create PKCS7 object in the way of PKCS7_encrypt.
PKCS7* pkcs7_encrypt = PKCS7_encrypt(x509_stack, bio_input_plain_text, EVP_aes_256_cbc(), 0);
if (NULL == pkcs7_encrypt) {
std::cout << "PKCS7_encrypt returns NULL" << std::endl; return -1;}
//dump encryped info.
BIO* bio_encrypted_smime = BIO_new(BIO_s_mem());
if (SMIME_write_PKCS7(bio_encrypted_smime, pkcs7_encrypt, bio_input_plain_text, 0) != 1){ std::cout << "SMIME_write_PKCS7 failed" << std::endl; return -1;}
BIO_flush(bio_encrypted_smime);
//get internal data address
const char* encrypted = NULL;
BIO_get_mem_data(bio_encrypted_smime, &encrypted); //encrypted has no new resource, only the reflection of the internal BIO data.
//char encrypted[8 * 1024] = "";
//copy BIO to char array
//BIO_read(bio_encrypted_smime, encrypted, sizeof encrypted - 1); //if we read the data out of BIO, later we need to write it back, BIO_read deletes the internal data inside BIO
std::cout << "PKCS7_encrypt length:" << strlen(encrypted) << std::endl << encrypted << std::endl;
//please be careful while taking care of BIO object.
//if we call BIO_read against BIO to get out data, the operation will cause the data deleted in the BIO at the same time.
//here we recover BIO data.
//BIO_write(bio_encrypted_smime, encrypted, strlen(encrypted));
//BIO_flush(bio_encrypted_smime);
BIO* bio_pkcs7 = BIO_new(BIO_s_mem());
//read&load PKCS7 object from SMIME format.
PKCS7* pkcs7_smime = SMIME_read_PKCS7(bio_encrypted_smime, &bio_pkcs7);
if (NULL == pkcs7_smime) {std::cout << "SMIME_read_PKCS7 returns NULL" << std::endl;return -1;}
BIO_flush(bio_pkcs7);
BIO* bio_pkcs7_decrypt = BIO_new(BIO_s_mem());
//decrypt in the way of PKCS7_decrypt
if (0 == PKCS7_decrypt(pkcs7_smime, key, x509, bio_pkcs7_decrypt, 0)){ std::cout << "PKCS7_decrypt failed" << std::endl;return -1;}
BIO_flush(bio_pkcs7_decrypt);
//char decrypted[8 * 1024] = "";
//dump decrypted data.
//BIO_read(bio_pkcs7_decrypt, decrypted, sizeof decrypted - 1);
const char* decrypted = NULL;
//get internal data address
BIO_get_mem_data(bio_pkcs7_decrypt, &decrypted);
std::cout << "PKCS7_decrypt length: " << strlen(decrypted) << std::endl << decrypted << std::endl;
//cleanup, idiot! donot forget to release resource you piece of shit!
BIO_free(bio_pkcs7_decrypt);
BIO_free(bio_pkcs7);
BIO_free(bio_encrypted_smime);
PKCS7_free(pkcs7_smime);
PKCS7_free(pkcs7_encrypt);
}
X509_free(x509);
sk_X509_pop_free(x509_stack, X509_free);
return 0;
}
这段代码在openssl-1.0.1g下运行良好。我尝试了线程和无线程配置选项。
但是如果我们输入一个224长度的纯文本没有if-continue的东西,加密仍然工作,它无法在SMIME_read_PKCS7的方法中解密,检查上面的回溯注释。
如果输入长度为223,则加密后的S/MIME长度为1200。
在224长度输入的情况下,S/MIME格式的加密结果长度超过1200,SMIME_read_PKCS7无法处理该长度,检查上面的内部调用,但我没有找到任何文档或页面进行解释。
smme_read_pkcs7的秘密是什么?
缺陷1:在@jw的帮助下。应该有
BIO_set_mem_eof_return(bio_encrypted_smime, 0);
之前PKCS7* pkcs7_smime = SMIME_read_PKCS7(bio_encrypted_smime, &bio_pkcs7);
缺陷2:BIO_get_mem_data这个应该返回数据的长度,实际上我们需要根据长度来处理char*,不要仅仅依赖于null终止,除非你期望附加垃圾值
smme_read_pkcs7的秘密是什么?
其实没什么秘密。就是有毛病。根据SMIME_read_PKCS7(3)上的文档:
BUGS
The MIME parser used by SMIME_read_PKCS7() is somewhat primitive.
While it will handle most S/MIME messages more complex compound
formats may not work.
The parser assumes that the PKCS7 structure is always base64
encoded and will not handle the case where it is in binary
format or uses quoted printable format.
The use of a memory BIO to hold the signed content limits the
size of message which can be processed due to memory restraints:
a streaming single pass option should be available.
在OpenSSL用户组中有一些关于SMIME_read_PKCS7
的好线程
相关文章:
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 2D数组来自文本输入,中间有空格
- 如何使用 < 和 > 命令获取 c++ 中的输入和输出?
- 检查输入是否不是整数或数字
- 正在尝试了解输入验证循环
- 读取文件并输入到矢量中
- C++如何通过用户输入删除列表元素
- 用c++从输入文件中读取另一行
- 读取文件的最后一行并输入到链接列表时出错
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 如何使用用户输入在C++中正确填充2D数组
- C++MySQL C api用户输入行
- 输入到文件并输出到另一个文件,并将流文件传递给函数
- 用户定义函数中的指针和输入
- 如何在C++中检查2D数组中负值的输入验证
- 如何只允许用户输入正整数
- 在while循环中输入带有std::cin的字符串后,控制台会输出大量胡言乱语
- 输入中的字符串数未知(以字母表示)
- cpp二进制搜索问题,计算给定数组中输入元素的出现次数
- OpenSSL库中的SMIME_read_PKCS7方法具有输入长度1200的限制