38

I'm working in a C++ unmanaged project.

I need to know how can I take a string like this "some data to encrypt" and get a byte[] array which I'm gonna use as the source for Encrypt.

In C# I do

  for (int i = 0; i < text.Length; i++)
    buffer[i] = (byte)text[i];

What I need to know is how to do the same but using unmanaged C++.

Thanks!

0

9 Answers 9

52

If you just need read-only access, then c_str() will do it:

char const *c = myString.c_str();

If you need read/write access, then you can copy the string into a vector. vectors manage dynamic memory for you. You don't have to mess with allocation/deallocation then:

std::vector<char> bytes(myString.begin(), myString.end());
bytes.push_back('\0');
char *c = &bytes[0];
Sign up to request clarification or add additional context in comments.

7 Comments

If he wants a byte array does he need the terminating '\0'? In which case you can use data() for read only.
i wasn't sure whether he needs the \0 or not. If he doesn't he now knows that he can use .data() . thanks for commenting on that, Martin.
This answer seems correct and may work but assuming the data store for a vector of char is contiguous and won't change is dangerous.
Assuming it's contiguous is not at all dangerous, it's a guarantee of vector (first paragraph under std::vector in the C++ spec IIRC). Assuming it won't change is safe provided that certain specified functions aren't called - amounting to those which might provoke a resize().
Mark, it is very safe to "assume" that, because it's always the case that the vector is contiguous :) and it's also safe to assume the pointer is valid. you don't modify the vector so that it has to reallocate its buffer. so the vector's first element address remains the same of course.
|
26

std::string::data would seem to be sufficient and most efficient. If you want to have non-const memory to manipulate (strange for encryption) you can copy the data to a buffer using memcpy:

unsigned char buffer[mystring.length()];
memcpy(buffer, mystring.data(), mystring.length());

STL fanboys would encourage you to use std::copy instead:

std::copy(mystring.begin(), mystring.end(), buffer);

but there really isn't much of an upside to this. If you need null termination use std::string::c_str() and the various string duplication techniques others have provided, but I'd generally avoid that and just query for the length. Particularly with cryptography you just know somebody is going to try to break it by shoving nulls in to it, and using std::string::data() discourages you from lazily making assumptions about the underlying bits in the string.

2 Comments

Can you please shed light on how using string::data() is better than using string::begin() ? One returns a pointer to the underlying storage, the other returns an iterator, how does that help security?
Variable length arrays, like unsigned char buffer[mystring.length()] are not standard C++. Some compilers support them, but Visual Studio does not.
4

Normally, encryption functions take

encrypt(const void *ptr, size_t bufferSize);

as arguments. You can pass c_str and length directly:

encrypt(strng.c_str(), strng.length());

This way, extra space is allocated or wasted.

1 Comment

If you are passing a pointer and a length then you should be using data() rather than c_str() to indicate it is not being used as a string.
3

In C++17 and later you can use std::byte to represent actual byte data. I would recommend something like this:

std::vector<std::byte> to_bytes(std::string const& s)
{
    std::vector<std::byte> bytes;
    bytes.reserve(std::size(s));
      
    std::transform(std::begin(s), std::end(s), std::back_inserter(bytes), [](char c){
        return std::byte(c);
    });

    return bytes;
}

3 Comments

Actually std::byte has appeared not in C++11 but in C++17 . See en.cppreference.com/w/cpp/types/byte
@Nikita128 Very true, thanks for pointing that out. Now fixed!
Amazing solution, highly recommended for modern C++.
1

From a std::string you can use the c_ptr() method if you want to get at the char_t buffer pointer.

It looks like you just want copy the characters of the string into a new buffer. I would simply use the std::string::copy function:

length = str.copy( buffer, str.size() );

1 Comment

Some implementations of std::string may use reference counting, so a copy would not necessarily result in new bytes that would be safe to write over.
1

If you just need to read the data.

encrypt(str.data(),str.size());

If you need a read/write copy of the data put it into a vector. (Don;t dynamically allocate space that's the job of vector).

std::vector<byte>  source(str.begin(),str.end());
encrypt(&source[0],source.size());

Of course we are all assuming that byte is a char!!!

Comments

0

If this is just plain vanilla C, then:

strcpy(buffer, text.c_str());

Assuming that buffer is allocated and large enough to hold the contents of 'text', which is the assumption in your original code.

If encrypt() takes a 'const char *' then you can use

encrypt(text.c_str())

and you do not need to copy the string.

Comments

0

You might go with range-based for loop, which would look like this:

std::vector<std::byte> getByteArray(const string& str)
{
    std::vector<std::byte> buffer;
    for (char str_char : str)
        buffer.push_back(std::byte(str_char));

    return buffer;
}

Comments

-7

I dont think you want to use the c# code you have there. They provide System.Text.Encoding.ASCII(also UTF-*)

string str = "some text;
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(str);

your problems stem from ignoring the encoding in c# not your c++ code

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.