Saturday, October 27, 2012

Transferring Data Securely - Part 1 - Digital Signatures

It has been a while since my last post... in part b/c I have been so busy and in part b/c I really didn't have a good topic.  Recently I had to build an encryption library for work and I decided that there weren't any good posts showing how to securely transfer data using cryptography in .Net - so, I have decided to write a multi-part post that will cover how to sign a message, encrypt it using Symmetric cryptography (with a random key), and then Asymmetrically encrypt the random key.  I am not going to get into a whole lot of theoretical detail about Asymmetric cryptography, digital signatures, or Symmetric cryptography and why this is important - there are many great sources out there for this.  One thing I want to point out up front... I am not handling exceptions the way I would for a robust library.  I have not included exception handling so that I could focus on the code you need to understand - I have, however, tried to add comments in places where you might consider adding exception handling code.  Remember for all of the code snippets below to adjust the namespaces accordingly to match your workspace.

Ok, let's get started... step 1 will be to create a test certificate that you can use for testing all of this out.  Open the "Developer Command Prompt" which is located in the Visual Studios program folder.  If you can't find that, google makecert.exe and pvk2pfx.exe to find out where they are located and then copy them to a location where you can save certificates.  Once you have the command prompt open and have access to makecert and pvk2pfx, issue the following commands.  You can adjust the dates as desired, but keep the names (or adjust the name in the test code we will write below).

makecert.exe -sv TestCertificate.pvk -n "CN=TestCertificate" 
     TestCertificate.cer -sky Exchange -pe 
     -b 10/27/2012 -e 10/27/2020 -r

pvk2pfx.exe -pvk TestCertificate.pvk -spc TestCertificate.cer 
     -pfx TestCertificate.pfx
After executing the makecert command, a window will pop up asking for a password... you can chose to use one or just select none.  If you do select a password, remember it... you will need it to install the cert.  After executing these commands, you should have 3 files: TestCertificate.pfx, TestCertificate.pvk, and TestCertificate.cer.  Double click on TestCertificate.pfx and follow the instructions to install it.  If you added a password when running makecert, enter it when it tells you to.  You can keep all the default options, but I tend to select the option to "make the key exportable" - that is up to you.  Once your certificate is installed, it is time to add some code.

Next up, let's add a utility that we will use for other cryptographic work... I have created a folder named "encryption" where my classes will go... it is up to you how you want to organize your code.  Add a new class file called CryptoUtilities.cs and add the following code:

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

