BIO_write() is not writing to the file when using BIO_f_base64() - c++

I am trying to learn OPENSSL and following this tutorial. I have written following code to read from a file and write the encoded form in another file.
#include <iostream>
#include <openssl/ssl.h>
#include <openssl/bio.h>
#define MAX_BUFFER_SIZE 512
int main (int argc, char* argv[])
{
BIO* bio_out = nullptr;
BIO* bio_in = nullptr;
BIO* bio_b64 = nullptr;
int in_byte, out_byte;
char buffer[MAX_BUFFER_SIZE];
std::memset(buffer, '\0', MAX_BUFFER_SIZE);
if (argc != 3)
{
std::cout << "Usage: bio_b64_encode <source-read> <encoded-write>\n";
return 1;
}
bio_in = BIO_new_file(argv[1], "r");
bio_out = BIO_new_file(argv[2], "wb");
bio_b64 = BIO_new(BIO_f_base64());
BIO_push(bio_b64, bio_out);
in_byte = BIO_read(bio_in, buffer, MAX_BUFFER_SIZE);
while (in_byte > 0)
{
std::cout << "Read " << in_byte << " bytes.\n";
out_byte = BIO_write(bio_b64, buffer, in_byte);
std::cout << "Wrote " << out_byte << " bytes.\n";
if (in_byte != out_byte)
{
std::cout << "In bytes: " << in_byte << "and Out bytes: " << out_byte << " are not equal.\n";
BIO_free(bio_in);
BIO_free(bio_out);
return 1;
}
in_byte = BIO_read(bio_in, buffer, MAX_BUFFER_SIZE);
}
BIO_free(bio_in);
BIO_free_all(bio_b64);
return 0;
}
The code reads properly from the input file given in argv[1] and tries to write to argv[2] but when I open the output file, it is empty but it should have the encoded text from the input file.
the output of the above program when I run ./bio_b64_encode in.txt out.txt is
Read 22 bytes.
Wrote 22 bytes.
but the output file is empty. If I remove the encoding constraints and try to simply write whatever I read from input file (the code is below), it works properly.
#include <iostream>
#include <openssl/ssl.h>
#include <openssl/bio.h>
#define MAX_BUFFER_SIZE 512
int main (int argc, char* argv[])
{
BIO* bio_out = nullptr;
BIO* bio_in = nullptr;
BIO* bio_b64 = nullptr;
int in_byte, out_byte;
char buffer[MAX_BUFFER_SIZE];
std::memset(buffer, '\0', MAX_BUFFER_SIZE);
if (argc != 3)
{
std::cout << "Usage: bio_write <file-read> <file-write>\n";
return 1;
}
bio_in = BIO_new_file(argv[1], "r");
bio_out = BIO_new_file(argv[2], "w");
in_byte = BIO_read(bio_in, buffer, MAX_BUFFER_SIZE);
while (in_byte > 0)
{
std::cout << "Read " << in_byte << " bytes.\n";
out_byte = BIO_write(bio_out, buffer, in_byte);
std::cout << "Wrote " << out_byte << " bytes.\n";
if (in_byte != out_byte)
{
std::cout << "In bytes: " << in_byte << "and Out bytes: " << out_byte << " are not equal.\n";
BIO_free(bio_in);
BIO_free(bio_out);
return 1;
}
in_byte = BIO_read(bio_in, buffer, MAX_BUFFER_SIZE);
}
BIO_free(bio_in);
BIO_free_all(bio_out);
return 0;
}
I am not able to figure out what am I missing here.

Related

C/C++ library to decompress tar.gz file while downloading

