My question/problem might be a bit newbie regarding this field, but I cannot find any solution or clear explanation to achieve what I want.
The problem
I must store and use the hash values as BYTE instead of STRING because of the size. ( it causes me troubles in other areas )
The function generates an MD5 hash for a file, used on windows OS.
Current code
std::string MD5Checksum(const path &file)
{
std::string result;
try
{
CryptoPP::Weak::MD5 md5;
CryptoPP::HashFilter f5(md5, new CryptoPP::HexEncoder(new CryptoPP::StringSink(result)));
CryptoPP::ChannelSwitch cs;
cs.AddDefaultRoute(f5);
CryptoPP::FileSource ss(file.string().c_str(), true /*pumpAll*/, new CryptoPP::Redirector(cs));
}
catch (CryptoPP::Exception const& exception)
{
//
}
return result;
}
What I tested
std::string MD5Checksum(const path &file)
{
std::string result;
try
{
CryptoPP::Weak::MD5 md5;
CryptoPP::HashFilter f5(md5, new CryptoPP::HexEncoder(new CryptoPP::StringSink(result)));
CryptoPP::ChannelSwitch cs;
cs.AddDefaultRoute(f5);
CryptoPP::FileSource ss(file.string().c_str(), true /*pumpAll*/, new CryptoPP::Redirector(cs));
}
catch (CryptoPP::Exception const& exception)
{
//
}
string decoded;
CryptoPP::StringSource ss(result, true /*pumpAll*/, new CryptoPP::StringSink(decoded));
const BYTE* data = reinterpret_cast<const BYTE*>(decoded.data());
printf(L"sizeof result: %d, sizeof data: %d"), sizeof(result), sizeof(data));
return result;
}
This seems to achieve the desired result, because the size of result string is 40 and the size of data is 8 which is a massive reduction in size for me.
However I do not see this as a good solution and I am pretty sure that there must but an easier and cleaner way of doing this.
Any examples are much appreciated.
I must store and use the hash values as BYTE instead of STRING because of the size...
You are almost there.
Both StringSource and ArraySink can handle byte arrays. You just need to use alternate constuctors. Also see StringSource and ArraySink on the Crypto++ wiki.
I would modify the code similar to the following. I'm using C++11 so I don't have std::path:
$ cat test.cxx
#include "cryptlib.h"
#include "filters.h"
#include "files.h"
#include "hex.h"
#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
#include "md5.h"
#include <iostream>
#if defined(CRYPTOPP_NO_GLOBAL_BYTE)
using CryptoPP::byte;
#endif
bool MD5Checksum(const std::string &file, byte* digest, size_t size)
{
using namespace CryptoPP;
try
{
Weak::MD5 md5;
FileSource(file.c_str(), true /*pumpAll*/,
new HashFilter(md5, new ArraySink(digest, size)));
}
catch (Exception const& exception)
{
return false;
}
return true;
}
int main(int argc, char* argv[])
{
using namespace CryptoPP;
std::string filename = (argc >= 2 ? argv[1] : "./cryptlib.h");
byte digest[Weak::MD5::DIGESTSIZE];
if (MD5Checksum(filename, digest, sizeof(digest)))
{
std::cout << "Filename: " << filename << std::endl;
std::cout << "Digest: ";
StringSource(digest, sizeof(digest), true, new HexEncoder(new FileSink(std::cout)));
std::cout << std::endl;
}
else
{
std::cerr << "Failed to calculate digest of " << filename << std::endl;
std::exit(1);
}
return 0;
}
And then compile. I'm working from the cryptopp/ directory in my home directory:
$ g++ ./test.cxx ./libcryptopp.a -o test.exe
$
And finally:
$ ./test.exe
Filename: ./cryptlib.h
Digest: 626047BC8770BE942B26B3AD6CBD3781
In the code above, here are the sources and sinks wrapping the byte array:
StringSource(digest, sizeof(digest) ...);
ArraySink(digest, size);
If you were storing into a std::string like in How to easily apply Crypto++ hash functions?, here are the sources and sinks wrapping the std::string. They are different constructors.
std::string digest;
...
StringSource(digest, ...);
StringSink(digest);
Related
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));
I want to create istream from QByteArray at runtime, without saving a physical file in memory of QByteArray.
I found that there are many ways to do the opposite conversion, i.e. istream to QByteArray, but not this one.
How to accomplish that?
To read via std::istringstream from QByteArray seems quite easy:
testQByteArray-istream.cc:
#include <iostream>
#include <sstream>
#include <QtCore>
int main()
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
// make a QByteArray
QByteArray data("Hello Qt World.");
// convert to std::string
std::istringstream in(data.toStdString());
// read from istringstream
for (;;) {
std::string buffer;
if (!std::getline(in, buffer)) break;
std::cout << "Got: '" << buffer << "'\n";
}
// done
return 0;
}
testQByteArray-istream.pro:
SOURCES = testQByteArray-istream.cc
QT = core
Compiled and tested on cygwin64:
$ qmake-qt5 testQByteArray-istream.pro
$ make
$ ./testQByteArray-istream
Qt Version: 5.9.4
Got: 'Hello Qt World.'
$
Done. Stop, wait!
without saving a physical file in memory
I'm not quite sure how to read this. Probably, it means
without copying data saved in QByteArray
I see only two solutions:
Use a QDataStream instead of std::stream. According to doc. QDataStream::QDataStream(const QByteArray &a)
Constructs a read-only data stream that operates on byte array a.
This sounds very promising that data is not copied.
DIY. Make a class derived from std::stream which may read from a QByteArray without copying.
Concerning 2. option, I found Dietmar Kühl's answer to SO: Creating an input stream from constant memory. Applying this to the above sample, it would look like this:
#include <iostream>
#include <QtCore>
// borrowed from https://stackoverflow.com/a/13059195/7478597
struct membuf: std::streambuf {
membuf(char const* base, size_t size) {
char* p(const_cast<char*>(base));
this->setg(p, p, p + size);
}
};
struct imemstream: virtual membuf, std::istream {
imemstream(char const *base, size_t size):
membuf(base, size),
std::istream(static_cast<std::streambuf*>(this)) {
}
};
int main()
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
// make a QByteArray
QByteArray data("Hello Qt World.");
imemstream in(data.data(), (size_t)data.size());
// read from istringstream
for (;;) {
std::string buffer;
if (!std::getline(in, buffer)) break;
std::cout << "Got: '" << buffer << "'\n";
}
// done
return 0;
}
Compiled and tested again on cygwin64:
$ qmake-qt5 testQByteArray-istream.pro
$ make
$ ./testQByteArray-istream
Qt Version: 5.9.4
Got: 'Hello Qt World.'
$
My code below crashes(Debug Error! R6010 abort() has been called). Can you help me? I'd also would like to know how to initialize the json object from a string value.
Json::Value obj;
obj["test"] = 5;
obj["testsd"] = 655;
string c = obj.asString();
Hello it is pretty simple:
1 - You need a CPP JSON value object (Json::Value) to store your data
2 - Use a Json Reader (Json::Reader) to read a JSON String and parse into a JSON Object
3 - Do your Stuff :)
Here is a simple code to make those steps:
#include <stdio.h>
#include <jsoncpp/json/json.h>
#include <jsoncpp/json/reader.h>
#include <jsoncpp/json/writer.h>
#include <jsoncpp/json/value.h>
#include <string>
int main( int argc, const char* argv[] )
{
std::string strJson = "{\"mykey\" : \"myvalue\"}"; // need escape the quotes
Json::Value root;
Json::Reader reader;
bool parsingSuccessful = reader.parse( strJson.c_str(), root ); //parse process
if ( !parsingSuccessful )
{
std::cout << "Failed to parse"
<< reader.getFormattedErrorMessages();
return 0;
}
std::cout << root.get("mykey", "A Default Value if not exists" ).asString() << std::endl;
return 0;
}
To compile: g++ YourMainFile.cpp -o main -l jsoncpp
I hope it helps ;)
Json::Reader is deprecated. Use Json::CharReader and Json::CharReaderBuilder instead:
std::string strJson = R"({"foo": "bar"})";
Json::CharReaderBuilder builder;
Json::CharReader* reader = builder.newCharReader();
Json::Value json;
std::string errors;
bool parsingSuccessful = reader->parse(
strJson.c_str(),
strJson.c_str() + strJson.size(),
&json,
&errors
);
delete reader;
if (!parsingSuccessful) {
std::cout << "Failed to parse the JSON, errors:" << std::endl;
std::cout << errors << std::endl;
return;
}
std::cout << json.get("foo", "default value").asString() << std::endl;
Kudos to p-a-o-l-o for their answer here: Parsing JSON string with jsoncpp
You can avoid using Json::CharReader and Json::CharReaderBuilder by using stringstream instead.
#include <string>
#include <sstream>
#include "jsoncpp/json/json.h"
int main() {
std::string strJson = "{\"mykey\" : \"myvalue\"}";
Json::Value obj;
// read a JSON String
stringstream(strJson) >> obj;
// get string value
std::string value1 = obj["mykey"].asString();
// or to get a default value if it isn't set
std::string value2 = obj.get("mykey", "...").asString();
return 0;
}
I have an wide-character string (std::wstring) in my code, and I need to search wide character in it.
I use find() function for it:
wcin >> str;
wcout << ((str.find(L'ф') != wstring::npos)? L"EXIST":L"NONE");
L'ф' is a Cyrillic letter.
But find() in same call always returns npos. In a case with Latin letters find() works correctly.
It is a problem of this function?
Or I incorrectly do something?
UPD
I use MinGW and save source in UTF-8.
I also set locale with setlocale(LC_ALL, "");.
Code same wcout << L'ф'; works coorectly.
But same
wchar_t w;
wcin >> w;
wcout << w;
works incorrectly.
It is strange. Earlier I had no problems with the encoding, using setlocale ().
The encoding of your source file and the execution environment's encoding may be wildly different. C++ makes no guarantees about any of this. You can check this by outputting the hexadecimal value of your string literal:
std::wcout << std::hex << L"ф";
Before C++11, you could use non-ASCII characters in source code by using their hex values:
"\x05" "five"
C++11 adds the ability to specify their Unicode value, which in your case would be
L"\u03A6"
If you're going full C++11 (and your environment ensures these are encoded in UTF-*), you can use any of char, char16_t, or char32_t, and do:
const char* phi_utf8 = "\u03A6";
const char16_t* phi_utf16 = u"\u03A6";
const char32_t* phi_utf16 = U"\u03A6";
You must set the encoding of the console.
This works:
#include <iostream>
#include <string>
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
using namespace std;
int main()
{
_setmode(_fileno(stdout), _O_U16TEXT);
_setmode(_fileno(stdin), _O_U16TEXT);
wstring str;
wcin >> str;
wcout << ((str.find(L'ф') != wstring::npos)? L"EXIST":L"NONE");
system("pause");
return 0;
}
std::wstring::find() works fine. But you have to read the input string correctly.
The following code runs fine on Windows console (the input Unicode string is read using ReadConsoleW() Win32 API):
#include <exception>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <windows.h>
using namespace std;
class Win32Error : public runtime_error
{
public:
Win32Error(const char* message, DWORD error)
: runtime_error(message)
, m_error(error)
{}
DWORD Error() const
{
return m_error;
}
private:
DWORD m_error;
};
void ThrowLastWin32(const char* message)
{
const DWORD error = GetLastError();
throw Win32Error(message, error);
}
void Test()
{
const HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
if (hStdIn == INVALID_HANDLE_VALUE)
ThrowLastWin32("GetStdHandle failed.");
static const int kBufferLen = 200;
wchar_t buffer[kBufferLen];
DWORD numRead = 0;
if (! ReadConsoleW(hStdIn, buffer, kBufferLen, &numRead, nullptr))
ThrowLastWin32("ReadConsoleW failed.");
const wstring str(buffer, numRead - 2);
static const wchar_t kEf = 0x0444;
wcout << ((str.find(kEf) != wstring::npos) ? L"EXIST" : L"NONE");
}
int main()
{
static const int kExitOk = 0;
static const int kExitError = 1;
try
{
Test();
return kExitOk;
}
catch(const Win32Error& e)
{
cerr << "\n*** ERROR: " << e.what() << '\n';
cerr << " (GetLastError returned " << e.Error() << ")\n";
return kExitError;
}
catch(const exception& e)
{
cerr << "\n*** ERROR: " << e.what() << '\n';
return kExitError;
}
}
Output:
C:\TEMP>test.exe
abc
NONE
C:\TEMP>test.exe
abcфabc
EXIST
That's probably an encoding issue. wcin works with an encoding different from your compiler's/source code's. Try entering the ф in the console/wcin -- it will work. Try printing the ф via wcout -- it will show a different character or no character at all.
There is no platform independent way to circumvent this, but if you are on windows, you can manually change the console encoding, either with the chchp commandline command or programmatically with SetConsoleCP() (input) and SetConsoleOutputCP() (output).
You could also change your source file's/compiler's encoding. How this is done depends on your editor/compiler. If you are using MSVC, this answer might help you: https://stackoverflow.com/a/1660901/2128694
So I recently installed JSONCPP and for some reason it gives me errors when I try this code:
#include <json.h>
#include <iostream>
#include <fstream>
int main(){
bool alive = true;
while (alive){
Json::Value root; // will contains the root value after parsing.
Json::Reader reader;
std::string test = "testis.json";
bool parsingSuccessful = reader.parse( test, root, false );
if ( !parsingSuccessful )
{
// report to the user the failure and their locations in the document.
std::cout << reader.getFormatedErrorMessages()
<< "\n";
}
std::string encoding = root.get("encoding", "UTF-8" ).asString();
std::cout << encoding << "\n";
alive = false;
}
return 0;
}
And here is the file:
{
"encoding" : "lab"
}
It says that there is a syntax error on Line 1, Column 1, and that there must be a value, object or array. Anyone know how to fix this?
EDIT: Changed to current code, from pastebin
See the Json::Reader::parse documentation. For that overload, the string needs to be the actual document, not the filename.
You can use the istream overload with a ifstream instead.
std::ifstream test("testis.json", std::ifstream::binary);
EDIT: I got it work with:
#include "json/json.h"
#include <iostream>
#include <fstream>
int main(){
bool alive = true;
while (alive){
Json::Value root; // will contains the root value after parsing.
Json::Reader reader;
std::ifstream test("testis.json", std::ifstream::binary);
bool parsingSuccessful = reader.parse( test, root, false );
if ( !parsingSuccessful )
{
// report to the user the failure and their locations in the document.
std::cout << reader.getFormatedErrorMessages()
<< "\n";
}
std::string encoding = root.get("encoding", "UTF-8" ).asString();
std::cout << encoding << "\n";
alive = false;
}
return 0;
}
#include "json/json.h"
#include <iostream>
#include <fstream>
int main(){
Json::Value root; // will contain the root value after parsing.
std::ifstream stream("testis.json", std::ifstream::binary);
stream >> root;
std::string encoding = root.get("encoding", "UTF-8" ).asString();
std::cout << encoding << "\n";
return 0;
}
Or more generally:
#include "json/json.h"
#include <iostream>
#include <fstream>
int main(){
Json::Value root; // will contain the root value after parsing.
Json::CharReaderBuilder builder;
std::ifstream test("testis.json", std::ifstream::binary);
std::string errs;
bool ok = Json::parseFromStream(builder, test, &root, &errs);
if ( !ok )
{
// report to the user the failure and their locations in the document.
std::cout << errs << "\n";
}
std::string encoding = root.get("encoding", "UTF-8" ).asString();
std::cout << encoding << "\n";
return 0;
}
http://open-source-parsers.github.io/jsoncpp-docs/doxygen/namespace_json.html
json cannot contain newlines. Try this instead:
{"encoding": "lab"}
You may need to ensure the file is saved without a final newline.
EDIT: Maybe your parser tolerates newlines, but some don't. Something to try if the other answers don't work