How can one protect sensitive data in the code?
Asked Answered
L

8

23

I was examining the ways of protecting my code from decompiling.

There are several good threads here describing obfuscation and code packing as the possible ways of protecting the code. However none of them is ideal, obfuscation doesn't work with reflection when the string method/property names are used. Many people do not recommend to use obfuscation at all.

So I currently decided not to go with any of the above. However, I have parts of the code where I need a sort of encryption, for example, a database connection string with an IP, login and password is stored inside the code as simple const string, same as email account data.

In ASP.NET there is an option to move the sensitive data to a .config file and encrypt it, but that requires the server key, i.e. linked to a single computer. I didn't read much about it, but I suppose something similar is available for desktop applications. But I need this to work on any computer where the application is installed.

Are there ways to encode/protect such data so that it cannot be read along with decompiled code?

Leuco answered 21/10, 2011 at 12:50 Comment(1)
The problem with what you are describing is that even if you encrypt what you distribute, you would need to distribute the decryption key along with it so that the code could decrypt it. Can you not externalize the credentials and connection string and then have your users register individually (each getting his own credentials)?Disquisition
H
26

First advice is to never store anything sensitive in your code directly. You can always reverse engineer that, no matter how cleverly you try to obfuscate it.

I've read about things like breaking a password into several pieces, placing them at different places in the code and running them through a series of functions before finally using them... although this makes things harder, you can still always monitor the application using a debugger and ultimately you will be able to retrieve the secret information.

If I interpret your scenario correctly, what you have is code that is to be deployed at some client's premises and your code is connected to a database (which I suppose is also under the client's supervision), connecting to it requires a password. This password is known to that client, so trying to hide it from the client is rather useless. What you do want is to restrict access to that password from anybody who is not supposed to know it.

You typically achieve this by putting the sensitive information in a separate file in a folder that should have very restrictive permissions, only the application and a handful of selected people should have access. The application would then access the information when needed during runtime.

Additionally encrypting the separate file turns out to be a problem - if you do so then there is a key involved that again would have to be secured somehow - infinite recursion is on it's way :) Securing access to the file is often sufficient, but if you really require to be as secure as possible, then a solution is to use password-based encryption for the file. But the idea here is not to store the password in yet another location on the system, but rather as out-of-band information (e.g. in a physical vault) and entering the password when starting the application. This, too, has its problems: physical presence of a person is required for (re-)starting the application, and you could still retrieve the password from the RAM of the machine where the application is running on. But it is probably the best you can do without specialized hardware.

Another good alternative to password-based encryption would be to rely on OS-specific "password vaults" such as Windows' Isolated Storage, it's sort of a trade-off between not encrypting at all and keeping the password out-of-band.

Hassler answered 21/10, 2011 at 17:38 Comment(0)
J
12

This isn't an encryption answer, but one way to 'secure' this would be to make all your database calls through a web service. Your connection credentials would then be stored on your secure server and the clients pass all calls through there.

Nothing sensitive stored in your re-distributable at all...

Julissa answered 21/10, 2011 at 13:2 Comment(0)
L
6

I have grappled with this problem in the past and come up with three ways of dealing with the problem, but I'm not sure any of them are perfect:

  1. Obfuscate or encrypt the value and hope for the best. Encryption, of course, is just an extra level of obfuscation since the key must be delivered with the rest.
  2. Eliminate the need for the key itself by using one-way encryption instead. Use a private key to generate a public key. This can be used for licensing or password validation. You generate the licenses with the private key, but the public key can be used to validate them. Or you use the private key to generate a password that can be validated, but not reversed using the public key.
  3. Create your own system-specific key-generation mechanism similar to that used by ASP.NET. You can limit the effect of someone reversing the encryption/obfuscation in step 1 by generating a unique key for each installation or site.
Legroom answered 21/10, 2011 at 13:5 Comment(4)
Points #2 and #3 seem to be interesting. I am trying to imagine the #2, is there any additional information on this method?Leuco
See #2743083Legroom
My previous link leads to the question when really my answer is the relevant piece: https://mcmap.net/q/584583/-modify-emdeded-string-in-c-compiled-exeLegroom
You could save the key in Hardware, here I am talking about Hardware Security Modules. Read more here: [markgamache.blogspot.in/2011/05/…Pyszka
S
4

There are tons of methods, but the reality is that if you really want to protect your code, the only solution is to use "professional" products :-) don't try to reinvent the wheel. These products normally have options to encrypt strings. The real problem is another: without a professional product (and even WITH a professional product) an expert can simply put a breakpoint and look at the parameters passed to the library method (for example the one that opens the connections). Now... If you really really want to encrypt the strings of your code, it's quite easy. But would it be useful? No.

Now, just so that no one will mark this as "not an answer", I'll post some simple encryption/decryption code:

