How to separate botan encryption and decryption operation via command line argument? - c++

i try to explore c++ cryptography using botan. From the provided example,the method of encrypt and decrypt a plaint text is shown below
include <botan/rng.h>
#include <botan/auto_rng.h>
#include <botan/cipher_mode.h>
#include <botan/hex.h>
#include <iostream>
int main()
{
Botan::AutoSeeded_RNG rng;
const std::string plaintext("Pa$$5523224lkj");
const std::vector<uint8_t> key = Botan::hex_decode("2B7E151628AED2A6ABF7158809CF4F3C");
const std::vector<uint8_t> decryptkey = Botan::hex_decode("2B7E151628AED2A6ABF7158809CF4F3C");
std::unique_ptr<Botan::Cipher_Mode> enc = Botan::Cipher_Mode::create("AES-128/CBC/PKCS7", Botan::ENCRYPTION);
std::unique_ptr<Botan::Cipher_Mode> dec = Botan::Cipher_Mode::create("AES-128/CBC/PKCS7", Botan::DECRYPTION);
enc->set_key(key);
//generate fresh nonce (IV)
Botan::secure_vector<uint8_t> iv = rng.random_vec(enc->default_nonce_length());
// Copy input data to a buffer that will be encrypted
Botan::secure_vector<uint8_t> pt(plaintext.data(), plaintext.data()+plaintext.length());
enc->start(iv);
enc->finish(pt);
std::cout << "enc->name() "<< enc->name()<<std::endl;
std::cout << "Botan::hex_encode(iv) "<< Botan::hex_encode(iv) <<std::endl;
std::cout << "Botan::hex_encode(pt) "<< Botan::hex_encode(pt) <<std::endl;
dec->set_key(decryptkey);
dec->start(iv);
dec->finish(pt);
std::cout <<pt.data()<<std::endl; // we will printout Pa$$5523224lkj
return 0;
}
I am curious is it possible to create command line argument to separate the operation?
The idea we store the encrypted text into a textfile, than we run the program using decryption argument and we read from the encrypted text to decrypt it into plaintext.
#include <botan/rng.h>
#include <botan/auto_rng.h>
#include <botan/cipher_mode.h>
#include <botan/hex.h>
#include <fstream>
#include <iostream>
int main(int argc, char** argv)
{
std::unique_ptr<Botan::Cipher_Mode> enc = Botan::Cipher_Mode::create("AES-128/CBC/PKCS7", Botan::ENCRYPTION);
std::unique_ptr<Botan::Cipher_Mode> dec = Botan::Cipher_Mode::create("AES-128/CBC/PKCS7", Botan::DECRYPTION);
const std::string plaintext("(5523224LOMAKDKWJDG#$%)");
const std::string encText ="A9B7DC28Cdgjlpuy";
Botan::secure_vector<uint8_t> myText(encText.data(), encText.data()+encText.length());
Botan::secure_vector<uint8_t> iv = myText;
Botan::secure_vector<uint8_t> pt (plaintext.data(), plaintext.data()+plaintext.length());
std::string encordedText;
const std::vector<uint8_t> key = Botan::hex_decode("2B7E151628AED2A6ABF7158809CF4F3C");
if(argv[1][1] == 'e')
{
std::ofstream myfile;
myfile.open("encoded.txt");
enc->set_key(key);
enc->start(iv);
enc->finish(pt);
std::cout <<"enc->name()"<< enc->name() << " with iv " <<std::endl;
std::cout<<"Botan::hex_encode(iv)"<<Botan::hex_encode(iv) <<std::endl;
std::cout<<"Botan::hex_encode(pt)"<<Botan::hex_encode(pt) << std::endl;
myfile <<Botan::hex_encode(pt);
myfile.close();
}
else if (argv[1][1] == 'd')
{
std::ifstream readfile;
readfile.open("encoded.txt");
readfile>>encordedText;
std::cout<<encordedText<<std::endl;
Botan::secure_vector<uint8_t> tmpPlainText(encordedText.data(), encordedText.data()+encordedText.length());
dec->set_key(key);
dec->start(iv);
dec->finish(tmpPlainText);
std::cout<<tmpPlainText.data()<<std::endl;
readfile.close();
}
return 0;
}
The program has no issue with encryption(e argument) side but when i try to run this program with decryption side(d argument) i have encountered the following error:
terminate called after throwing an instance of 'Botan::Decoding_Error'
what(): Invalid CBC padding
Aborted (core dumped)
Let me knw if i do anything wrong, happy to learn from you all.

