Skip to main content

X509 certificate encryption fun :-)

Recently I needed to encrypt data on a server and allow a limited number of service accounts the ability to decrypt that data so it was as safe as possible.

The approach I took to achieve this was by using a X509 certificate and it's ability to allow you to encrypt information via it's public key and decrypt that information through the private key.

The key parts of this approach are:

- Create a certificate

- Ensure the KeySpec of the certificate is set up correctly to allow for encryption e.g. "KeyExchange" or "None" if you are doing this via PowerShell

- Set the security on the private keys so only specific user accounts can access it and decrypt information encrypted via the public key.


Step 1 - Create a certificate to use

The easiest way to get a quick example going is via PowerShell to create a dummy root certificate and the one we will use for encrypting and decrypting.


$rootCert = New-SelfSignedCertificate -CertStoreLocation Cert:\LocalMachine\My -DnsName "BlogSuperRootCA" -TextExtension @("2.5.29.19={text}CA=true") -KeyUsage CertSign,CrlSign,DigitalSignature
$testCert = New-SelfSignedCertificate -CertStoreLocation Cert:\LocalMachine\My -DnsName "SignedByBlogSuperRootCA" -KeyExportPolicy Exportable -KeyLength 2048 -KeyUsage DigitalSignature,KeyEncipherment -Signer $rootCert -KeySpec "None"

Step 2 - Secure your private keys

Once you have the certificate created you can then easily secure the private key via PowerShell

$accounts = @("someDomain\userA","someDomain\userB")
$fileName = $testCert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName
$path = "$env:ALLUSERSPROFILE\Microsoft\Crypto\RSA\MachineKeys\$fileName"
$acl = Get-Acl -Path $path
$acl.SetAccessRuleProtection($True, $False)
                                                                
foreach($account in  $accounts)
{
  Write-Output "Adding  $account"           
  $rule = New-Object System.Security.AccessControl.FileSystemAccessRule($account,"Full","Allow")
  $acl.AddAccessRule($rule)
}

Set-Acl -Path  $path -AclObject $acl

Now we have our certificate and the permissions all set we can move onto the C# code which enables the encryption and decryption!


Step 3 - Use the certificate to encrypt and decrypt

Once you have the certificate and the permissions setup for who has access to the private key it's very straight forward to do the encryption and decryption. I've included below a simple test that should enable you to test this out yourself without much trouble.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;

namespace Blog.Michael.Ciba.CertEncryptionTesting
{
    [TestFixture]
    public class Given_a_valid_certificate_with_a_private_key_we_can_access
    {
        private X509Certificate2 _certificate;

        [OneTimeSetUp]
        public void Using()
        {
            const string BlogCertificateSubject = "CN=SignedByBlogSuperRootCA";
            using (var store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
            {
                store.Open(OpenFlags.ReadOnly);

                _certificate = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName,
                        BlogCertificateSubject, false)
                    .Cast()
                    .FirstOrDefault();

            }
        }

        [Test]
        public void It_will_encrypt_and_decrypt_the_text_and_not_throw_an_exception()
        {
            // Arrange
            const string TextToEncrypt = "Some random text to encrypt";

            // Act
            var encryptedText = GetEncryptedTextBasedOnCertificatePublicKey(_certificate, TextToEncrypt);
            var actualDecryptedText = GetDecryptedTextBasedOnCertPrivateKey(_certificate, encryptedText);

            // Assert
            Assert.That(encryptedText, Is.Not.EqualTo(TextToEncrypt));
            Assert.That(actualDecryptedText, Is.EqualTo(TextToEncrypt));
        }

        public static string GetEncryptedTextBasedOnCertificatePublicKey(X509Certificate2 certificate,
            string textToEncrypt)
        {
            var rsa = certificate.GetRSAPublicKey();
            var bytesToEncrypt = Encoding.UTF8.GetBytes(textToEncrypt);
            var encryptedBytes = rsa.Encrypt(bytesToEncrypt, RSAEncryptionPadding.OaepSHA512);
            var encryptedText = Convert.ToBase64String(encryptedBytes);
            return encryptedText;
        }

        public static string GetDecryptedTextBasedOnCertPrivateKey(X509Certificate2 certificate,
            string textToDecrypt)
        {
            var rsa = certificate.GetRSAPrivateKey();
            var bytesToDecrypt = Convert.FromBase64String(textToDecrypt);
            var decryptedBytes = rsa.Decrypt(bytesToDecrypt, RSAEncryptionPadding.OaepSHA512);
            var decryptedText = Encoding.UTF8.GetString(decryptedBytes);
            return decryptedText;
        }
    }
}

See that wasn't too complex was it?

Comments

Popular posts from this blog

SharePoint - Search Service Application (SSA) - Attempted to perform an unauthorized operation

On my current project I needed to adjust and add some search mapping via SharePoint's Central Administration web site. This should have been very straight forward as you have the ability to add managed properties and mappings easily via the UI. However, when I went to save my changes I got the error "The settings could not be saved because of an internal error: Attempted to perform an unauthorized operation". Now this was very confusing as I am administrator on the server and added into all of the correct SharePoint groups. I also tried the same action via PowerShell and got the same error.   After a few hours of research and head scratching I managed to get to the bottom of the problem which is the way my user account had been added as an administrator to the server. In the company I work for to make it easier to manage the administrators on a server a group is created in active directory called " servername_admins ". This group is added to the local administra...

Sharepoint feature activation and strange timeouts....

  So I have been meaning to write a blog entry for some time now and at last I have finally manage to drag together a few coherent sentences and get the ball rolling. So what topic have I picked to start my blogging experience with at Conchango? Well Sharepoint of course! Anyway down to business and the reason for the post is that the other day I had to deal with an issue surrounding a timeout when activating a feature via the "ManageFeatures.aspx" page within the Windows Sharepoint Services (WSS) user interface. The feature itself was somewhat of a beast and did a lot of work within the "FeatureActivated" method behind the screens setting up lists, creating content etc which meant it was going to take a long time to complete.  So a timeout issue? Well as it turns out yes. The problem is that activating a feature via the "ManageFeatures.aspx" page means that the request to activate the feature is handled by asp.net and as such i...

Debugging hidden features in SharePoint

Well it’s been a while since I have done a blog entry so I thought I would ease myself back into them with a small post about how to debug a hidden feature. As everyone knows in SharePoint you have the ability to make a feature hidden which means it doesn’t show up via the UI. This is useful if you don’t want users deactivating or activating a feature in the wrong site etc and making a mess of things. However, to debug these features I until quite recently use to switch the “hidden” attribute back to “false” so I could activate the feature via the UI and attached the debugger to the “w3wp” to see what gremlins were making my code go up in a cloud of smoke. However I learnt the other day about the “Debugger.Launch();” method which enables you to launch a debugger for your code and attach to the relevant process to enabling debugging (see http://msdn.microsoft.com/en-us/library/system.diagnostics.debugger.launch.aspx ). Now all I need to do when I want to debug my hidden featu...