namespace BlogSandbox.encryption
{
    public class CryptoUtilities
    {
        // make sure certName passed in starts with 'CN='
        public static X509Certificate2 GetCertFromStore(
                                    StoreName storeName, 
                                    string certName)
        {
            X509Store store = new X509Store(storeName);
            store.Open(OpenFlags.ReadOnly);

            X509Certificate2Collection currentValidCerts =
                store.Certificates.Find(
                    X509FindType.FindByTimeValid, 
                    DateTime.Now, 
                    false);

            X509Certificate2Collection certs = 
                currentValidCerts.Find(
                    X509FindType.FindBySubjectDistinguishedName, 
                    certName, 
                    false);

            // check certs count and throw error if 0 if desired
            return certs[0];
        }
    }
}
Adjust the namespace as needed.  I have a couple recommendations here.  In this code, I am first finding all the valid certs that have not expired and then I am finding the certificate with "certName".  Since I am using "FindBySubjectDistinguishedName", the certName must start with "CN=".  I recommend that you add some code to check certName to see if it starts with CN= and if not, add it.  Also, I recommend that you check certs to make sure it has one (if you don't you will get an IndexOutOfRangeException - I think it is cleaner to instead throw a CryptographicException with a message indicating the cert could not be found, but it is up to you).  Ok, now that we have the ability to find the certificate, let's write the digital signature code.

Create a new class called DigitilSignature.cs and add the following code to it:

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;

namespace BlogSandbox.encryption
{
    class DigitalSignature
    {
        private const string DefaultAlgName = "sha1";

        public static byte[] SignMessage(
                                StoreName storeName,
                                string certName,
                                string algName,
                                byte[] message)
        {
            X509Certificate2 x509Cert = 
                CryptoUtilities.GetCertFromStore(
                                            storeName, 
                                            certName);
            RSACryptoServiceProvider digSigProvider = 
                x509Cert.PrivateKey as RSACryptoServiceProvider;

            // if no provider and no private key 
            // check for and throw exception
            return digSigProvider.SignData(
                message, 
                CryptoConfig.MapNameToOID(algName));
        }


        public static byte[] SignMessage(
                                StoreName storeName,
                                string certName,
                                byte[] message)
        {
            return SignMessage(storeName,
                               certName,
                               DefaultAlgName,
                               message);
        }

        public static bool VerifySignature(
                        StoreName storeName,
                        string certName,
                        string algName,
                        byte[] message,
                        byte[] signature)
        {
            X509Certificate2 x509Cert =
                CryptoUtilities.GetCertFromStore(
                                            storeName,
                                            certName);
            RSACryptoServiceProvider digSigProvider =
                x509Cert.PrivateKey as RSACryptoServiceProvider;

            // if no provider and no private key 
            // check for and throw exception
            return digSigProvider.VerifyData(
                message,
                CryptoConfig.MapNameToOID(algName),
                signature);
        }

        public static bool VerifySignature(
                        StoreName storeName,
                        string certName,
                        byte[] message,
                        byte[] signature)
        {
            return VerifySignature(storeName,
                               certName,
                               DefaultAlgName,
                               message,
                               signature);
        }
    }
}
Let's walk through these methods starting with SignMessage.  The first thing you will notice is that I there are 2 methods, one that takes in "algName" and one that does not (but instead uses a default "sha1").  This is to provide support for Cryptographic Agility... I will be adding another post to go over this in the future.  For now, let's just use "sha1".  As an aside, the certificate we created will only support "sha1" and I need a whole post just to go over creating a cert that you can use for sha2 algorithms.  Another thing you will probably notice is that there is some shared code in the sign/verify methods, feel free to abstract at will.  One thing I would like to mention is the method call CryptoConfig.MapNameToOID(algName) - this is for Cryptographic Agility and it internally maps the algorithm name "sha1" to an object identifier that the system understands as a SHA1 algorithm.  In a future post, I will try to expand on this some more and show you how you can map different names and make it possible to use very generic names (like "HashAlgorithm") that you can map to your preferred algorithms (particularly important for government work where you must use SHA2 based algorithms).  The only real difference between the sign and verify methods is that the sign method takes a message and an algorithm and then returns the signature as a byte[] while the verify takes the message, an algorithm, and the signature we obtained in the sign method and returns a true or false indicating if the signature is valid.

Ok, the final code for this post is a simple method to execute a test on this code.

using BlogSandbox.command;
using BlogSandbox.encryption;
using System;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;

namespace BlogSandbox
{
    class Program
    {
        static void Main(string[] args)
        {
            string textToSign = "Sign this text";
            byte[] signature = DigitalSignature.SignMessage(
                        StoreName.My,
                        "CN=TestCertificate", 
                        Encoding.UTF8.GetBytes(textToSign));
            bool verified = DigitalSignature.VerifySignature(
                        StoreName.My,
                        "CN=TestCertificate", 
                        Encoding.UTF8.GetBytes(textToSign),
                        signature);
            Console.WriteLine("Verified? " + verified);
            Thread.Sleep(20000);
        }
    }
}
That's it... you now have a small library that you can use to sign data.  To make the library more robust, I recommend adding methods to support using "stream" based messages so that you can handle files directly.  Additionally, you will probably want to handle exceptional cases, which I have not done here for brevity and clarity.

In the next few blog posts (I will try to wrap them up over the next few weeks) I will show you how to handle the symmetric encryption of your message, followed by the asymmetric encryption of the keys.  Once I have done that, I will go over how to put it all together to create a single message that you can send across the network/intranet/internet.

Wednesday, October 3, 2012

Information Security - Book Review

As part of the requirements of maintaining my Certified Secure Software Lifecycle Professional (CSSLP) certification from ISC2, I have to earn 15 Continuing Professional Education (CPE) credits per year.  As part of this requirement, I wrote a book review to be published on their site and I thought I would share it here as well for anyone interested.  I hope it is useful to someone.

Title: The Basics of Information Security
By: Jason Andress
Publisher: Syngress
Publication Date: August 1, 2011
Print ISBN-13: 978-1-59749-653-7
Web ISBN-13: 978-1-59749-654-4

Review (Overall rating 4 out of 5):

Jason Andress’ book, “The Basics of Information Security”, provides a high level overview of the primary risks security specialists need to be aware of.  The book is well written and discusses the issues in more of a conversational style, which keeps the reader engaged.  As the title of the book indicates, the content is higher level and does not delve deeply into the specifics about how to specifically mitigate security flaws, but rather focuses on making the reader more aware of the issues.  The book provides real world examples that help the reader to understand each of the security domains much more clearly.  Additionally, at the end of each chapter, there are several exercise questions that helps ensure the reader has a solid understanding of the topic.

While all of the chapters are necessary some of the topics are much more interesting and contained more useful content than others.  Specifically, the chapter discussing Physical Security, while relevant, probably could have been shorter as many of the points discussed were rather obvious.  Additionally, the book would have been better if the author delved a little more deeply into some of the more interesting content, like Cryptography.  While this book’s focus was not specifically on software development, it would have been much better if it included a chapter on the Software Development Life Cycle and how important it is to build security in from scratch as opposed to bolting it on later.

One of the most informative chapters in this book was the one on “Authorization and Access Control”.  This chapter outlined several approaches and provided a very clear and understandable discussion about them.  In particular, the author did an exceptional job clearly explaining the Bell-LaPadula, Biba, and Brewer and Nash models of access control.  Many authors provide the details, but do not provide examples that make these concepts understandable, but this author does and he does it well.

Overall, this book provides a really good high level, conceptual overview of information security and the issues security professionals are faced with on a day to day basis.  The author’s conversational style is very engaging and keeps the reader focused on the topic; he is careful not to provide too much mundane detail which would just cause the reader to lose interest.  This book is a great read for anyone that is just starting to study for the CSSLP as it provides a very nice overview of the topics in the exam.  This book does not dig in too deeply to the topics, however, and should only be the start of one’s study.  That said, the book does provide examples at the end of each section that will help ensure that the reader understands the topics, which will help anyone studying for the exam to ensure they have a solid understanding of the material.  Additionally, this book is a great read for anyone that thinks they might want to start a career in information security as it outlines the main topics and provides the reader with a sense of what they could expect in such a job.

Followers