I'm having a problem trying to convert SecByteBlock
to string.
Here's my case:
I want to encrypt user access data using AES with static key and dynamic iv.
My code is something like this:
AesKeyIvFactory aesKeyIvFactory;
SecByteBlock key = aesKeyIvFactory.loadKey();
SecByteBlock iv = aesKeyIvFactory.createIv();
encryptionService->encode(&userAccess, key, iv);
std::string token = std::string(iv.begin(), iv.end()) + userAccess;
The code above is supposed to:
Load key from file;
Create iv;
Encrypt (AES) user access data;
Concatenate the iv with the user data access encrypted to create a "token";
Running a test several times, sometimes (1 to 10 times) the std::string(iv.begin(), iv.end())
doesn't work correctly. It seems like there is a "line break" in the iv that makes the conversion fail.
I tried a lot of things, but nothing works and I don't have experience with c++.
I hope that someone can help me.
I think Eric answered your primary question on how to convert the SecByteBlock
to a std::string
(including the explicit conversions between char*
and byte*
). But here's how you might approach std::string token = std::string(iv.begin(), iv.end()) + userAccess;
issue.
string token;
SecByteBlock iv(16), userAccess(16);
OS_GenerateRandomBlock(false, iv, iv.size());
OS_GenerateRandomBlock(false, userAccess, userAccess.size());
SecByteBlock nil;
nil.CleanNew(HMAC<SHA256>::DEFAULT_KEYLENGTH);
HMAC<SHA256> hmac;
hmac.SetKey(nil.data(), nil.size());
HashFilter filter(hmac, new HexEncoder(new StringSink(token)));
filter.Put(iv.data(), iv.size());
filter.Put(userAccess.data(), userAccess.size());
filter.MessageEnd();
cout << token << endl;
The SecByteBlock nil
creates an object with no memory or size. The nil.CleanNew(HMAC<SHA256>::DEFAULT_KEYLENGTH)
sizes and initializes the SecByteBlock
to 0. Otherwise, you have an uninitialized block of memory.
It is possible to declare it and size it with a 0-inialized array, but you have to be familiar with the sources because its no Doxygen-docimented as of Crypto++ 5.6.2. That way is to use a NULL
pointer, but a non-0 size. Here's what it would look like, but its very non-intuitive:
SecByteBlock nil(NULL, HMAC<SHA256>::DEFAULT_KEYLENGTH);
The trick relies on this SecBlock<T>
constructor:
00250 SecBlock(const T *t, size_type len)
00251 : m_size(len)
00252 {
00253 m_ptr = m_alloc.allocate(len, NULL);
00254 if (t == NULL)
00255 memset_z(m_ptr, 0, len*sizeof(T));
00256 else
00257 memcpy(m_ptr, t, len*sizeof(T));
00258 }
If possible, you should use HKDF
instead of the HMAC<SHA>
with a nil
vector to extract the entropy from the security parameters. You can find the HKDF
in the repo at the HKDF class
. Its a stand alone header, so it will "just work".
A typical run of the program with random values for iv
and userAccess
is:
$ ./cryptopp-test.exe
061CF705259058C4E01A2BF22830FC3F2A7E97F12FE605B38405B1E1B19A9E0F
Another way to approach it could be concatenation based on SecByteBlock
's operator +=
. The result is a binary string, and not a human readable ASCII string.
SecByteBlock result;
result += iv;
result += SecByteBlock(userAccess.data(), userAccess.size());
string token(result.data(), result.size());
If you need a human readable string, then run it through a HexEncoder
:
HexEncoder hex(new StringSink(token));
hex.Put(result.data(), result.size());
hex.MessageEnd();
But it does not extract the entropy from the parameters, so I personally like it less.
When you move from a SecByteBlock
to a std::string
, you effectively lose your secure allocator. That means the data in the copies will not be zeroized after egressing data to the string
object.
The HexEncoder
is a convenience item, and it allows you to dump the binary string.
Another useful one might be the Base64URLEncoder
. It uses the web safe alphabet.
I'm having a problem trying to convert SecByteBlock to string
If the issue is with conversion from SecByteBlock
and its byte
array to a std::string
and its char
array, then you should:
SecByteBlock iv;
...
// C-style cast
std::string token = std::string((const char*)iv.data(), iv.size()) + userAccess;
Or,
SecByteBlock iv;
...
// C++-style cast
std::string token = std::string(reinterpret_cast<const char*>(iv.data()), iv.size()) + userAccess;
You can also forgo the assignment, and just initialize and later append:
SecByteBlock iv;
...
std::string token(reinterpret_cast<const char*>(iv.data()), iv.size());
...
std::string userAccess;
...
token += userAccess;
The other problem you might have is string
to SecByteBlock
. You should do this:
std::string str;
...
// C-style cast
SecByteBlock sbb((const byte*)str.data(), str.size());
Or:
std::string str;
...
// C++-style cast
SecByteBlock sbb(reinterpret_cast<const byte*>(str.data()), str.size());