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
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
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;
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?
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
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;
}