#include <cryptopp/cryptlib.h>
#include <assert.h>
#include <cryptopp/queue.h>
#include <cryptopp/secblockfwd.h>
#include <iostream>
#include <fstream>
#include <cryptopp/integer.h>
#include <cryptopp/rsa.h>
#include <cryptopp/osrng.h>
#include <cryptopp/files.h>
#include <cryptopp/secblock.h>
#include <sstream>
void SaveKey(const std::string filename, const CryptoPP::RSA::PublicKey& key);
void SaveKey(const std::string filename, const CryptoPP::RSA::PrivateKey& key);
void Save(const std::string filename, const CryptoPP::BufferedTransformation& bt);
std::string Convert(CryptoPP::SecByteBlock block);
std::string decrypt(CryptoPP::SecByteBlock ciphertext, CryptoPP::RSA::PrivateKey priv_key);
CryptoPP::RSA::PrivateKey createPrivateKey(int size);
CryptoPP::SecByteBlock Encrypt(CryptoPP::RSA::PublicKey pub_key, const std::string file);
std::string read(std::string filename);
int main(int argc, char* argv[]){
std::string file = read(argv[1]);
std::cout << file << "\n";
//creates a public and private key
CryptoPP::AutoSeededRandomPool prng;
CryptoPP::RSA::PrivateKey priv_key;
priv_key.GenerateRandomWithKeySize(prng, 3072);
CryptoPP::RSA::PublicKey pub_key(priv_key);
SaveKey("priv", priv_key);
SaveKey("pub", pub_key);
//Encrypts the file using the public key
CryptoPP::SecByteBlock ciphertext = Encrypt(pub_key, file);
//Converts the encrypted data to string format and saves it in a file
std::string encryptStr = Convert(ciphertext);
std::ofstream encFile("encrypt.txt");
encFile << encryptStr;
std::cout << "Decrypted text "<< decrypt(ciphertext, priv_key) << "\n";
return 0;
}
std::string decrypt(CryptoPP::SecByteBlock ciphertext, CryptoPP::RSA::PrivateKey priv_key){
CryptoPP::AutoSeededRandomPool rnd;
CryptoPP::RSAES_OAEP_SHA_Decryptor decryptor(priv_key);
//checks
assert(0 != decryptor.FixedMaxPlaintextLength());
assert(ciphertext.size() <= decryptor.FixedCiphertextLength());
// Create recovered text space
size_t dpl = decryptor.MaxPlaintextLength( ciphertext.size() );
assert( 0 != dpl );
CryptoPP::SecByteBlock recovered( dpl );
// Decoding text
CryptoPP::DecodingResult result = decryptor.Decrypt( rnd,
ciphertext, ciphertext.size(), recovered );
// More sanity checks
assert( result.isValidCoding );
assert( result.messageLength <= decryptor.MaxPlaintextLength( ciphertext.size() ) );
//Resised the buffer to the correct length and converts it to string format
recovered.resize(result.messageLength);
std::string message = Convert(recovered);
return message;
}
void Save(const std::string filename, const CryptoPP::BufferedTransformation& bt){
CryptoPP::FileSink file(filename.c_str());
bt.CopyTo(file);
file.MessageEnd();
}
void SaveKey(const std::string filename, const CryptoPP::RSA::PublicKey& key){
CryptoPP::ByteQueue queue;
key.Save(queue);
Save(filename, queue);
}
void SaveKey(const std::string filename, const CryptoPP::RSA::PrivateKey& key){
CryptoPP::ByteQueue queue;
key.Save(queue);
Save(filename, queue);
}
CryptoPP::SecByteBlock Encrypt(CryptoPP::RSA::PublicKey pub_key, const std::string file){
CryptoPP::AutoSeededRandomPool rnd;
CryptoPP::RSAES_OAEP_SHA_Encryptor encryptor(pub_key);
CryptoPP::SecByteBlock plaintext(reinterpret_cast<const CryptoPP::byte*>(&file[-1]), file.size());
size_t ecl = encryptor.CiphertextLength(plaintext.size());
assert(ecl != -1);
CryptoPP::SecByteBlock ciphertext(ecl);
encryptor.Encrypt(rnd, plaintext, plaintext.size(), ciphertext);
return ciphertext;
}
std::string Convert(CryptoPP::SecByteBlock block){
std::string str;
str.resize(block.size());
memcpy(&str[0], &block[0], str.size());
return str;
}
std::string read(std::string filename){
std::ifstream file;
file.open(filename);
assert(file.is_open());
std::ostringstream sstr;
sstr << file.rdbuf();
return sstr.str();
}
This code starts by reading in an external file passed in through arg[0]. Them it creates an saves an RSA public and private key using crypto++. Then it encrypts the file using the public key and saves it to a file. Then it decrypts it and prints the result. Is there a way that I can make it more secure, more readable and more efficient.
-
\$\begingroup\$ My standard comment on encryption. Don't roll your own (if you are doing this for practical use). Assuming this is for learning purposes, fine. \$\endgroup\$Loki Astari– Loki Astari2022年01月04日 19:09:50 +00:00Commented Jan 4, 2022 at 19:09
1 Answer 1
The main thing I don't like is the need to load the whole file into memory before you start encryption. This will only work for relatively small files.
I would expect the interface to be more like:
std::ifstream file(file);
std::ofstream encryptedFile(file + ".encryp");
EnctptedStream encryptedStream(encryptedFile, publicKey);
encryptedStream << file.rdbuf();
So:
// Make the encryption be a normal stream like object.
// Then you can send data to the encryption stream just like
// you send data to a normal stream (so it can be used anywhere
// you would normally use a stream the using code does not need
// to know that this is a special stream).
//
// I would also make it a wrapper of a stream so we can send the
// data to any other normla stream be that a file or a memory
// buffer.
class EnctptedStream: public std::ostream
{
public:
EnctptedStream(std::ostream& stream, Key key);
};