What cipher does MachineKey.Protect() use? - c#

I've just come across the MachineKey.Protect() method. I've not seen this before (a contractor introduced it into the code base). It seems interesting but the documentation on what it's doing is a little sparse.
I'm not really one for blindly following Microsoft's lead without a little investigation so I tried to find docs on how this works, what ciper does it use, how big is the key, how's the key generated, etc. But the doc's contain surprisingly little information and I couldn't find any other information on how this is implemented:
This method supersedes the Encode method, which requires the caller to
specify whether the plaintext data should be encrypted, signed, or
both. The Protect method performs the appropriate operation and
securely protects the data. Ciphertext data produced by this method
can only be deciphered by the Unprotect method.
The purposes parameter is an optional list of reasons that can lock
the ciphertext to a specific purpose. This parameter lets you isolate
cryptographic operations performed by different subsystems within an
application. A malicious client should not be able to get the result
of one subsystem's Protect method and feed it as input to another
subsystem's Unprotect method, which could compromise application
security. The purposes parameter helps ensure that protected data can
only be used by the component that originally generated it.
Applications should make sure that each subsystem uses a unique
purposes list.
so can anyone shed some light on what cipher this uses to "protect" the data sent into it? Any best practice on usage would be useful too. When is this appropriate to use, when not, etc.?

The machineKey Element specifies which algorithms and keys to use for encryption.
Following on from the comment, the documentation for the MachineKey class includes the following snippet that leads to the machineKey Element
The MachineKey class provides methods that expose the hashing and encryption logic that ASP.NET provides. For information about which encryption and hashing algorithms ASP.NET uses, and the key values that it uses with them, see machineKey Element (ASP.NET Settings Schema).

Related

Create keys without writing them to disk?

Preamble
I was digging deep into the .Net x509certificate2 and x509certificate objects noticed that both the certificate classes serialize the private key to disk by default due to the verifiable use of Persist-Key options in the constructors of the x509certificate2 and x509certificate classes using a default option set for CspProviderFlags that does not include CspProviderFlags.CreateEphemeralKey. This is verifiable via any number of web sites that show the source for .Net as well as with a copy of resharper should you choose to do it yourself.
Looking further, In fact these .Net objects simply seem to be wrappers for a central old style crypto32.dll cryptographic context. What worries me about this is that looking at the code deeper I find that it seems to explicitly look in an on-disk file storage for public and private keys in the getters and setters for the PublicKey field on the x509certificate2 and x509certificate object.. despite the fact that I would otherwise expect them to only exist in memory. Based on this knowledge it seems to store my private key in this storage even if I do not want it to do so, because the constructor does not allow you to change this option and turn it off based on the constructor list I am seeing when I look at the documentation; So if you set() or get() from the PrivateKey field it is really just collecting it from this file store behind the scenes.
Reason for my question
I think that being forced to leak my private key to the file system - even temporally - is a huge security issue so I do not want to do it. I also do not trust the certificate store. Even if you disagree with me, I personally believe that being forced to serialize my private key to disk even if I do not intend to do so is a huge security issue, so I do not want to do it.
Goal
My current goal is to simply be able to generate RSA public and private X509 keys in C# that can be used on windows without needing to be forced to write them to the hard disk as part of the creation process, and I am not finding many valid options as all of the ones I can find seem to have either hidden gaps or publicly known issues.
The goal is not to never write them to disk, it is just to not do so unless its with code I have written and know to be secure to make sure they are fully encrypted at rest; ie, it should not do so unless I explicitly ask for it after the keys themselves have been fully encrypted.
Goal tldr;
In short: I want to write secure software on windows using C# to generate a 509 certificate that doesn't force me to export, import, or otherwise leak my private key to the file system as part of the certificate creation. I want to be able to create my own X509Certificates on windows using as little third party code as possible.
Options I have considered
The Standard .Net types as stated have been looked at in depth and found to be lacking due to the above issues. I just don't have enough access to the internal CSP settings as the constructors and access do not expose them, and the defaults used as what I would personally consider to be insecure.
The Bouncy Castle library looked like a good option at first, but it actively exposes my public and private keys to the file system just lie the normal .net types do when it converts them to the standard .Net types since these objects store things behind the scenes without asking BC if its ok first..
I attempted to find a crypto32.dll p-invoke option that would allow me to not serialize my keys, only to find that all I could find did exactly that even when I did not want them to. And finding data on it was very difficult so I mostly just looked at the source code only to find that it didn't seem to like me trying to not store keys.
I am unable to find any other options despite spending several days researching this topic. Even Stack Overflow says to use BC or the native typesd in most cases; yet that doesn't solve my problem.
Question
How would I best create my own X509 Certificates without doing any of the following as I feel they are all security issues:
The use of makecert.exe requires I allow my process execute rights on the server so it can start a process; thats a security issue waiting to happen. Not to mention, I cant audit the code and I am willing to bet its still storing the keys in the cert store even If I do not want them to be.
The use of the C#/.Net x509certificate2 and x509certificate objects serialize a generated public key to disk by default via its calls to the Certificate Store so that's not an option; The goal is to do things in a secure manner, and so the idea of all the private keys I'm generating being stored on disk for just anybody to access them doesn't leave me with good feelings. ANd its very hard to find data on the cert store; thus I cant validate its security and have to consider it not a valid option.
The use of third party libs such as Bouncy Castle creates update scenarios and the possibility of a third party that has to be trusted, creating an even larger attack surface; and sadly they all use the same conversions that are affected by what I am personally calling the "hidden private key store" issue of them trying to play nice with the standard System.Security.Cryptography API by using the same objects that have this leaking key issue. So If in general we want to keep the system as secure as possible.. that sort of leak is not an option.
Without going super-low-level (or disabling paging altogether) you can't guarantee that your private key material is never written to disk, because it can always be paged out. Even then, on a system that supports hibernation your key will be present in the hibernation file.
The crypt32 key storage mechanism uses DPAPI (user or machine scoped, depending on your import flags and/or flags in the PFX) to encrypt the key material at rest. So while it is involving the filesystem, it isn't "stored on disk for just anybody to access them"; unless they're running as you, or have permission to access the system keys.
Like others have said, if you are this concerned and not willing to trust anyone/any outside APIs then you are going to have to use a lower level language than .Net. .Net is a great RAD type language, but if you don't trust the machine you are running on, you will want the lowest level environment you can achieve.
C would be a good option.