I download a tar.gz file with libcurl, and need to decompress the file while downloading, that is, when chunk of the file is downloaded, decompress chunk of the file imediately, instead of decompressing the whole file when the whole file is downloaded. Is there any C/C++ libraries that meet my requirements
I tried to use libarchive to extract the file, but it returned truncated gzip input when extracting the first chunk of the file. It seems that libarchive need the whole file to extract it. Here is my code. I am not sure if i used libarchive correctly as I am new to it.
#include <iostream>
#include <vector>
#include <string>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <atomic>
#include <thread>
// libarchive
#include <archive.h>
#include <archive_entry.h>
#include <curl/curl.h>
struct mydata {
void *buffer;
ssize_t *size;
};
struct curldata {
void *buffer;
ssize_t *size;
CURL *curl;
};
std::atomic<bool> rd(true);
struct archive *archive, *archivefd;
std::atomic<bool> start_read(false);
la_ssize_t libarchiveRead(struct archive* a, void* client_data, const void** block)
{
if(!rd) {
mydata *my_data = (mydata*)client_data;
std::cout << "calling custom read(), size " << *(my_data->size) << std::endl;
*block = my_data->buffer;
rd=true;
return *(my_data->size);
}
return 0;
}
int libarchiveClose(struct archive* a, void* client_data)
{
std::cout << "calling custom close() for archive" << std::endl;
mydata *my_data = (mydata*)client_data;
delete my_data;
return (ARCHIVE_OK);
}
int libarchiveClosefd(struct archive* a, void* client_data)
{
std::cout << "calling custom close() for archivefd" << std::endl;
mydata *my_data = (mydata*)client_data;
delete my_data;
return (ARCHIVE_OK);
}
static size_t curlWriteFunction(void *ptr, size_t size, size_t nmemb, void *write_data) {
//size is always 1
curldata *my_data = (curldata*)(write_data);
*(my_data->size) = nmemb * size;
std::cout << "calling curlWriteFunction(), size: " << size << " , nmemb: " << nmemb
<< " , my_data->size: " << *(my_data->size) << std::endl;
memcpy(my_data->buffer, ptr, *(my_data->size));
curl_easy_pause(my_data->curl, CURL_WRITEFUNC_PAUSE);
rd=false;
return (*(my_data->size));
}
static size_t progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) {
CURL *curl = (CURL *)clientp;
(void)ultotal;
(void)ulnow;
if(dltotal == 0) {
return 0;
}
if(rd) {
curl_easy_pause(curl, CURLPAUSE_CONT);
std::cout << "progress: " << dlnow/dltotal * 100 << "%" << std::endl;
}
return 0;
}
void readarchive(void *client_data) {
struct archive_entry *entry;
int flags = ARCHIVE_EXTRACT_TIME;
flags |= ARCHIVE_EXTRACT_PERM;
flags |= ARCHIVE_EXTRACT_ACL;
flags |= ARCHIVE_EXTRACT_FFLAGS;
while(rd);
std::cout << "calling archive_read_open for archive.." << std::endl;
int res = archive_read_open(archive,
client_data,
nullptr,
(archive_read_callback*)libarchiveRead,
(archive_close_callback*)libarchiveClose);
std::cout << "called archive_read_open for archive.." << std::endl;
res = archive_read_next_header(archive, &(entry));
while(res == ARCHIVE_OK ) {
std::cout << "Extracting for archive " << archive_entry_pathname(entry) << "..." << std::endl;
// extract current entry
archive_read_extract(archive, entry, flags);
// read next if available
res = archive_read_next_header(archive, &(entry));
}
std::cout << "archive_read_next_header for archive failed, errcode: " << res << " error: " << archive_error_string(archive) << std::endl;
}
//size_t curlWriteFunction(void *ptr, size_t size, size_t nmemb,FILE* fptr) {
// //size is always 1
// std::cout << "calling curlWriteFunction().." << std::endl;
// return fwrite(ptr, size, nmemb, fptr);
//}
int main(int argc, char** argv) {
if(argc < 3)
{
std::cout << argv[0] << "{-r | -w} file[s]" << std::endl;
return 1;
}
std::vector<std::string> filenames;
filenames.reserve(argc);
while (*++argv != nullptr)
{
filenames.emplace_back(*argv);
}
bool modeRead = (filenames[0] == "-r");
std::cout << filenames[0] << " " << filenames[1] << std::endl;
// archive related variables
char buff_archive[16 * 1024], buff_archivefd[16 * 1024];
if(modeRead)
{
archive = archive_read_new();
archive_read_support_filter_gzip(archive);
archive_read_support_format_tar(archive);
mydata *client_data = new mydata();
int res;
char *buff1 = new char[16 * 1024];
client_data->size = new ssize_t;
*(client_data->size) = 0;
client_data->buffer = buff1;
curldata *curl_data = new curldata();
curl_data->size=client_data->size;
curl_data->buffer=buff1;
CURL *curl = curl_easy_init();
curl_data->curl = curl;
curl_easy_setopt(curl, CURLOPT_URL, filenames[1].c_str());
curl_easy_setopt(curl, CURLOPT_WRITEDATA, curl_data);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlWriteFunction);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, curl);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION,progress);
std::thread t(readarchive, client_data);
CURLcode result = curl_easy_perform(curl);
if(result != CURLE_OK) {
std::cout << "curl perform failed, errcode; " << result << " err: " << curl_easy_strerror(result) << std::endl;
}
//std::cout << "calling archive_read_open for archivefd.." << std::endl;
//res = archive_read_open(archivefd,
// client_datafd,
// nullptr,
// (archive_read_callback*)libarchiveReadfd,
// (archive_close_callback*)libarchiveClosefd);
//std::cout << "called archive_read_open for archivefd.." << std::endl;
//res = archive_read_next_header(archivefd, &(entry));
//if (res != ARCHIVE_OK) {
// std::cout << "archive_read_next_header for archivefd failed, errcode: " << res << " error: " << archive_error_string(archivefd) << std::endl;
//}
//while(res == ARCHIVE_OK) {
// std::cout << "Extracting for archivefd " << archive_entry_pathname(entry) << "..." << std::endl;
// // extract current entry
// archive_read_extract(archivefd, entry, flags);
// // read next if available
// res = archive_read_next_header(archivefd, &(entry));
//}
t.join();
delete client_data->size;
delete []buff1;
archive_read_close(archive);
archive_read_free(archive);
archive_read_free(archive);
curl_easy_cleanup(curl);
}
return 0;
}