// Generate key. You do it once and save the key in the code
var encryptorForGenerateKey = Aes.Create();
encryptorForGenerateKey.BlockSize = 128;
encryptorForGenerateKey.KeySize = 128;
encryptorForGenerateKey.GenerateKey();
encryptorForGenerateKey.GenerateIV();

var key = encryptorForGenerateKey.Key;
var iv = encryptorForGenerateKey.IV;

// Encrypt: this code doesn't need to be in the program. You create a console
// program to do it
var encryptor = Aes.Create();
var encryptorTransformer = encryptorForGenerateKey.CreateEncryptor(key, iv);

string str = "Hello world";
var bytes = Encoding.UTF8.GetBytes(str);
var encrypted = encryptorTransformer.TransformFinalBlock(bytes, 0, bytes.Length);
var encryptedString = Convert.ToBase64String(encrypted);

Console.WriteLine(encryptedString);

// Decrypt: this code needs to be in the program

var decryptor = Aes.Create();
var decryptorTransformer = decryptor.CreateDecryptor(key, iv);

byte[] encrypted2 = Convert.FromBase64String(encryptedString)

var result = decryptorTransformer.TransformFinalBlock(encrypted2, 0, encrypted2.Length);

var str2 = Encoding.UTF8.GetString(result);

This code clearly isn't secure. Anyone can decompile the program, add a Console.WriteLine(str2) and recompile it.

Scrophulariaceous answered 21/10, 2011 at 12:58 Comment(3)
So what you write is to encrypt the strings outside the program and store the encrypted strings in the form of const string inside the program along with the encryption key. Then the program also contains the decryption code. Thus if I go and decompile the program with .NET Reflector I will see the key and the decryption logic, i.e. useless. Is that correct?Leuco
@Leuco I thought the comment in bold at the end of the answer was enough :-) Yes, you are right. The difference between my code and the generated by a professional obfuscator is that the code of the obfuscator is much more difficult to de-obfuscate to find the strings.Scrophulariaceous
@Leuco The point is: if your boss asked for string encryption, you now can give him string encryption. Another checkbox set. If you really want a solution... Well... There isn't one. If you give the key, the decrypting code and the string to a person, he has all that he needs to decrypt it.Scrophulariaceous
P
4

You can of course encrypt your string before compiling it, but your code need that in plain text sometime if you are using a simple db or http url.

There is not a real protection in this case: Everyone can listen (breakpoint) to a specified method and when called see what's going on without really reading your code. So no, there is not a real protection against this, also using obfuscation at some point you will call some .NET method with that plain text string, and everyone can read it.

You can for example put a COM or C++ dll for storing encrypted strings. A unmanaged dll is not decompilable, however, expert people can of course understand the disassembly of a dll. And as said before, sometime you will need the plain data, and at that moment, there is no protection that can last.

The only thing you can do is to change your architecture.

For example, if your db is online and your application is a client application, you can connect using web services. Then you can expose only the web services the user really need to use, there is no risk of user writing sql queries. Then you can add the protection logic on the server instead that on the client.

If everything is offline there is not much you can do, you can make life harder using simple string encryption but it will never be a real protection.

Palmore answered 21/10, 2011 at 13:40 Comment(0)
S
3

As Lucas pointed out in its comment, if you have only one piece, then anybody decompiling your application can reverse-engineer it and decrypt your database passwords.

About storing credentials, my usual practice is to always store them in the application configuration file. If then I need to secure it, I use a SecureString and some encryption. And this could work for any kind of configuration information, not only credentials. There is a really good article about securing configuration files here: Encrypting Passwords in a .NET app.config File

Sangsanger answered 21/10, 2011 at 14:16 Comment(0)
C
1

Maybe you should read some more on encrypting the web.config http://learn.iis.net/page.aspx/141/using-encryption-to-protect-passwords/

Otherwise there isnt much you can do. Storing sensitive data in code isn't an option since anyone with a reflector tool can open it and see it. If you want code or variables to be invisible to everyone, you should create a webservice on a private server that accepts data, transforms it through it's magic and returns it to the client. In that way everything in between posting and retrieving the data is kept secret.

Caryncaryo answered 21/10, 2011 at 13:0 Comment(1)
accepts data, transforms it through it's magic and returns it to the client isn't a solution. Network traffic can be sniffed or with some disassemblers running code can be attached.Heater
C
0

I am not sure if it is possible to protect your code at a client location, but a solution might be to store the password in Azure Key Vault and authenticate to it with Azure Active Directory. However, this might still be possible to reverse engineer. You can read more here: https://learn.microsoft.com/en-us/azure/key-vault/

Celaeno answered 14/7, 2022 at 20:1 Comment(1)
This might have added an extra dependency/layer that would add extra cost/network traffic/ and complexity. But yes, it is still valid solution.Irkutsk

© 2022 - 2024 — McMap. All rights reserved.