Hello. I'm trying to use high level API provided by OpenSSL for cryptography work.
Here it works pretty well. /** * 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; } This piece of code works fine with openssl-1.0.1g. I tried both threads and no-threads config options. But if we input one 224 length plain text WITHOUT the if-continue stuff, encryption is still working, it fails to decrypt in the method of SMIME_read_PKCS7, check backtrace comment above. The length of encrypted S/MIME is 1200 in case of the length of input is 223. In the case of 224 length input, the encrypted result which is in S/MIME format has length beyond 1200, SMIME_read_PKCS7 can not handle that length, check bt above for internal calls, but I have not find any document or page for explanation. What is the secret of SMIME_read_PKCS7?