Securing encryption keys in C# - c#

I am aware of the many cryptography providers that are available in the .NET framework along with the basics of how to use them. This is simple enough.
But my concern is this.
Lets say I want to use these libraries to encrypt XML serialized objects to prevent tampering and the ability of anyone to come along and view the contents of these files.
The problem that I am always left with is that the key to decrypt this data would need to be stored as a constant somewhere in my application. Essentially rendering the entire exercise pointless.
So, how does one store a key for an encryption algorithm securely inside of a disassemblable application?
EDIT: So If I am understanding both answers below correctly. What this means is that essentially any implementation (to be secure) requires it to be readonly or writeonly but never both? Is this correct?

You don't. If the application can access the key, it is just security by obscurity. It is better to authenticate the user in some way (a password is the simplest example), to make sure he is allowed to access the data. You can't let the application do that for you, because it simply isn't trustworthy. Anyone can obtain the information stored in the application.
If the key information is stored somewhere else, a malicious user or application can probably access it, too. If not, then store your data directly to that magical safe place.
Now if you still want to go down that path and store sensitive data without authentication, your best bet - or at least an easy way that is halfway secure - is probably the DPAPI (see the ProtectedData class in System.Security.Cryptography). It will encrypt the data either with the machine key or to the user account key (you can select that). So that a program running on another machine or with another user account can't access it. Windows will try to protect those keys but in effect any application running on the proper machine or with the proper user account may be able to access your data.

We'll assume you're using some kind of public key cryptography scheme, because otherwise it would be pointless.
The answer is you do not store the private key anywhere in the application. You store it somewhere where only your application can get to it. For example, a file in the local system that only admins and your app have rights to read it. On a protected network share. Etc.
Think about how we manage keys as people. We keep our private ones in a file maybe, or an encrypted USB drive or something like that. The same principles apply to applications.

There a various possible solutions. One of them is using RSA. Alternatively you could use the same approach used in TLS.
One good way would be to generate a pair of public and private key. Encrypt with the private and destroy the key. With the public key, you could decrypt but not tamper the data.

Collecting given answers: All encryption security relies on protection of a "root" password. This cannot be guaranteed in a compromitable system.
A feasible hardware architecture is given by e.g. Chip Card Readers. As external systems they cannot be compromised by internal malicious manipulations.
Accordingly you could set up a separate "Secure Server" with strongly restricted access, e.g. key board and local network. This server would provide sensitive data like passwords by secured communication with authenticated clients in a limited time window.
Suggested measures for clients in this time window are clamping spyware, messengers, remote control server and basically internet access, process monitoring, ...
... or you do all sensitive data processing on secure platforms, excluding talkative ones like Windows.

Related

Proper way to store encryption keys for use with multiple apps across multiple machines

