I need to store sensitive information (a symmetric encryption key that I want to keep private) in my C++ application. The simple approach is to do this:
std::
Instead of storing private key in your executable, you may want to request it from the user and store it by means of an external password manager, something similar to Mac OS X Keychain Access.
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;
// ...
}
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 key1
and 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.
Context dependent but you could just store the hash of the key plus a salt (constant string, easy to obscure).
Then when (if) the user enters the key, you add the salt, calculate the hash and compare.
The salt is probably unnecessary in this case, it stops a brute-force dictionary attack if the hash can be isolated (a Google search has also been know to work).
A hacker still only has to insert a jmp instruction somewhere to bypass the whole lot, but that's rather more complicated than a simple text search.
Somewhat dependent on what you are trying to protect as joshperry points out. From experience, I would say that if it is part of some licensing scheme to protect your software then don't bother. They will eventially reverse engineer it. Simply use a simple cipher like ROT-13 to protect it from simple attacks (line running strings over it). If it is to secure users sensitive data I would be questioning whether protecting that data with a private key stored locally is a wise move. Again it comes down to what you are trying to protect.
EDIT: If you are going to do it then a combination of techniques that Chris points out will be far better than rot13.
Try this. The source code explains how to encrypt and decrypt on the fly all strings in a given Visual Studio c++ project.