Techniques for obscuring sensitive strings in C++

Solution 1:

Basically, anyone with access to your program and a debugger can and will find the key in the application if they want to.

But, if you just want to make sure the key doesn't show up when running strings on your binary, you could for instance make sure that the key is not within the printable range.

Obscuring key with XOR

For instance, you could use XOR to split the key into two byte arrays:

key = key1 XOR key2

If you create key1 with the same byte-length as key you can use (completely) random byte values and then compute key2:

key1[n] = crypto_grade_random_number(0..255)
key2[n] = key[n] XOR key1[n]

You can do this in your build environment, and then only store key1and key2 in your application.

Protecting your binary

Another approach is to use a tool to protect your binary. For instance, there are several security tools that can make sure your binary is obfuscated and starts a virtual machine that it runs on. This makes it hard(er) to debug, and is also the convential way many commercial grade secure applications (also, alas, malware) is protected.

One of the premier tools is Themida, which does an awesome job of protecting your binaries. It is often used by well known programs, such as Spotify, to protect against reverse engineering. It has features to prevent debugging in programs such as OllyDbg and Ida Pro.

There is also a larger list, maybe somewhat outdated, of tools to protect your binary.
Some of them are free.

Password matching

Someone here discussed hashing password+salt.

If you need to store the key to match it against some kind of user submitted password, you should use a one-way hashing function, preferrably by combining username, password and a salt. The problem with this, though, is that your application has to know the salt to be able to do the one-way and compare the resulting hashes. So therefore you still need to store the salt somewhere in your application. But, as @Edward points out in the comments below, this will effectively protect against a dictionary attack using, e.g, rainbow tables.

Finally, you can use a combination of all the techniques above.

Solution 2:

First of all, realise that there is nothing you can do that will stop a sufficiently determined hacker, and there are plenty of those around. The protection on every game and console around is cracked eventually, so this is only a temporary fix.

There are 4 things you can do that will increase you chances of staying hidden for a while.

1) Hide the elements of the string in some way -- something obvious like xoring ( the ^ operator) the string with another string will be good enough to make the string impossible to search for.

2) Split the string into pieces -- split up your string and pop bits of it into strangely named methods in strange modules. Don't make it easy to search through and find the method with the string in it. Of course some method will have to call all these bits, but it still makes it a little harder.

3) Don't ever build the string in memory -- most hackers use tools that let them see the string in memory after you have encoded it. If possible, avoid this. If for example you are sending the key off to a server, send it character by character, so the whole string is never around. Of course, if you are using it from something like RSA encoding, then this is trickier.

4) Do an ad-hoc algorithm -- on top of all this, add a unique twist or two. Maybe just add 1 to everything you produce, or do any encryption twice, or add a sugar. This just makes it a little harder for the hacker who already knows what to look for when someone is using, for example, vanilla md5 hashing or RSA encryption.

Above all, make sure it isn't too important when (and it will be when if you application becomes popular enough) your key is discovered!

Solution 3:

A strategy i've used in the past is to create an array of seemingly-random characters. You initially insert, and then locate your particular characters with a algebraic process where each step from 0 to N will yield a number < size of the array which contains the next char in your obfuscated string. (This answer is feeling obfuscated now!)

Example:

Given an array of chars (numbers and dashes are for reference only)

0123456789
----------
ALFHNFELKD
LKFKFLEHGT
FLKRKLFRFK
FJFJJFJ!JL

And an equation whose first six results are: 3, 6, 7, 10, 21, 47

Would yield the word "HELLO!" from the array above.

Solution 4:

I agree with @Checkers, your executable can be reverse-engineered.

A bit better way is to create it dynamically, for example:

std::string myKey = part1() + part2() + ... + partN();

Solution 5:

Of course, storing private data in software which is shipped to the user is always a risk. Any sufficiently educated (and dedicated) engineer could reverse engineer the data.

That being said, you can often make things secure enough by raising the barrier which people need to overcome to reveal your private data. That's usually a good compromise.

In your case, you could clutter your strings with non-printable data, and then decode that at runtime using a simple helper function, like this:

void unscramble( char *s )
{
    for ( char *str = s + 1; *str != 0; str += 2 ) {
        *s++ = *str;
    }
    *s = '\0';
}

void f()
{
    char privateStr[] = "\001H\002e\003l\004l\005o";
    unscramble( privateStr ); // privateStr is 'Hello' now.

    string s = privateStr;
    // ...
}