Here is the scenario.
We have sensitive data such as SSN and DOB stored in our database.
This data is encrypted before we insert the record.
We have many (more than 20) application and web apps spanning multiple machines and datacenters that will need to either encrypt and store the data or retrieve and decrypt it. Most of the apps are .Net, but not all of them.
Currently we have a are using the Microsoft TrippleDESCryptoServiceProvide (we will be using a newer algorithm soon) to do the encryption/decryption.
We currently store the key inside the class we have that does the encryption/decryption.
This is obviously bad for multiple reasons that I'm sure we are all ware aware of. And before anyone chastises me, I didn't write this code, I inherited it.
In the end I need a central location where I can securely store the key and retrieve it quickly.
Things to consider
Different types of apps (Console, windows forms, web sites and API's) need to access it
Apps run on different machines, some are not part of the domain and are in a DMZ. Most are windows running .Net apps, but some run Linux and are GO apps.
We do have a central DB server, but then how would we securely store the SQL credentials used to access the key?
Running SQL server 2016 Pro.
Have you considered using the Transparent Data Encryption feature of SQL Server?
While it's not a key storage mechanism per se, if your goal is to protect the data "at rest" (i.e. in the database files on the filesystem and in all backups), then this may provide a way to do that without having your own encryption method split between the various applications.
TDE is not the most complicated thing to set up, but make sure you understand how the certificates and keys are used, and that you know what you need to back-up (and store securely) to be able to recover data and restore backups to different machines and the like.
It won't fix your distributed key issue, but you could either do away with the requirement to encrypt/decrypt the data into and out of the database in each application and have the database do it transparently.
As another alternative, you could also use a separate TDE-secured database on the central server as the store for your encryption key, which all the other applications can then access.
With TDE, you're correct in that anyone with credentials to the SQL Server would be able to access the data in plain-text, so you'd need to protect the credentials to the server, as you mentioned.
Protecting Credentials
As you have machines spread between different operating systems and domains, you probably need multiple different ways of protecting the credentials on each one (which I guess you know).
For Windows machines on the same domain as the SQL Server (or a domain trusted by the SQL Server), you can't really beat a Group Managed Service Account. They are a domain-level account that cannot be interactively logged in, have a very long and periodically mutating password, and can only be used by service accounts. With these, you don't need SQL account credentials because you can grant database permissions directly to the service account (the connection string uses "Integrated_Security=True").
For Windows machines not on the domain, a sensible way to store credentials is with the Data Protection API. With this, you can give the SQL Username and Password credentials to your code (running as some low-priviledge service user), which it then DPAPI protects and stores in a file. That way, only code running as that service user would be able to read them back out. Nefarious code accessing the filesystem from another user wouldn't be able to decrypt them.
As for Linux, that's not really my area, sorry.
Certificates
To throw even more food for thought in, all operating systems (well, at least Windows and Linux) have some way of protecting certificates and their private keys, and many frameworks (such as .NET) have methods for using certificates to encrypt and decrypt data. You could potentially generate a certificate and private key (which gives you an Asymmetric key pair), and install them both on each on your servers.
With that, you can then generate a Symmetric key (for 3DES or AES, for example), then encrypt the Symmetric key with your certificate's Asymmetric public key. The encrypted Symmetric key can be put in a central database or somewhere else. Only applications with the asymmetric private key to decrypt the symmetric key would then be able to use it to decrypt the data.

How to allow application vendor (only) to detect tampering of log files?

I'm trying to figure out the best way to sign data (log-data, etcetera) written to file by a C# desktop application. Somehow the application, and the application only, needs a private key (secret) to encrypt the checksum/hash of the data.
The reason: Only the vendor should be able to tell if data produced by the application has been tampered. Only the integrity of the data is importent. Confidentiality is not a problem (encryption not needed).
The vendor has no control of the on-site installation process (read: can't enter secret manually during the installation process).
The customers doesn't nessecarily have a Internet connection or other means to retrieve the secret from a secure communication line.
Users (customers) may or may not have admininstrator-privileges on the computer where the application is executing.
The vendor will NOT hardcode (and obfuscate) the secret inside the application (or its installer).
Installing a certificate containing a private key along with the application seems to be a dumb idea, but maybe its not?
Is it possible to sign the application with a certificate and extract the secret/private key from the certificate somehow? (implementing a mechanism to create a private key is NOT a good idea, though. The secret must be associated with the key only according to good security principles).
Does anyone have any experience with the best way to solve this challange?

Best method for securely storing passwords

What is the best method for saving passwords on a computer so that they can not be accessed? I would like to store them in the Registry encrypted. I would like you to be able to reset the password but this is not for the server. This is for storing them on a computer to remember them and sign in automatically.
IMPORTANT EDIT: I need to be able to retrieve the plain-text password from within the program, just not anywhere else.
CryptProtectData and CryptUnprotectData are your best bet on Windows. They encrypt the data using login credentials, so the passwords are safe from attacks to the disk. However, they can be accessed by any program running under the same user. I would recommend storing them in a file whose permissions prevent other programs from accessing them (such as a file that requires administrator privileges to access).
The managed class ProtectedData uses these function, so it can be used from C#.
You can also use these functions directly using P/Invoke. There is some example code that does exactly that here.
Expansion in response to additional requirements:
There is a way to ensure that your program is the only one able to access the password without needing your program to be launched with administrator privileges, though it will take a lot more work.
The basic idea is this: you create a Windows service that is installed when you install your application. It should be launched on demand from your application when it wants to store/retrieve the user's password. The service will simply provide read/write access to a file with permissions set so that only administrators can read/write it. The additional security comes from the IPC connection to the process, which will use a Named Pipe. You can then use GetNamedPipeClientProcessId (sorry, you need P/Invoke) to authenticate the request by looking up the process ID of the client that connected to the pipe.
Depending on how worried you are about security, you can verify the process ID using code signing, if you have access to a valid certificate. Or, you can verify the checksum of the executable or something of that nature.
This is the only way I can think of to create the security you are looking for on Windows. Your application should also use ProtectedData to encrypt the data before handing it over to the Windows service to protect against hard disk attacks.
I believe what I'm looking for is AES. This seems like an easy way to store a password. Of course, this is only for remembering a password on the computer so the user does not have to type it.
http://en.wikipedia.org/wiki/Advanced_Encryption_Standard

Need a Security Scenario for asp.net webservice

I have developed a .Net 3.5 windows forms application. I also want to design a website that has a webservice with multiple Webmethods to query the database on the host machine. I want the webservice to be called ONLY through my winapp and my website! And I don't want any other people to be able to call and use my webservice but only some people who have access to the windows application that I have developed.
I need a good security scenario for this! I truly appreciate anyone who can help me because this is my first experience of developing a webservice and I really need it to be as secure as I mentioned!
What you're talking about is going to be difficult to do for several reasons, but primarily this:
If you put anything in code on your WinForms app, it can be decompiled very easily. You can obfuscate the code all you like, but it can be de-compiled.
Because of that, any code that you have in your app can be read by anyone with access to the code. You should always treat any WinForms app as if it's completely compromised, and ensure that the security at the server end compensates.
Because of this, you can't simply store usernames and passwords in configuration files or in code. You have to come up with something else. You CAN use authentication and prompt the user to enter a username/password on program launch, and use that. However, people tend to share these things, so you may want to go for extra protection.
You can put the connection info, or secrets into the app.config and encrypt it, but anyone who can de-compile the code, can recompile it, and add code to decrypt it at will.
You can provide signed keys with your app, and use that in an authentication mechanism, but that can be bypassed.
You can restrict your IP address to specific IP addresses, but those can be spoofed.
However...
By layering all of the above techniques, you can make it difficult for an attacker to bypass your precautions. We did the following in one of our apps where we had a similar requirement:
We set up a database that holds a GUID record for each authorized customer, and IP addresses allowed for that customer.
Every web method expects a CustomerKey parameter. (the guid mentioned above) Each call to a web service checks the key against the IP address.
If it matches, valid data is returned.
If it fails, valid looking data is returned. We actually return what looks like good data, but it's really not. This makes it harder for an attacker to know if they've actually broken through the defenses.
In the WinForms app, the key is stored in the app.config, which is encrypted in the main() event (the entry point for WinForms apps). This is to prevent the casual reader from accessing it.
The program is launched automatically on install, so that the encryption happens at startup, to minimize the chance someone can read the file before it's encrypted.
Also, the code is obfuscated.
Layering the defenses, hopefully, will discourage the average attacker.
Microsoft has some guidelines as well: http://msdn.microsoft.com/en-us/library/ff648643.aspx

Best practice for storing settings

I have only been programming for the better part of 1-2 years, C# the last 7 months or so, Up til now I have used the .config file to store needed settings that cannot be stored in the database, and it was okay to do so.
Now I have a client where there are many users that will access a database, and part of the spec is that the application must log into sql using the sa username, obviously if anyone gets hold these settings it would be a problem.
I want to know what the best practice for something like this would be, I can encrypt the password and server address, but I still feel uneasy about this.
What is the best practice in the industry for storing settings that cannot be in the database, especially the ones that are sensitive configurations
Many Thanks in advance
You can put settings into a local database. I prefer MS SQL Server Compact 3.5, which is free. This way you can store your settings into a local SDF database file, which can be encrypted and password protected. The data stored in the SDF file can be accessed using e.g. ADO.NET+SQL, but I prefer Linq-to-SQL.
EDIT:
Please take into account that although SDF files can be encrypted and password protected, if the file is stolen, it can definitely be cracked by a brute force method. The same is true for any other solution, which stores sensitive data on client machines.
You can try to store information in Isolated Storage
I can't recommend highly enough to revisit the requirement to have the sa account used by the application. That is a HUGE security hole. Given the information provided, I would recommend encrypting the connection (won't really matter where you store it). Make sure that if your database connection methods fail, the error result won't display the user name and password.
The best practice method (I think) would be to use SQL server integrated security: (you authorize a Windows/Active Directory user to access the server, the security aspect is now handled by Windows and your Domain configuration) - however this is not always practical, and you might not want to give the windows user that much access to the database outside the client software (eg, the application must insert/update/delete records in the database, something you wouldn't necessarily want the user to be able to do if they logged into the DB via SSMS)
Another method would be to use the 'Protect' and 'Unprotect' methods of the System.Security.Cryptography.ProtectedData class to encrypt and decrypt the password, and/or the connection string. (you will need to set a reference to System.Security.dll).
This gets around the "where do you hide the key" issue - the ProtectedData class uses your Windows machine's entropy pool to generate a key. You can add your own salt (by way of a byte-array as "additional entropy") to ensure that the data cannot be retrieved by another .NET program running under the same user-context also using the ProtectedData class. You can 'protect' the password/data so it can only be 'un-protected' by the same user on the same machine that protected it.
Hope this helps :)
Cheers,
Simon.

Categories

Resources