ASP.NET Security Consultant

I'm an author, speaker, and generally a the-way-we've-always-done-it-sucks security guy who specializes in web technologies and ASP.NET.

I'm a bit of a health nut too, having lost 50 pounds in 2019 and 2020. Check out my blog for weight loss tips!

How the Security Framework Implements Cryptography

Published on: 2018-07-02

In a previous post, I went over some basics of cryptography. I did this partly because I think it's an area for growth for many developers (as it was for me before I really started getting into serious security), but it was also a prelude to this article—how the ASP.NET Security Enhancer implements cryptography. So without further ado…

Key Storage

Why start with key storage rather than symmetric encryption or hashing? Quite simply, the quality of your key storage can make or break your encryption security. If you store your keys in an insecure way and hackers get your keys, then you might as well have stored your data in plain text. If you lose your keys, then you might as well have not stored your data at all, because it will be gibberish to you. These difficulties, combined with the fact that the best ways to store keys are outside of your website and database, are quite possibly why Microsoft didn't even try to hide personal information in the user table in the default version of their websites.

Perhaps the most secure way to store cryptographic keys is to use a Hardware Security Module (HSM), which is hardware that is built to store cryptographic keys securely. If you have one, please use it, and implement your own version of INCGApplicationKeyStore in your system. If not, then your next best option is to store keys in a file on the server or perhaps in the registry, but you won't always have access to these in the cloud. (Here again, if you do, please implement it on your own and use it with the ASP.NET Security Enhancer.) The next best thing that I could think of was to store the keys in the database, but with the following precautions:

  • Put the key storage table in a separate schema. You should be sure that the permissions of the database user that accesses the user data does not have access to the key store and vice versa.
  • Store the key names in hashed format with a salt stored in the web.config file, then store the key values encrypted with a key stored in web.config.

I thought that this would be the best balance between security and ease of use (and setup). Keys are stored in the database, which is less than ideal, but they're stored in a way where any hacker with the information would have a very hard time doing anything useful with it. But please do look into HSM or encrypted file options if these are available to you.

One note about the key store: I do not intend programmers to call the key store directly. The encryption and hashing services will take care of calling the key store for you.

Please note that you are responsible for backing up your own keys! If you lose them, you will not be able to decrypt your data, and I cannot help you!

Encryption

In all honesty, I have a hard time getting the default encryption algorithms to work in .NET. There are too many cryptic error messages, I'm annoyed that I have to work with byte arrays instead of strings, and it doesn't support some things I think it should, such as CTR mode for AES. (I'll get to that in a minute.) So I implemented an encryption service that is much easier to use. It has two functions:

  • Encrypt(String toEncrypt, String encryptionKeyName)
  • Decrypt(String toDecrypt, String encryptionKeyName)

Both of these functions take care of the rest for you. It will call the key storage service to get (and generate if needed) cryptographic keys for you. It will also generate appropriate IVs (initialization vectors) for you and store them with the string. It also stores a marker at the beginning of the string telling the decryptor what algorithm to use. If you update the encryption algorithm at some point, there won't be any need to re-encrypt the existing data with the new algorithm; the service will refer to the marker and be backwards compatible.

One caveat worth noting if you are encrypting large chunks of data like files or paragraphs of text: the framework uses AES (the Advanced Encryption Standard, which is the standard algorithm for encrypting data as of this writing), and as mentioned earlier, the .NET framework does not support the best modes for doing this. If you find yourself needing to encrypt large documents or relatively long strings, please reach out to me and I'll see what I can do to implement a different algorithm in the framework for this purpose.

Hashing

There are two separate services for hashing in the framework, the INCGHashService for general-use hashing and the INCGPasswordHasher for password hashing. Here's how the two differ:

General Hashing

The INCGHashService has one method:

  • Hash(String plainText, String saltNameInKeyStore, HashAlgorithm algorithm)

This service will hash your text, and manage the salts for you in the key store. (As with encryption, the keys will be created for you if they aren't present in the database.) Generally it is acceptable to store salts in plain text, but the service will encrypt them in the key store for extra security.

Password Hashing

Generally, you won't need to worry about this service, since both Microsoft's and my security framework's SignInManager and UserManager encapsulate the password logic for you. But a few notes about the password hashing service:

  • Like encryption, the password hasher has a marker indicating which algorithm was used to hash the password, making it easy to upgrade the algorithm but remain backwards compatible with old data.
  • A new salt is generated with each password and is stored with the password itself. This makes it virtually impossible for hackers to easily find passwords. They would have to brute force each password individually if they got the data in the database.
  • If you need backwards compatibility with an old format, implement the INCGLegacyPasswordHasher and add it as a service—the authentication managers will handle the rest.

Asymmetric Encryption and Digital Signatures

There are too many practical limitations on the use of asymmetric encryption, so I didn't implement that in the framework. As with anything, if there is enough of a demand, I can certainly put it in.

I did, however, put in support for creating digital signatures. Here's a summary of how to use this service:

  1. Generate a public/private key pair using the GenerateKeys() method.
  2. Put your private key in a safe place!
  3. Create a signature using the CreateSignature(String textToSign, String keyInXMLFormat) method using the private key generated in step 1.
  4. You can later verify the signature using the VerifySignature(String textToVerify, String oldSignature, String keyInXMLFormat) method. It will return true if the text has not been altered.

Final Thoughts

The cryptography services were created with the idea of making storing data securely as easy as possible. Please do take note of the areas that don't meet all needs, and reach out if there is anything you would like added. I'm always adding features to the framework, I just need to know what is needed!

And of course, if you are interested in using this framework to make your encryption easier, please contact me today!