The problem is that you are trying to decrypt the hex-encoding of the encrypted plaintext.
You encrypt the plaintext and write the hex-encoding of the encryption to the file. For decryption, you read the hex-encoding into encordedText, and then you construct a Botan::secure_vector tmpPlainText from the data contained in encodedText. The hex-encoding is not undone in this step, so tmpPlainText still holds the hex-encoding. The cipher then rejects this data, because it does not have the expected format.
To fix this problem, you have to undo the hex-encoding. Replace the line where you construct the Botan::secure_vector with:
Botan::secure_vector<uint8_t> tmpPlainText(Botan::hex_decode_locked(encordedText));

Related

Unable to compile example code from AWS SDK for C++ - Developer Guide

I am trying to upload a file using an encrypted client and i`m having a hard time setting the body of the PutObjectRequest object. I am using the sample code.
PutObjectRequest putObjectRequest;
putObjectRequest.WithBucket("BUCKET_NAME")
.WithKey(AES_MASTER_KEY);
std::shared_ptr<Aws::IOStream> input_data =
Aws::MakeShared<Aws::FStream>("SampleAllocationTag",
FILE_NAME,
std::ios_base::in | std::ios_base::binary);
putObjectRequest.SetBody(input_data);
but I am getting the following error:
no suitable user-defined conversion from "std::shared_ptrAws::FStream" to "std::shared_ptrAws::IOStream" exists
The original code can be found at https://docs.aws.amazon.com/sdk-for-cpp/v1/developer-guide/aws-sdk-cpp-dg.pdf , page 180
This is the full function:
#include <aws/core/Aws.h>
#include <aws/core/utils/logging/LogLevel.h>
#include <aws/s3/S3Client.h>
#include <aws/s3-encryption/materials/SimpleEncryptionMaterials.h>
#include <aws/core/auth/AWSCredentialsProviderChain.h>
#include <aws/s3-encryption/S3EncryptionClient.h>
#include <aws/s3-encryption/CryptoConfiguration.h>
#include <aws/core/utils/HashingUtils.h>
#include <aws/s3/model/PutObjectRequest.h>
#include <aws/core/utils/memory/stl/AWSStreamFwd.h>
#include <iostream>
using namespace Aws;
using namespace Aws::S3::Model;
bool PutObject(const Aws::String& bucketName,
const Aws::String& objectName)
{
// Verify that the file exists.
struct stat buffer;
if (stat(objectName.c_str(), &buffer) == -1)
{
std::cout << "Error: PutObject: File '" <<
objectName << "' does not exist." << std::endl;
return false;
}
Aws::Client::ClientConfiguration config;
Aws::S3::S3Client s3_client(config);
Aws::S3::Model::PutObjectRequest request;
request.SetBucket(bucketName);
//We are using the name of the file as the key for the object in the bucket.
//However, this is just a string and can set according to your retrieval needs.
request.SetKey(objectName);
std::shared_ptr<Aws::IOStream> input_data =
Aws::MakeShared<Aws::FStream>("SampleAllocationTag",
objectName.c_str(),
std::ios_base::in | std::ios_base::binary);
request.SetBody(input_data);
Aws::S3::Model::PutObjectOutcome outcome =
s3_client.PutObject(request);
if (outcome.IsSuccess()) {
std::cout << "Added object '" << objectName << "' to bucket '"
<< bucketName << "'.";
return true;
}
else
{
std::cout << "Error: PutObject: " <<
outcome.GetError().GetMessage() << std::endl;
return false;
}
}
That is the only error I get
Image showing build error
As the code is missing #include <fstream> Aws::FStream (which is a typedef for std::fstream) is an incomplete type and the compiler doesn't know that std::fstream is derived from std::iostream so doesn't know how to convert from std::shared_ptr<Aws::FStream> to std::shared_ptr<Aws::IOStream>.
Visual studio isn't very helpful here, clang and GCC at least tell you that std::fstream is an incomplete type: https://godbolt.org/z/Paeqj5saW

Crypto++ : Hash generation hangs on windows 10

I have the following simple program :
#include <cryptlib.h>
#include "sha.h"
#include <sha3.h>
#include <filters.h>
#include <hex.h>
#include <beast/core/detail/base64.hpp>
using namespace CryptoPP;
using namespace boost::beast::detail::base64;
int main(int argc, char** argv) {
if (argc < 2) {
std::cout << "missing argument 1 : password";
return 0;
}
std::string password = std::string(argv[1]);
byte digest[SHA3_256::DIGESTSIZE];
SHA3 digestAlgo = SHA3_256();
std::cout << "going to calculate the digest\n";
digestAlgo.Update((const byte*) password.data(), password.size());
std::cout << "updated...\n";
digestAlgo.Final(digest);
std::cout << "calculated the digest\n";
char* b64encodedHash = (char*)malloc(sizeof(byte)*1000);
encode(b64encodedHash, digest, sizeof(byte)*1000);
std::cout << "password hashed : " << b64encodedHash << "\n";
return 1;
}
When I run it the text : "going to calculate the digest" is output on the command line and the program does not continue. It hangs.
Does anyone know why ? I am trying to follow the examples on the Crypto++ wiki, and this is very similar to theirs.
After the Final call I want to base64 encode the digest, you can remove that part, it uses a boost header file.
Thanks,
Regards
Change the line
SHA3 digestAlgo = SHA3_256();
to
SHA3_256 digestAlgo;

fstream does not work well with Pin

I've written a very simple Pin tool that only contains one instrumention function, that is, instruction below. It has no analysis function/callback. Its purpose is to only store the address of instructions that may be executed.
#include <cstdint>
#include <iostream>
#include <fstream>
#include <list>
#include "pin.H"
std::ofstream of1;
std::list<uint64_t> instrList;
uint64_t instrCount = 0;
VOID instruction(INS ins, VOID* v)
{
ADDRINT ip = INS_Address(ins);
of1 << ip << std::endl;
of1.flush();
instrList.push_back(ip);
++instrCount;
}
VOID finishFunc(INT32 code, VOID *v)
{
of1.close();
std::ofstream of2;
of2.open("out2.txt", std::ofstream::out);
of2 << std::hex;
for (std::list<uint64_t>::iterator i = instrList.begin(); i != instrList.end(); ++i)
of2 << *i << std::endl;
of2.close();
std::cerr << "Instruction count: " << instrCount << std::endl;
}
int main(int argc, char* argv[])
{
PIN_Init(argc, argv);
of1.open("out1.txt", std::ofstream::out);
of1 << std::hex;
INS_AddInstrumentFunction(instruction, 0);
PIN_AddFiniFunction(finishFunc, 0);
PIN_StartProgram();
return 0;
}
The contents of the files out1.txt and out2.txt should be the same.
I attached this Pin tool to some programs such as /bin/ls. For them, out1.txt and out2.txt are the same. But when I attach it to gcc compiling a code, out1.txt would have more lines than out2.txt. out2.txt has a number of lines that is equal to instrCount, which seems reasonable. It seems that there's a problem with the fstream corresponding to out1.txt. out1.txt has a number of duplicate lines as compared to out2.txt.
These snippets show where they start to differ (marked with <):
out1.txt:
7f87ceb050a2
7f87ceb050a4
7f87ceb050a5
7f87ceb050a8
7f87ceb050aa
7f87ceb050b2
7f87ceb050b7
7f87ceb050b9
<7f87ceb050a4
<7f87ceb050a5
<7f87ceb050a8
<7f87ceb050aa
<7f87ceb050b2
<7f87ceb050b7
<7f87ceb050b9
<7f87ceb050b2
45218c
<7f87ceb050b7
45218e
<7f87ceb050b9
452190
out2.txt:
7f87ceb050a2
7f87ceb050a4
7f87ceb050a5
7f87ceb050a8
7f87ceb050aa
7f87ceb050b2
7f87ceb050b7
7f87ceb050b9
45218c
45218e
452190
I used a PIN_LOCK inside instruction function, but that doesn't change anything. I also tried to write into output files using fprintf, but the problem still exists.
Any idea how to solve this issue?

Exception 'key is too short to encrypt any messages' when trying to use RSA encryption

I'm trying to build a small encryption C++ library for Android with Crypto++.
I've built the library and I'm testing parts of it on Linux (x64) to see if everything's alright. Note that I almost have no experience with C++ coding and I'm mostly copying the Crypto++ wiki.
I'm having an issue with my RSA encryption function. I load a public key from two CryptoPP::Integers and then try to encrypt a message. I always get this exception from the try/catch statement:
RSA/OAEP-MGF1(SHA-1): this key is too short to encrypt any messages
I've looked at Crypto++'s code and this seems to come from this exact part (code here):
if (plaintextLength > FixedMaxPlaintextLength())
{
if (FixedMaxPlaintextLength() < 1)
throw InvalidArgument(AlgorithmName() + ": this key is too short to encrypt any messages");
...
}
Conversely, the Crypto++ wiki says about FixedMaxPlaintextLength:
The maximum length of a plaintext string that can be encrypted with RSA can be determined by FixedMaxPlaintextLength. On error, FixedMaxPlaintextLength returns 0. The value returned by FixedMaxPlaintextLength is directly related to the modulus size n and the padding scheme.
I'm compiling with:
g++ code.cpp -lcrypto++
An excerpt from my code is below. Know that I'm encrypting a message short enough for this key size, and that the key passes the 'ThrowIfInvalid' check fine.
#include <crypto++/rsa.h>
#include <crypto++/integer.h>
#include <crypto++/osrng.h>
#include <crypto++/aes.h>
#include <crypto++/modes.h>
#include <crypto++/filters.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
//Server public key
CryptoPP::Integer n("151819660278907849564280096608257132054351407309758535974318074707969518724128280259037374014724406632325172752862895193195363199223664682104258638634769874466650499673675383641901147871521771256322561247704585104482417607961937338394672732384692437499643518759317209830786970636267836539513421170177732815387");
CryptoPP::Integer e("65537");
std::string EncryptWithRSA(std::string message);
int main(){
std::cout << "Input string: " << std::endl;
std::string message = "";
std::getline(std::cin, message);
std::string result = "";
result = EncryptWithRSA(message);
std::cout << result << std::endl;
return 0;
}
std::string EncryptWithRSA(std::string message){
CryptoPP::Integer n("151819660278907849564280096608257132054351407309758535974318074707969518724128280259037374014724406632325172752862895193195363199223664682104258638634769874466650499673675383641901147871521771256322561247704585104482417607961937338394672732384692437499643518759317209830786970636267836539513421170177732815387");
CryptoPP::Integer e("65537");
CryptoPP::RSA::PublicKey pubKey;
CryptoPP::AutoSeededRandomPool rng;
pubKey.Initialize(n, e);
pubKey.ThrowIfInvalid(rng, 3);
std::cout << "Public key initialized and validated" << std::endl;
CryptoPP::RSAES_OAEP_SHA_Encryptor enc(pubKey);
std::string result = "";
std::cout << "Starting encryption with RSA" << std::endl;
try{
CryptoPP::StringSource ss1(message, true, new CryptoPP::PK_EncryptorFilter(rng, enc, new CryptoPP::StringSink(result)));
} catch (const CryptoPP::Exception& e){
std::cout << e.what() << std::endl;
}
return result;
}
EDITED
Here's the output for an Input string = "s"
Input string:
s
Public key initialized
Starting encryption with RSA
RSA/OAEP-MGF1(SHA-1): this key is too short to encrypt any messages

Splitting read file C++

Lets start with that I have absolutely no experience with C++ , but I got this project to connect a POS with a verifone. We do not have the standard verifone SDK but something custom.
At fist I needed to prepair data to send to C++ and C++ will send it to the Verifone. This is where I am getting stuck, I have a .txt file, which I can read with C++ but now I need to split the data.
This is my current code:
#include "stdafx.h"
#include <sstream>
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
string file_get_contents(const char *filename)
{
ifstream in(filename);
if (in.fail())
{
cerr << "File not found: " << filename << endl;
return "";
}
std::stringstream buffer;
buffer << in.rdbuf();
in.close();
return buffer.str();
}
int main(int argc, char **argv)
{
vector<string> strings;
string contents = file_get_contents("C:/wamp/www/cmd/config.txt");
string s;
while (contents, s, '||') {
cout << s << endl;
strings.push_back(s);
}
cout << s; // ECHO CONTENTS
std::cin.ignore(); // pause
return 0;
}
With this code my console just stays blank, no data is being displayed.
The full string I am splitting is:
"notepad://amount=10320.53||session_id=7946548443287465/"
The result that I want is to get an array that uses "amount" and "session_id" as keys and their values as value.
What is the best way of achieving this?
I used the following code to actually display the string in my console which was working:
int main(int argc, char **argv)
{
string contents = file_get_contents("config.txt");
cout << contents; // ECHO CONTENTS
std::cin.ignore(); // pause
return 0;
}
This shows how to use a regex to extract the information you want, there are a lot of online resources on how to read files properly so I left that part out.
#include <iostream>
#include <regex>
#include <unordered_map>
#include <string>
int main(int argc, char **argv)
{
std::regex pattern("amount=([[:digit:]\\.]*)\\|\\|session_id=([[:digit:]]*)");
std::smatch results;
std::unordered_map<std::string, std::string> data;
std::string contents = "notepad://amount=10320.53||session_id=7946548443287465/";
//string contents = file_get_contents("C:/wamp/www/cmd/file.txt");
if(std::regex_search(contents, results, pattern))
{
data["amount"] = results[1];
data["session_id"] = results[2];
}
std::cout << "Amount: " << data["amount"] << std::endl;
std::cout << "Seesion ID: " << data["session_id"] << std::endl;
return 0;
}