What is the best way to protect sensitive data in the code?

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.
And here is the question: are there ways to encode/protect such data so that it cannot be read along with decompiled code?
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.
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...
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:
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.
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.
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.
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.
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.
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
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.
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/

Adding a custom hashAlgorithmType in C# ASP.NET

I've got a page that I need to beef up security on. I'm using the built-in MembershipProvider functionality and currently have hashAlgorithmType set to SHA512. I've got the BCrypt.NET library (http://bcrypt.codeplex.com/) and it seems to be working nicely when I call its functions from code but I'm having the worst time figuring out how to create the appropriate <cryptographySettings> section in Web.config to let me create a hashAlgorithmType.
I found the following code snippet on the web:
<mscorlib>
<cryptographySettings>
<cryptoNameMapping>
<cryptoClasses>
<cryptoClass MyHash="MyHashClass, MyAssembly
Culture=neutral, PublicKeyToken=a5d015c7d5a0b012,
Version=1.0.0.0"/>
<cryptoClass MyCrypto="MyCryptoClass, MyAssembly
Culture=neutral, PublicKeyToken=a5d015c7d5a0b012,
Version=1.0.0.0"/>
</cryptoClasses>
<nameEntry name="System.Security.Cryptography.HashAlgorithm"
class="MyHash"/>
</cryptoNameMapping>
<oidMap>
<oidEntry OID="1.3.36.3.2.1" name="MyCryptoClass"/>
</oidMap>
</cryptographySettings>
</mscorlib>
Call me a noob if you want, but I apparently don't have the requisite knowledge to make heads or tails of that. All I need is a method to tell the membership provider that something like <hashAlgorithmType="bcrypt"> corresponds to something like string hashed = BCrypt.HashPassword(password, BCrypt.GenerateSalt(12)); to encrypt and bool matches = BCrypt.CheckPassword(candidate, hashed); to decrypt. Please tell me there's an easy answer. I can rewrite the login system from scratch if I have to, but I already have a working implementation that I'd really like to just change the hashing algorithm of.
I believe that config pattern must be applied to the machine.config file; which isn't necessarily a great move if you need to be able to roll out this code easily.
You can programmatically register the BCrypt encryption primitive(s) with the CryptoConfig class through a call to AddAlgorithm with a name that can you can later use.
So long as the BCrypt hash provider implements HashAlgorithn you should be able to register it simply, you can also test this by calling HashAlgorithm.Create(string) with the name you use to verify that it builds the algorithm correctly.
The membership provider should then be able to use it without issue.
Here's a good article about this topic.
Update
(deep breath) - apologies if this is tl;dr.
Okay, so having read around about BCrypt.Net's password hashing - it's obviously good, and follows accepted practise. It is, also, completely incompatible with how the HashAlgorithm class works because it requires additional state in order to work it's magic, and can't simply be extended to implement the HashAlgorithm contract.
Thus, you have a choice - stick with MembershipProvider and use SHA512 as you already are - you're talking about beefing up security on a page, so I'm thinking there might be issues with authentication itself, rather than the storage of passwords (which must, of course, still be done properly) - so consider simply making sure that the authentication traffic is sent over HTTPS if it's not already.
Using password stretching algorithms blindly has its own issues - see the responses to my own recent SO on this topic - if you do the stretching on the server you could potentially end up causing a DOS attack on the site!
The other option is, as you've suggested, to manage the membership entirely yourself - thus you can use whichever types you want and manage the necessary storage of the password information manually.
My sites now use an algorithm very similar to PBKDF2 that I lifted from Bruce Schneier and Niels Ferguson's book Practical Cryptography, for which I use 512 bit random salt and SHA512 (storage is cheap) plus many thousands of iterations to hash a clear text. The server benchmarks itself once per appdomain to establish 'levels' of protection that equate to millisecond ranges - thus over time newly hashed passwords will receive a constant level of protection even if the hardware improves. The library is standalone, too, and I've been able to deploy it to SQL Server 2008 R2 to provide CLR SPs if we have to generate password records at the SQL level.
But this only protects the passwords - you then need an authentication mechanism that can protect the act of logging in; plus another system for protecting the authenticated session token (.Net's Authentication Cookie system is actually pretty good for this).
Following on from that SO I have now spent a week implementing SCRAM primitives that I have then plugged into my MVC web services for authentication, and I plan to do the same to enable login from the web browser using Javascript (locking out non-JS clients). The key there being the client is doing all the hash calculations; thus I've stuck to SHA because mature implementations are readily available in practically any environment (e.g. we have iPhone apps too - and they need to authenticate as well).
In your case, however, with the existing investment in the MembershipProvider, I would consider 512 bits of SHA plus SSL plus Asp.Net's auth cookie sufficient - so long as the database is really secure(!) and you've got no SQL injection holes in the site.
For a BCrypt implementation of HashAlgorithm, see my answer to a similar question here.
You would need to create a signed assembly with the sample code in my answer, and then modify your settings as needed:
<cryptoNameMapping>
<cryptoClasses>
<cryptoClass MyHash="BCryptHasher, MySignedAssemblyName
Culture=neutral, PublicKeyToken=<my public key for singed assembly>,
Version=1.0.0.0"/>
</cryptoClasses>
<nameEntry name="System.Security.Cryptography.HashAlgorithm" class="MyHash"/>
</cryptoNameMapping>
To be able to register a custom hashAlgorythmType, the first thing you need is a type that actually implements HashAlgorythm. If BCrypt implements it, it's your lucky day, but apparently it does NOT implement it, so this is your problem.
There is really no work around for it, as implementing HashAlgorithm is a requirement for being able to register it like this.
So what you are going to need to do is either write a wrapper around BCrypt to implement HashAlgorithm, or, of this is not possible, modify BCrypt itself to implement it.
Unless you are really-really lucky and BCrypt is written in a way that easily lend itself to such a modification, it can require some non-trivial efforts.

Encrypt a file base upon a pregenerated "key" C#

I'm trying to determine the best course of action to implement a simple "licensing" system with a partner of mine. The concept is:
Generate an encrypted value based upon several internal hardware components. Have the customer send this value to us which we will implement into our key generator. Once we have that, we add any other restrictions on the license (user, expires, etc.). From there we generate a file which we send to the customer they can add to their installation and voila, happy people about.
I have the first part all done. My next part is trying to figure out which encryption methodology I would need to use. I already know Symmetric Encryption is pretty much the only route I can take. Most of the information I have found involves .NET already creating a key from its own internal methods.
That's a bit of background, my question is: "Which encryption method could I use which would allow me to encrypt the restrictions based upon the "id" I was given from the customer's computer?" I'm writing this in C# by the way.
You say you know you need symmetric encryption but you would be wrong. With symmetric encryption the code checking the license has to have access to the secret, which means if your code is reverse engineered someone can not only figure out where to remove the checks, they can generate and sell license keys that are indistinguishable from the ones you make.
Use asymmetric encryption, or a secure hash. And don't try to use the customer-specific hardware information as the key, instead prepend or append it to the other data. You're essentially creating an access control/rights/privileges list file coupled with a message authentication code to verify its source (you).
I recently did something very similar to this. I used AES to generate a value based on a private key using an internal customer id or order number as the IV used to encrypt the value.
Instead of an order number you can use some form of checksum from your first step so it's not something that's stored as the IV. That way if the file is hosed or if they transfer the software to a new computer - either way will invalidate the file.
Something you might be careful of though is how closely you tie the installation/license to the hardware. You don't want to punish a legitimate user simply because they upgraded their motherboard.

How do you hide an encryption key in a .NET application?

I'm developing an intranet application (C#) that uses some data (local to the web server) that we'd like to keep private. This data is encrypted (AES) using a legacy data repository. We can't totally prevent physical access to the machine.
Clearly, we're never going to have perfect security here. However, we want to make it as hard as possible for anyone to gain unauthorized access to the data.
The question is how best to store the key. Encrypting it based on some machine specific ID is an option, but that information would be readily available to anyone running a diagnostic tool on the machine.
Encoding it in the application is an option (it's a one off application). However, .NET assemblies are pretty easy to decompile. So, would it be best to obfuscate it, use an encryption launcher, compile it?
Or is there an option I'm missing?
Just so we're clear, I know it's pretty much a lost cause if someone is determined, but we're looking to make it as hard as possible within the constraints.
Encryption is built into the .NET configuration system. You can encrypt chunks of your app/web.config file, including where you store your private key.
http://www.dotnetprofessional.com/blog/post/2008/03/03/Encrypt-sections-of-WebConfig-or-AppConfig.aspx
Speaking in obfuscation terminology, what you are after is called constant hiding, i.e. a means by which you transform a constant into, say, a number of functions and calculations that are executed at runtime to re-materialize said constant.
This still falls within the domain of obfuscation, however, and is susceptible to either code extraction, where the attacker simply maps out the code relevant to this constant, and runs it in a separate application to retrieve the value; or dumping the application's memory at the right point in order to scan it for the desired value.
There is another, slightly more advanced method of hiding crypto keys in particular, called White-box cryptography, which employs key-less ciphers through essentially generating a cipher function from a given key, baking them together. As the name suggests, this method has been devised to be resilient even in a white-box attack scenario (the attacker has access to the bytecode and is able to inspect and manipulate the executable at runtime).
These are both quite advanced methods of achieving security through obscurity, and it might be worth considering alternative models which do not force you to do this in the first place.
If somebody can just attach a debugger to your program, there is absolutely nothing you can do. They won't have to figure out your config, disassemble your app, etc. All they have to do is run the app - watch it use the key - bingo.
Obfuscation is of no help under those conditions.
The best defense is to use hardware to protect the key - which will do the crypto but not give out the key itself (and is sometimes hardened against attacks such as probing the wires, exposing the memory to low temperatures/radiation/other novel stuff). IBM do some appropriate stuff (google IBM-4764) but it's not cheap.

Categories