CryptProtectData in one exe and CryptUnprotectData in different exe on same machine and same user credentials fails - Error code 998

When both CryptProtectData and CryptUnprotectData done in same exe like below code, it works.
When we run CryptProtectData first by commentting CryptUnprotectData and then again run CryptUnprotectData by commenting CryptProtectData , the decryption fails with error code -
ERROR_NOACCESS
998 (0x3E6)
Invalid access to memory location.
#pragma once
#include <atlstr.h>
#include <string>
#include <iostream>
#include <fstream>
#include <atlbase.h>
#include <atlcom.h>
#pragma comment(lib, "crypt32.lib")
int main()
{
std::string username = "abcxyzabc";
std::string fileName = "./ConfigInfoNew.dat";
//==================Encryption=========================
bool retvalue = true;
std::ofstream encryptedfile(filename, std::ios::out | std::ios::binary);
DATA_BLOB dataout;
char* ca = new char[username.size() + 1];
std::copy(username.begin(), username.end(), ca);
ca[username.size()] = '\0';
byte* pbdatainput = (byte*)ca;
dword cbdatainput = strlen((char*)pbdatainput) + 1;
DATA_BLOB datain;
datain.pbdata = pbdatainput;
datain.cbdata = cbdatainput;
//-------------------------------------------------------------------
// begin protect phase.
if (cryptprotectdata(&datain,
null, // a description string.
null, // optional entropy not used.
null, // reserved.
null, // pass a promptstruct.
CRYPTPROTECT_LOCAL_MACHINE,//unsigned int(0),
&dataout))
{
std::cout << (char*)(dataout.pbdata) << std::endl;
encryptedfile.write((char*)&dataout.cbdata, sizeof(dword));
encryptedfile.write((char*)&dataout.pbdata, sizeof(dataout.pbdata));
dword errcode = getlasterror();
std::cout << " encrypt success code ---" + std::to_string(errcode) + "---" << std::endl;
}
else
{
dword errcode = getlasterror();
std::cout << " encrypt failed code ---" + std::to_string(errcode) + "---" << std::endl;
}
encryptedfile.close();
//===============Decryption====================
std::ifstream decryptFile(fileName, std::ios::in);
if (decryptFile.is_open())
{
{
DATA_BLOB pEncryptedData;
decryptFile.read((char*)&pEncryptedData.cbData, sizeof(DWORD));
pEncryptedData.pbData = new BYTE[pEncryptedData.cbData];
decryptFile.read((char*)&pEncryptedData.pbData, sizeof(pEncryptedData.pbData));
DATA_BLOB DataVerify;
if (CryptUnprotectData(
&pEncryptedData,
NULL,
NULL, // Optional entropy
NULL, // Reserved
NULL, // Optional PromptStruct
CRYPTPROTECT_LOCAL_MACHINE, //unsigned int(0),
&DataVerify))
{
std::cout << (char*)(DataVerify.pbData) << std::endl;
DWORD errCode = GetLastError();
std::cout << " Decrypt Success code ---" + std::to_string(errCode) + "---" << std::endl;
}
else
{
LocalFree(pEncryptedData.pbData);
LocalFree(DataVerify.pbData);
DWORD errCode = GetLastError();
std::cout << " Decrypt failed code ---" + std::to_string(errCode) + "---" << std::endl;
return false;
}
LocalFree(pEncryptedData.pbData);
LocalFree(DataVerify.pbData);
}
}
decryptFile.close();
return 0;
}
You are writing the pointer to the encrypted data into your file, instead of writing the actual encrypted data. So it makes sense why decryption works when performed in the same process as the encryption, but not in a separate process.
You need to change this:
encryptedfile.write((char*)&dataout.pbdata, sizeof(dataout.pbdata));
...
decryptFile.read((char*)&pEncryptedData.pbData, sizeof(pEncryptedData.pbData));
To this instead:
encryptedfile.write((char*)dataout.pbdata, dataout.cbdata);
...
decryptFile.read((char*)pEncryptedData.pbData, pEncryptedData.cbData);
That being said, your code can be simplified a little bit:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#pragma comment(lib, "crypt32.lib")
int main()
{
std::string username = "abcxyzabc";
std::string fileName = "./ConfigInfoNew.dat";
//==================Encryption=========================
std::ofstream encryptedfile(filename, std::ios::binary);
if (encryptedfile.is_open())
{
DATA_BLOB datain, dataout;
datain.pbdata = reinterpret_cast<BYTE*>(username.data()); // or: reinterpret_cast<BYTE*>(const_cast<char*>(username.c_str()))
datain.cbdata = username.size() + 1;
if (!CryptProtectData(&datain,
nullptr, // a description string.
nullptr, // optional entropy not used.
nullptr, // reserved.
nullptr, // pass a promptstruct.
CRYPTPROTECT_LOCAL_MACHINE,
&dataout))
{
DWORD errcode = GetLastError();
std::cout << " encrypt failed code ---" + std::to_string(errcode) + "---" << std::endl;
return 1;
}
std::cout.write(reinterpret_cast<char*>(dataout.pbdata), dataout.cbdata);
std::cout << std::endl;
if (!(encryptedfile.write(reinterpret_cast<char*>(&dataout.cbdata), sizeof(dataout.cbdata)) &&
encryptedfile.write(reinterpret_cast<char*>(dataout.pbdata), dataout.cbdata)))
{
std::cout << " failed to write to encrypted file" << std::endl;
return 1;
}
encryptedfile.close();
std::cout << " encrypt success" << std::endl;
}
else
{
std::cout << " failed to create encrypted file" << std::endl;
return 1;
}
//===============Decryption====================
std::ifstream decryptFile(fileName, std::ios::binary);
if (decryptFile.is_open())
{
DATA_BLOB EncryptedData, DataVerify;
if (!decryptFile.read(reinterpret_cast<char*>(&EncryptedData.cbData), sizeof(EncryptedData.cbData)))
{
std::cout << " failed to read from encrypted file" << std::endl;
return 1;
}
std::vector<BYTE> buffer(EncryptedData.cbData);
EncryptedData.pbData = buffer.data();
if (!decryptFile.read(reinterpret_cast<char*>(EncryptedData.pbData), EncryptedData.cbData))
{
std::cout << " failed to read from encrypted file" << std::endl;
return 1;
}
if (!CryptUnprotectData(
&EncryptedData,
nullptr,
nullptr, // Optional entropy
nullptr, // Reserved
nullptr, // Optional PromptStruct
CRYPTPROTECT_LOCAL_MACHINE,
&DataVerify))
{
DWORD errCode = GetLastError();
std::cout << " Decrypt failed code ---" + std::to_string(errCode) + "---" << std::endl;
return 1;
}
std::cout.write(reinterpret_cast<char*>(DataVerify.pbData), DataVerify.cbData);
std::cout << std::endl;
std::cout << " decrypt success" << std::endl;
LocalFree(DataVerify.pbData);
decryptFile.close();
}
else
{
std::cout << " failed to open encrypted file" << std::endl;
return 1;
}
return 0;
}

