How can this class library help me?
Have you ever encountered situations where your application needs access to sensitive information in order to function? Connection strings... impersonation passwords... API keys... I'm sure you can think of other examples.
Certificate-based encryption is an excellent way to protect such information because it greatly reduces the "Turtles all the way down" problem. Sure, you can implement a quick-and-dirty AES encryption method, but where are you going to store the encryption key? Not the source code; lord knows who else has access to THAT! So, why not encrypt the encryption key? Well, where are you going to store the key to unlock the key? ...And on and on it goes!
Leveraging asymmetric encryption and the built-in security of the Windows Cryptographic API (CAPI) is a far better approach to managing encryption keys than hiding them in plain site. CAPI natively ensures that your private keys are protected by many layers of encryption, most of which are completely transparent to you as the key owner.
The X509Crypto library allows you to easily leverage certificates and keys from either the LocalMachine or CurrentUser CAPI store. Certificates are identified to the library via their thumbprint value:
In a nutshell, if you know how to copy and paste text, then you can use this library!
OK, but certificates are a pain. How do I get one?
You can create one easily using one of the following available utilities:
- The command-line interface (Documentation)
- The all-new X509Crypto PowerShell Module
The Powershell module is a bit sleaker & takes advantage of the PowerShell pipeline. It does not support impersonation, though.
If you need to encrypt secrets in the context of service accounts that don't have interactive login rights, our custom CLI is the better option as the "impersonate" verb will allow you to execute X509Crypto commands in a quasi-interactive interface. The only caveat is that the service account must have batch logon rights on the system.
You can use this library with a standard TLS (formerly known as SSL) certificate from any of the well known providers (such as Entrust, Verisign, Comodo and GoDaddy). Your organization may also have it's own internal PKI, from which you should easily be able to obtain a compatible certificate. The only prerequisites are that the certificate must be non-expired and it must contain Key Encipherment in its Key Usages extension:
Alright, I'm sold. How can I use X509Crypto to protect secrets and programmatically retreive them in my .NET projects?
In this simplistic example, we're going to encrypt an API key, store the encrypted API key in an X509Alias and then recover the API key in an example C# program:
Encrypting a secret using X509Crypto
1. Install the X509Crypto PowerShell module:
The X509Crypto PowerShell module can be installed from the PowerShell Gallery.
> Install-Module X509Crypto
# ...Or if you are not an admin:
> Install-Module X509Crypto -Scope CurrentUser
2. Use the New-X509Alias cmdlet:
This cmdlet instantiates a new X509Crypto Alias (which stores encrypted secrets). In this example, we'll be performing cryptographic operations using a certificate located in the currently logged in user's keystore, so we'll pass "user" in the required -Location parameter. If we wanted the secret to be recoverable by the SYSTEM account, we would pass "system" instead. We don't have a previously-existing certificate and key pair, so we'll execute the cmdlet without the optional -Thumbprint parameter, which will trigger the creation of a new certificate that will be automatically associated with this X509Alias.
> $Alias = New-X509Alias -Name myvault -Location user
New alias "myvault" committed to "user" X509Context
Thumbprint: B31FE7E7AE5229F8186782742CF579197FA859FD
3. Use the Protect-X509CryptoSecret PowerShell cmdlet to encrypt a secret
In this example, we'll be storing an API authentication key in the X509Alias "myvault". Secrets are stored in X509Aliases as key/value pairs, so we'll assign the identifier "apikey" to this new secret.
> $Alias | Protect-X509CryptoSecret -Id apkikey -Input '80EAF03248965AC2B78090'
Secret "apkikey" added to X509Alias "myvault4" in the user X509Context
3. Reference the secret in your program
Once you have an X509Alias established with your secret(s) added, it is trivial to retreive them in your program with the Org.X509Crypto nuget package installed:
using Org.X509Crypto;
namespace SampleApp
{
class Program
{
static void Main(string[] args)
{
// Instantiate the X509Alias object, referencing the "myvault" alias in the CurrentUser context
using (var Alias = new X509Alias(@"myvault", X509Context.UserReadOnly))
{
// Recover the plaintext secret "apikey" as plaintext in a string variable
string apiKey = Alias.RecoverSecret(@"apikey");
// Use the secret before leaving the "using" block so that it will be garbage-collected promptly
MyApi.Connect(apiKey);
}
}
}
}
Down in the weeds
For your reference, the contents of the X509Alias are saved as a base64-encoded file in the logged-in user's AppData directory:
C:\Users\mikeb>type c:\users\mikeb\AppData\Local\X509Crypto\myvault.xca
eyJDb250ZXh0Ijp7fSwiTmFtZSI6...
If you decode the file, you'll find an object in json format. The secrets contained in the X509Alias remain unreadable, of course:
{
"Context":{
},
"Name":"myvault",
"Secrets":[
{
"Key":"apikey",
"Value":"AAEAABAAAAAHjn58kwkbA4SDinqSVjWHY..."
}
],
"Thumbprint":"B31FE7E7AE5229F8186782742CF579197FA859FD"
}
What if I get stuck?
I'm always happy to help you get the most out of this class library! Send any questions or comments to mikebrunocissp@gmail.com.