Convert RSA public/private key from XML to PEM format (.NET) (Part 2)

In my previous post I’ve shown how to convert the public key of an XML formatted RSA key to the more widely used PEM format. The only limitation of the solution was that since it utilizes the Cryptographic Next Generation (CNG) algorithms it is usable only on Windows 7 and Windows Server 2008 R2.

So bellow I’ll demonstrate a solution that works under all operating systems. Also as an extra the solution bellow can convert the private key as well 😉 Both the public and the private keys exported by the functions bellow are parsed by OpenSSL!

You can find the compiled source here.

Enjoy!

C#

private static byte[] RSA_OID = 
{ 0x30, 0xD, 0x6, 0x9, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0xD, 0x1, 0x1, 0x1, 0x5, 0x0 }; // Object ID for RSA

// Corresponding ASN identification bytes
const byte INTEGER = 0x2;
const byte SEQUENCE = 0x30;
const byte BIT_STRING = 0x3;
const byte OCTET_STRING = 0x4;

private static string ConvertPublicKey(RSAParameters param)
{
    List<byte> arrBinaryPublicKey = new List<byte>();

    arrBinaryPublicKey.InsertRange(0, param.Exponent);
    arrBinaryPublicKey.Insert(0, (byte)arrBinaryPublicKey.Count);
    arrBinaryPublicKey.Insert(0, INTEGER);

    arrBinaryPublicKey.InsertRange(0, param.Modulus);
    AppendLength(ref arrBinaryPublicKey, param.Modulus.Length);
    arrBinaryPublicKey.Insert(0, INTEGER);

    AppendLength(ref arrBinaryPublicKey, arrBinaryPublicKey.Count);
    arrBinaryPublicKey.Insert(0, SEQUENCE);

    arrBinaryPublicKey.Insert(0, 0x0); // Add NULL value

    AppendLength(ref arrBinaryPublicKey, arrBinaryPublicKey.Count);

    arrBinaryPublicKey.Insert(0, BIT_STRING);
    arrBinaryPublicKey.InsertRange(0, RSA_OID);

    AppendLength(ref arrBinaryPublicKey, arrBinaryPublicKey.Count);

    arrBinaryPublicKey.Insert(0, SEQUENCE);

    return System.Convert.ToBase64String(arrBinaryPublicKey.ToArray());
}

private static string ConvertPrivateKey(RSAParameters param)
{
    List<byte> arrBinaryPrivateKey = new List<byte>();

    arrBinaryPrivateKey.InsertRange(0, param.InverseQ);
    AppendLength(ref arrBinaryPrivateKey, param.InverseQ.Length);
    arrBinaryPrivateKey.Insert(0, INTEGER);

    arrBinaryPrivateKey.InsertRange(0, param.DQ);
    AppendLength(ref arrBinaryPrivateKey, param.DQ.Length);
    arrBinaryPrivateKey.Insert(0, INTEGER);

    arrBinaryPrivateKey.InsertRange(0, param.DP);
    AppendLength(ref arrBinaryPrivateKey, param.DP.Length);
    arrBinaryPrivateKey.Insert(0, INTEGER);

    arrBinaryPrivateKey.InsertRange(0, param.Q);
    AppendLength(ref arrBinaryPrivateKey, param.Q.Length);
    arrBinaryPrivateKey.Insert(0, INTEGER);

    arrBinaryPrivateKey.InsertRange(0, param.P);
    AppendLength(ref arrBinaryPrivateKey, param.P.Length);
    arrBinaryPrivateKey.Insert(0, INTEGER);

    arrBinaryPrivateKey.InsertRange(0, param.D);
    AppendLength(ref arrBinaryPrivateKey, param.D.Length);
    arrBinaryPrivateKey.Insert(0, INTEGER);

    arrBinaryPrivateKey.InsertRange(0, param.Exponent);
    AppendLength(ref arrBinaryPrivateKey, param.Exponent.Length);
    arrBinaryPrivateKey.Insert(0, INTEGER);

    arrBinaryPrivateKey.InsertRange(0, param.Modulus);
    AppendLength(ref arrBinaryPrivateKey, param.Modulus.Length);
    arrBinaryPrivateKey.Insert(0, INTEGER);

    arrBinaryPrivateKey.Insert(0, 0x00);
    AppendLength(ref arrBinaryPrivateKey, 1);
    arrBinaryPrivateKey.Insert(0, INTEGER);

    AppendLength(ref arrBinaryPrivateKey, arrBinaryPrivateKey.Count);
    arrBinaryPrivateKey.Insert(0, SEQUENCE);

    return System.Convert.ToBase64String(arrBinaryPrivateKey.ToArray());
}

private static void AppendLength(ref List<byte> arrBinaryData, int nLen)
{
    if (nLen <= byte.MaxValue)
    {
        arrBinaryData.Insert(0, Convert.ToByte(nLen));
        arrBinaryData.Insert(0, 0x81); //This byte means that the length fits in one byte
    }
    else
    {
        arrBinaryData.Insert(0, Convert.ToByte(nLen % (byte.MaxValue + 1)));
        arrBinaryData.Insert(0, Convert.ToByte(nLen / (byte.MaxValue + 1)));
        arrBinaryData.Insert(0, 0x82); //This byte means that the length fits in two byte
    }

}

