Advertisement

Securely store a string in a C++ program?

Started by August 24, 2024 10:39 PM
17 comments, last by a light breeze 2 weeks, 4 days ago

Just be aware it still is not “secure”. It is easily extracted by anyone who can run the program and is motivated to obtain it.

Locking it with RSA would help secure the “data at rest” and “data in transit” phases, poking at the values on disk won't reveal what is encrypted without the key, watching it flow over the wire the same, but it still is opened up in the “data in use” phases. Anyone with a debugger could still intercept it, and with analysis could also get the key and unlock it themselves.

Mostly this is about understanding what you are protecting and who you are trying to protect it from. Often all it takes is one motivated person to dig in and publish the answer to expose it to the world. Are you okay with that? Sometimes it is more complex, like a patch where you must be careful against leaking anything around unannounced future features in progress, that might unintentionally be leaked through unexpected binary metadata and discovered by enthusiastic fans. Other times it is about avoiding exploits, or about securing transactions between players, or about attacks on the infrastructure, or exposed player information like public IP addresses, or other information. Fortunately in general games are not protecting critical secrets that impact lives or livelihoods.

The purpose of this is to obfuscate a password for an AES-256 encrypted zip file that holds game files.

10x Faster Performance for VR: www.ultraengine.com
Unless you only want to be able to post on ****ing Reddit, we should all get a GDNet+ subscription. It's not expensive.

Advertisement

Josh Klint said:
The purpose of this is to obfuscate a password for an AES-256 encrypted zip file that holds game files.

You want to have passwords in code for production convenience?

Put it in a header file, add a compile time task to generate an encrypted header file, which is included in the release build.

Josh Klint said:

The purpose of this is to obfuscate a password for an AES-256 encrypted zip file that holds game files.

That's going to be trivial for anyone experienced in attacking software.

Yes it will slow down casual folks, but any serious attacks or significant game will have a crack published within a few hours.

frob said:

Josh Klint said:

The purpose of this is to obfuscate a password for an AES-256 encrypted zip file that holds game files.

That's going to be trivial for anyone experienced in attacking software.

Yes it will slow down casual folks, but any serious attacks or significant game will have a crack published within a few hours.

The enemy can disassemble the game, find routines for AES-256 decryption, run the game under a debugger and look at the key as it is passed to and used by those decryption routines.

There are some tricks to make each of the four steps more difficult and/or annoying and/or time consuming, but culling the inexperienced crackers who give up is balanced by attracting the expert crackers who want to be challenged.

Are you trying to prevent piracy, to prevent hacking the game (e.g. to avoid cheating mods in multiplayer matches), to prevent ripping assets, or something else? Useful techniques for different purposes are quite different.

Omae Wa Mou Shindeiru

The goal is to prevent ripping of assets, so third-party authors are able to release assets for our engine without worrying about the content being ripped out of distributed games. Yes, I know texture and mesh data can be read from VRAM, but raw texture data is not that useful in most cases.

10x Faster Performance for VR: www.ultraengine.com
Unless you only want to be able to post on ****ing Reddit, we should all get a GDNet+ subscription. It's not expensive.

Advertisement

The simple renamed zip file is adequate for what you need. Nobody is going to bother decrypting AES. As you described, it is easy enough to pluck it from memory once loaded. Anybody with a modern debugger — freely available from system manufacturers — can rip them. Pluck it from RAM, pluck it from the drivers, pluck it from VRAM, record it through RenderDoc or Pix, pull it out through Windows Debugger, or many other tools, none of what you described is 'secure'.

AES will secure it after it is encoded and only until it is decoded. Your program must decode it to make any use of it, and at that point it is accessible in all kinds of methods to anybody with a debugger, performance analysis tool, or hacking tool.

It feels like the ‘third party authors’ don't have a fear based on reality, but based on the theoretical. What you described gives virtually zero ‘security’. It has virtually nothing to do with the initial question of securely storing a string in a C++ program. Spend your time on features that provide actual value.

There's no point in trying to hide an encryption key in an executable. Encryption keys look like raw noise, so the only way the encryption key will be found in the code is by tracing through the program until you get to the decryption algorithm, at which point you already have access to the decoded encryption key.

That said, if I wanted to hide a password in an executable, here's what I'd do:

  • Create a random string of bytes the same length as my password and store it in my executable.
  • Create a second string by xor-ing each byte in the password with one byte from the previous string of random bytes, and store that it the executable.
  • To get the original password, xor the first string with the second string.

Both strings, looked at independently, contain only raw random noise with no hint as to the password. The only realistic way to get to the password is to trace through the program until the strings are combined to form the password. If the attacker does trace through the program, you're fucked anyway.

Advertisement