Why does the search code work on its own but not when added to rest of code?

I'm working on a C++ project that requires a client to send a file path and search string to a server. The server then searches through the provided file for the search string and prints the whole line for each instance it finds the search string. Searching in its own program works fine, however, when I add it to the rest of my code it does not work.
Search on its own is as follows:
#include <iostream>
#include <fstream>
#include <string>
int main(int argc, char *argv[]) {
std::ifstream inFile;
std::string path = argv[1];//"dat/anna_karenina.txt";
inFile.open(path);
std::string searchStr = argv[2];//"you m";
std::string line = "";
int bytesSent = 0;
if(inFile.is_open()) {
while(std::getline(inFile, line)) {
if(line.find(searchStr, 0)!=std::string::npos) {
char sending[line.length()];
for(int i=0; i<line.length(); i++) {
sending[i]=line.at(i);
}
std::cout << line << std::endl;
bytesSent += line.length();
}
}
}
std::cout << "BYTES SENT: " << bytesSent << std::endl;
inFile.close();
return 1;
}
When I run this all lines are printed how they should be.
This is my server code:
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <sys/sysinfo.h>
int main(int argc, char *argv[]) {
if(argc != 2) {
std::cout << "Need domain socket file name" << std::endl;
exit(-1);
}
struct sockaddr_un server;
char buffer[32];
unlink(argv[1]);
int serverSock = socket(AF_UNIX, SOCK_STREAM, 0);
if(serverSock < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
std::cout << "SERVER CONNECTED" << std::endl;
size_t maxClients = get_nprocs_conf()-1;
memset(&server, 0, sizeof(server));
server.sun_family = AF_UNIX;
strncpy(server.sun_path, argv[1], sizeof(server.sun_path)-1);
int success = bind(serverSock, (const struct sockaddr *) &server,
sizeof(struct sockaddr_un));
if(success < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
success = listen(serverSock, maxClients);
if(success < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
while(true) {
std::cout << "Waiting for clients" << std::endl;
int clientSock = accept(serverSock, nullptr, nullptr);
if(clientSock < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
std::cout << "CLIENT CONNECTED" << std::endl;
std::string path="";
std::string searchStr="";
char fileBuff[32];
char searchBuff[32];
memset(fileBuff, 0, 32);
success = read(clientSock, fileBuff, 32);
if(success < 0) {
perror("read");
exit(EXIT_FAILURE);
}
for(int i=0; i<(sizeof(fileBuff)/sizeof(char)); i++) {
path+=fileBuff[i];
}
std::cout << path << std::endl;
if(path.empty()) {
std::cout << "No path to file given" << std::endl;
exit(1);
}
memset(searchBuff, 0, 32);
success = read(clientSock, searchBuff, 32);
if(success < 0) {
perror("read");
exit(EXIT_FAILURE);
}
for(int j=0; j<(sizeof(searchBuff)/sizeof(char)); j++) {
searchStr+=searchBuff[j];
}
std::cout << searchStr << std::endl;
if(searchStr.empty()) {
std::cout << "No search string given" << std::endl;
exit(1);
}
std::ifstream inFile;
inFile.open(path);
std::string line = "";
int bytesSent = 0;
if(inFile.is_open()) {
//std::cout << "ok" << std::endl;
std::cout << searchStr << std::endl;
while(std::getline(inFile, line)) {
// std::cout << "ok" << std::endl;
if(line.find(searchStr, 0)!=std::string::npos) {
/std::cout << "ok" << std::endl;
char sending[line.length()];
//memset(sending, 0, sizeof(sending)/sizeof(char));
for(int k=0; k<(sizeof(sending)/sizeof(char)); k++) {
/std::cout << "ok" << std::endl;
sending[k]=line.at(k);
}
std::cout << line << std::endl;
bytesSent += line.length();
}
}
}
std::cout << "BYTES SENT: " << bytesSent << std::endl;
inFile.close();
close(clientSock);
}
return 1;
}
When I run the server and client code, the client does as it should, and so does the server, until if(line.find(searchStr, 0)!=std::string::npos) { at which it acts as if the search string is not found anywhere on any line and prints no lines and says the bytes sent is 0. I don't understand why the server cannot search for the string but the search method on its own can. I fairly sure the search string is correct; when I print it out it is what it needs to be. I'm just confused as to what I'm doing wrong in the server code for it to not enter the if statement.
If you're confused as to what bytes sent is, the server is supposed to send all the lines found to the client for it to print and count how many bytes it's sending. I don't need the server to print the lines. I am just doing it now so I can see that the lines are actually being found.

Change named pipe buffer size in macOS

Is there any way to control the buffer size of a named pipe created through mkfifo?
I’m using macOS 10.13.2 and the buffer size seems fixed at 8192 bytes. I was able to get to that number with this snippet of code:
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <thread>
#define BUFFER_SIZE 1024*1024
#define FIFO_PATH "/Users/joao/Desktop/fifo"
void readFifo() {
auto fd = open(FIFO_PATH, O_RDONLY);
if (fd < 0) {
std::cerr << "Failed to open fifo for reading" << std::endl;
return;
}
std::cout << "Ready to read!" << std::endl;
char buffer[BUFFER_SIZE];
auto total_bytes_read = 0;
while (total_bytes_read < BUFFER_SIZE) {
auto bytes_read = read(fd, buffer, BUFFER_SIZE);
std::cout << "Read " << bytes_read << " bytes" << std::endl;
total_bytes_read += bytes_read;
}
close(fd);
}
int main(int argc, const char * argv[]) {
unlink(FIFO_PATH);
if (mkfifo(FIFO_PATH, 0666) != 0) {
std::cerr << "Failed to create fifo" << std::endl;
return 1;
}
std::thread reader(readFifo);
auto fd = open(FIFO_PATH, O_WRONLY);
if (fd < 0) {
std::cerr << "Failed to open fifo for writing" << std::endl;
return 1;
}
char buffer[BUFFER_SIZE];
for (int i = 0; i < BUFFER_SIZE; i++) {
buffer[i] = 'a';
}
auto bytes_written = write(fd, buffer, BUFFER_SIZE);
reader.join();
std::cout << "Wrote " << bytes_written << " bytes" << std::endl;
unlink(FIFO_PATH);
return 0;
}

Server - Client RSA keypair exchange

I'm new to programming and i've got this little project going for my diploma and i need help on this little code. This is a Server->Client C++ code where server generates and sends RSA Keypair to client. My problem is that both server and client codes compiled without any problem but when i start it the client side doesn't get any keypair just blank.
Here is my server code:
#include <iostream>
#include <cstdlib>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <stdio.h>
#include <string.h>
#define KEY_LENGTH 1024
#define PUB_EXP 3
#define PRINT_KEYS
#define WRITE_TO_FILE
using std::exit;
#define int_error(msg) handle_error(__FILE__, __LINE__, msg)
void handle_error(const char* file, int lineno, const char* msg)
{
std::cerr << "\n** " << file << ":" << lineno << " " << msg << "\n";
ERR_print_errors_fp(stderr);
exit(-1);
}
void init_OpenSSL()
{
std::cout << "Initializng OpenSSL library ... ";
if (!SSL_library_init())
int_error("OpenSSL initialization failed");
std::cout << "done\n";
SSL_load_error_strings();
}
DH* setup_dh()
{
DH* dh = DH_new();
if (!dh)
int_error("DH_new failed");
std::cout << "Generating DH parameters ... ";
if (!DH_generate_parameters_ex(dh, 2, DH_GENERATOR_2, 0))
int_error("DH_generate_parameters_ex failed");
std::cout << "done\n";
std::cout << "Checking DH parameters ... ";
int codes = 0;
if (!DH_check(dh, &codes))
int_error("DH_check failed");
std::cout << "done\n";
std::cout << "Generating DH keys ... ";
if (!DH_generate_key(dh))
int_error("DH_generate_key failed");
std::cout << "done\n";
return dh;
}
SSL_CTX* setup_ctx()
{
SSL_CTX* ctx;
std::cout << "Creating context ... ";
ctx = SSL_CTX_new(TLSv1_server_method());
if (!ctx)
int_error("SSL_CTX_new failed");
std::cout << "done\n";
DH* dh = setup_dh();
std::cout << "Setting DH parameters ... ";
SSL_CTX_set_tmp_dh(ctx, dh);
std::cout << "done\n";
std::cout << "Setting cipher list ... ";
if (SSL_CTX_set_cipher_list(ctx, "ADH-AES256-SHA") != 1)
int_error("Error setting cipher list (no valid ciphers)");
std::cout << "done\n";
return ctx;
}
int main()
{
init_OpenSSL();
BIO *acc, *client;
SSL* ssl;
SSL_CTX* ctx;
ctx = setup_ctx();
size_t pri_len;
size_t pub_len;
char *pri_key;
char *pub_key;
std::cout << "Generating RSA (%d bits) keypair...\n", 1024;
RSA *keypair = RSA_generate_key(1024, 3, NULL, NULL);
BIO *pri = BIO_new(BIO_s_mem());
BIO *pub = BIO_new(BIO_s_mem());
PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
PEM_write_bio_RSAPublicKey(pub, keypair);
pri_len = BIO_pending(pri);
pub_len = BIO_pending(pub);
pri_key = (char*)malloc(pri_len + 1);
pub_key = (char*)malloc(pub_len + 1);
BIO_read(pri, pri_key, pri_len);
BIO_read(pub, pub_key, pub_len);
pri_key[pri_len] = '\0';
pub_key[pub_len] = '\0';
std::cout << "Creating server socket ... ";
acc = BIO_new_accept("*:5055");
if (!acc)
int_error("Error creating server socket");
std::cout << "done\n";
std::cout << "Binding server socket ... ";
if (BIO_do_accept(acc) <= 0)
int_error("Error binding server socket");
std::cout << "done\n";
while (true) {
std::cout << "Accepting connections ...\n";
if (BIO_do_accept(acc) <= 0)
int_error("Error accepting connection");
client = BIO_pop(acc);
std::cout << "Creating context ... ";
if (!(ssl = SSL_new(ctx)))
int_error("Error creating SSL context");
std::cout << "done\n";
SSL_set_bio(ssl, client, client);
if (SSL_accept(ssl) <= 0)
int_error("Error accepting SSL connection");
std::cout << "SSL connection opened: " << SSL_get_cipher(ssl) << " " <<
SSL_get_cipher_version(ssl) << " (" << SSL_get_cipher_bits(ssl, 0) << " bits)\n";
char buff[256] = {0};
int r = SSL_read(ssl, buff, sizeof buff);
if (r > 0) {
std::cout << buff;
SSL_write(ssl, keypair, 1024 );
}
SSL_shutdown(ssl);
SSL_free(ssl);
std::cout << "SSL connection finished\n";
}
SSL_CTX_free(ctx);
BIO_free(acc);
std::cout << "Server closed\n";
}
Here is my client code:
#include <iostream>
#include <cstdlib>
#include <string>
#include <fstream>
#include <openssl/ssl.h>
#include <openssl/err.h>
using namespace std;
using std::exit;
#define int_error(msg) handle_error(__FILE__, __LINE__, msg)
void handle_error(const char* file, int lineno, const char* msg)
{
std::cerr << "** " << file << ":" << lineno << " " << msg << "\n";
ERR_print_errors_fp(stderr);
exit(-1);
}
void init_OpenSSL()
{
std::cout << "Initializng OpenSSL library ... ";
if (!SSL_library_init())
int_error("OpenSSL initialization failed");
std::cout << "done\n";
SSL_load_error_strings();
}
SSL_CTX* setup_ctx()
{
SSL_CTX* ctx;
std::cout << "Creating context ... ";
ctx = SSL_CTX_new(TLSv1_client_method());
if (!ctx)
int_error("SSL_CTX_new failed");
std::cout << "done\n";
std::cout << "Setting cipher list ... ";
if (SSL_CTX_set_cipher_list(ctx, "ADH-AES256-SHA") != 1)
int_error("Error setting cipher list (no valid ciphers)");
std::cout << "done\n";
return ctx;
}
int main()
{
init_OpenSSL();
BIO* conn;
SSL* ssl;
SSL_CTX* ctx;
ofstream myfile;
ctx = setup_ctx();
std::cout << "Creating connection ... ";
conn = BIO_new_connect("192.168.1.10:5055");
if (!conn)
int_error("Error creating connection");
std::cout << "done\n";
std::cout << "Connecting to server ... ";
if (BIO_do_connect(conn) <= 0)
int_error("Error connecting to server");
std::cout << "done\n";
std::cout << "Creating context ... ";
if (!(ssl = SSL_new(ctx)))
int_error("Error creating an SSL context");
std::cout << "done\n";
SSL_set_bio(ssl, conn, conn);
std::cout << "Opening connection ... ";
if (SSL_connect(ssl) <= 0)
int_error("Error connecting SSL object");
std::cout << "done\n";
SSL_write(ssl, "The client is connected", 26);
char buff[64] = {0};
int bread = SSL_read(ssl, buff, sizeof buff);
if (bread > 0)
std::cout << "The key has been recieved\n";
myfile.open ("keypair.pem");
myfile << buff;
myfile.close();
SSL_shutdown(ssl);
SSL_free(ssl);
std::cout << "SSL connection finished\n";
SSL_CTX_free(ctx);
std::cout << "Client finished\n";
}
Can someone show me what i did wrong and it would be great if someone can tell me how i can get my private key and public keys(server generated) separately. Thanks a lot guys...really appreciate it