The Power of Simplicity

Solving a problem very often results in unnecessary complex solutions. One of the first lessons I learned from my math teacher was to scrap any solution that exceeds a page. She would urge me to start all over and look for simpler way to resolve it. In her world there was always a short and simple solution, it was only a matter of seeing it.
     I find this rule applicable to any type of problem. Only the dimension of the page size changes according to the subject matter. Many believe that finding the simpler and better solution is to “think outside the box”. But in my opinion it is exactly the opposite – to think inside the box. Know the fundamentals of your area of expertise, systematically apply them, and you will find a simple and elegant solution! Isaac Newton did not just discover the gravity when an apple fell on his head (if at all it did). It took him 20 years of hard work to explain gravity!
     In the world of SQL it drills down to deep understanding of the set based nature of SQL and coming up with solution based on that. Thinking like a procedural programmer will not help.

What are the rules to simplicity? There are no rules! I like to use the following quotes as guidelines:

The simplest way to achieve simplicity is through thoughtful reduction.
   John Maeda, The Laws of Simplicity

Make everything as simple as possible, but not simpler.
   Albert Einstein

Let’s illustrate this with one example in SQL. In out sample scenario the request is to retrieve a list of customers who always order the exact same product (regardless of what the product is).  This is a very valid business problem because you may want to send targeted coupons to customers who always buy the same products.
     There are different ways to solve this problem and Listing 1 shows one method. It is very close to describing the solution in plain English: select all customers where the customer has no other orders with different product SKU.

Listing 1
SELECT DISTINCT customer_nbr
FROM Orders AS O
WHERE NOT EXISTS(SELECT *
                
FROM Orders AS O1
                
WHERE O1.customer_nbr = O.customer_nbr
                  
AND O1.sku <> O.sku);

Is this the simplest way to solve the problem? This query is set based but still in a way mimics procedural thinking – examine all other customer orders and check that there is no other order with different product SKU.
     If you think about the set of all customer orders, you will notice that these that we need have repeating attribute values, that is the same product SKU. Applying the MIN and MAX aggregate functions on that attribute will return the same value. Then here is our simplified solution: retrieve all customers that have equal MIN and MAX product SKU on all orders. Listing 2 shows the query.

Listing 2
SELECT customer_nbr
FROM Orders
GROUP BY customer_nbr
HAVING MIN(sku) = MAX(sku);

This is more elegant and simpler solution!  Thinking more about the set of all customer orders you will notice that the distinct count of product SKUs is 1 for the customers in the needed result set. That brings us to another elegant solution:

Listing 3
SELECT customer_nbr
FROM Orders
GROUP BY customer_nbr
HAVING COUNT(DISTINCT sku) = 1;

Pretty and simple, right? Try it next time when you see that two page query!

Convert RSA public key from XML to PEM format (.NET) (Part 1)

Probably the people working with asymmetric cryptography have struggled for a way to convert the XML format of the RSA public key to the more widely used PEM format. Although there is a solution for the reverse transformation (from PEM to XML) on the following address http://www.jensign.com/opensslkey/opensslkey.cs I have not found anywhere a solution to this problem.

So after a bit of reading and examining the code in the above mentioned link I’ve come up with a small code that does the conversion and the resulting key is parsed OK from OpenSSL.

NOTE: You will need to download and use the assemblies from http://clrsecurity.codeplex.com/
NOTE2: The code bellow only works under Windows 7 and Windows Server 2008 R2, because it uses the Cryptographic Next Generation (CNG) that were added only to those operating systems.

C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            RSACng rsa = new RSACng();
            X509Certificate2 cert;
            List<byte> arrBinaryPublicKey = new List<byte>();

            byte[] oid = 
            { 0x30, 0xD, 0x6, 0x9, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0xD, 0x1, 0x1, 0x1, 0x5, 0x0 }; // Object ID for RSA

            //rsa.FromXmlString(xmlFormatedRSAKey);

            cert = rsa.Key.CreateSelfSignedCertificate(new X500DistinguishedName("CN=something"));

            //Transform the public key to PEM Base64 Format
            arrBinaryPublicKey = cert.PublicKey.EncodedKeyValue.RawData.ToList();
            arrBinaryPublicKey.Insert(0, 0x0); // Add NULL value

            CalculateAndAppendLength(ref arrBinaryPublicKey);

            arrBinaryPublicKey.Insert(0, 0x3);
            arrBinaryPublicKey.InsertRange(0, oid);

            CalculateAndAppendLength(ref arrBinaryPublicKey);

            arrBinaryPublicKey.Insert(0, 0x30);
            //End Transformation

            Console.WriteLine();
            Console.WriteLine("-----BEGIN PUBLIC KEY-----");
            Console.WriteLine(System.Convert.ToBase64String(arrBinaryPublicKey.ToArray()));
            Console.WriteLine("-----END PUBLIC KEY-----");

        }

        private static void CalculateAndAppendLength(ref List<byte> arrBinaryData)
        {
            int nLen;
            nLen = arrBinaryData.Count;
            if (nLen <= byte.MaxValue)
            {
                arrBinaryData.Insert(0, Convert.ToByte(nLen));
                arrBinaryData.Insert(0, 0x81); //This byte means that the length fits in one byte
            }
            else
            {
                arrBinaryData.Insert(0, Convert.ToByte(nLen % (byte.MaxValue + 1)));
                arrBinaryData.Insert(0, Convert.ToByte(nLen / (byte.MaxValue + 1)));
                arrBinaryData.Insert(0, 0x82); //This byte means that the length fits in two byte
            }

        }

    }
}

Compiled source available here

It’s a Matter of Style

W riting SQL can be very enjoyable activity. Reading SQL can be also enjoyable (maybe like reading poetry to some), or very unpleasant… How do you write SQL with style that results in eye pleasing and easy to read/understand code? And does it matter?
    Sometimes code writing drills down to concentrating on the task at hand and producing a brilliant piece of code, which looks like this:

Listing 1
select c.customer_name, o.order_amt,
d.qty from customers c left outer join
orders o on c.customer_nbr = o.customer_nbr
left outer join orderdetails d on d.order_nbr =
o.order_nbr and d.sku = 101

Or maybe like this:

Listing 2
SELECT C.CUSTOMER_NAME, O.ORDER_AMT,
D.QTY FROM CUSTOMERS C LEFT OUTER JOIN
ORDERS O ON C.CUSTOMER_NBR = O.CUSTOMER_NBR
LEFT OUTER JOIN ORDERDETAILS D ON D.ORDER_NBR =
O.ORDER_NBR AND D.SKU = 101

While this code performs exceptionally and solves the problem in a very clever way, is it really that good? What happens when the code review/test team gets their turn? Or when you/someone else has to modify it two years from now? To my opinion this code is a very long way from what a real production code should be. And yes, this is very real and it happens every day, even as I type this. Just pay attention on the next code review, or take a look at any online SQL forum (and no, it is not only the people that ask questions, unfortunately  many SQL gurus that know it all would post an answer with similar “example” style).
    How do you make this code look better? The answer is in the four basic principles of design: contrast, repetition, alignment, and proximity. Let’s look how applying these principles of design (which many think are applicable only to graphic design) can lead to stylish and enjoyable code.

Contrast
The idea is to use contrast for elements that a very different. One example is columns and reserved keyword. They are not the same and the code should make that distinction very clear. Let’s apply that:

Listing 3
SELECT C.customer_name...

Here the SELECT keyword is capitalized to differentiate from the lower case column name. Also, the table alias is capitalized to indicate clearly the table source.

Repetition
Repeating the same element styles for all similar items adds consistency and organization throughout code. For example, repeat and maintain capitalization for all keyword, do not mix style in different context of the code. Like the style of the SELECT and FROM reserved keywords in Listing 4.

Listing 4
SELECT C.customer_name... FROM Customers AS C...

This allows to “visualize” the shape of the query code. Now the eye can easily flow from one section of code to the next one and concentrate on each element.

Alignment
Code elements should not be placed arbitrarily on the lines of code. Every code item should have some visual connection with another item in the code.  One example is aligning the start of each clause of the query (SELECT, FROM, WHERE, etc.) on a new line:

Listing 5
SELECT C.customer_name...
FROM Customers AS C...

Alignment creates a clean and pleasing look of the code structure.

Proximity
Code items that relate to each other should be grouped close together. When several items are in close proximity they become one visual unit. Like placing SELECT and column names together on the line, similar for FROM and table names or WHERE and predicates. Listing 6 demonstrates this.

Listing 6
SELECT C.customer_name, O.order_amt...
FROM Customers AS C
LEFT OUTER JOIN Orders AS O...

This makes the code structure very clear and eliminates clutter.

Let’s apply all four principles to the initial query. Here is one way it may look:

Listing 7
SELECT C.customer_name, O.order_amt, D.qty
FROM Customers AS C
LEFT OUTER JOIN Orders AS O
 
ON C.customer_nbr = O.customer_nbr
LEFT OUTER JOIN OrderDetails AS D
 
ON D.order_nbr = O.order_nbr
 AND D.sku = 101;

I added a couple extra styling elements (compared to the original query), can you catch them?

Another form of alignment is this:

Listing 8
         SELECT C.customer_name, O.order_amt, D.qty
          
FROM Customers AS C
LEFT OUTER JOIN Orders AS O
            
ON C.customer_nbr = O.customer_nbr
LEFT OUTER JOIN OrderDetails AS D
            
ON D.order_nbr = O.order_nbr
           
AND D.sku = 101;

There are many different ways to style your SQL. You may agree or disagree with some elements, but the bottom line is this: style matters!