Question

I have an existing application that is written in C++ for Windows. This application uses the Win32 CryptoAPI to generate a TripleDES session key for encrypting/decrypting data. We're using the exponent of one trick to export the session key out as a blob, which allows the blob to be stored somewhere in a decrypted format.

The question is how can we use this in our .NET application (C#). The framework encapsulates/wraps much of what the CryptoAPI is doing. Part of the problem is the CryptAPI states that the TripleDES algorithm for the Microsoft Enhanced Cryptographic Provider is 168 bits (3 keys of 56 bits). However, the .NET framework states their keys are 192 bits (3 keys of 64 bits). Apparently, the 3 extra bytes in the .NET framework is for parity?

Anyway, we need to read the key portion out of the blob and somehow be able to use that in our .NET application. Currently we are not getting the expected results when attempting to use the key in .NET. The decryption is failing miserably. Any help would be greatly appreciated.

Update:

I've been working on ways to resolve this and have come up with a solution that I will post in time. However, still would appreciate any feedback from others.

Was it helpful?

Solution

Intro

I'm Finally getting around to posting the solution. I hope it provides some help to others out there that might be doing similar type things. There really isn't much reference to doing this elsewhere.

Prerequisites

In order for a lot of this to make sense it's necessary to read the exponent of one trick, which allows you to export a session key out to a blob (a well known byte structure). One can then do what they wish with this byte stream, but it holds the all important key.

MSDN Documentation is Confusing

In this particular example, I'm using the Microsoft Enhanced Cryptographic Provider, with the Triple DES (CALG_3DES) algorithm. The first thing that threw me for a loop was the fact that the key length is listed at 168 bits, with a block length of 64 bits. How can the key length be 168? Three keys of 56 bits? What happens to the other byte?

So with that information I started to read elsewhere how the last byte is really parity and for whatever reason CryptoAPI strips that off. Is that really the case? Seems kind of crazy that they would do that, but OK.

Consumption of Key in .NET

Using the TripleDESCryptoServiceProvider, I noticed the remarks in the docs indicated that:

This algorithm supports key lengths from 128 bits to 192 bits in increments of 64 bits.

So if CryptoAPI has key lengths of 168, how will I get that into .NET which supports only supports multiples of 64? Therefore, the .NET side of the API takes parity into account, where the CryptoAPI does not. As one could imagine... confused was I.

So with all of this, I'm trying to figure out how to reconstruct the key on the .NET side with the proper parity information. Doable, but not very fun... let's just leave it at that. Once I got all of this in place, everything ended up failing with a CAPITAL F.

Still with me? Good, because I just fell off my horse again.

Light Bulbs and Fireworks

Low and behold, as I'm scraping MSDN for every last bit of information I find a conflicting piece in the Win32 CryptExportKey function. Low and behold I find this piece of invaluble information:

For any of the DES key permutations that use a PLAINTEXTKEYBLOB, only the full key size, including parity bit, may be exported. The following key sizes are supported.

Algorithm Supported key size

CALG_DES 64 bits

CALG_3DES_112 128 bits

CALG_3DES 192 bits

So it does export a key that is a multiple of 64 bits! Woohoo! Now to fix the code on the .NET side.

.NET Import Code Tweak

The byte order is important to keep in mind when importing a byte stream that contains a key that was exported as a blob from the CryptoAPI. The two API's do not use the same byte order, therefore, as @nic-strong indicates, reversing the byte array is essential before actually trying to use the key. Other than that, things work as expected. Simply solved:

Array.Reverse( keyByteArray );

Conclusion

I hope this helps somebody out there. I spent way too much time trying to track this down. Leave any comments if you have further questions and I can attempt to help fill in any details.

Happy Crypto!

OTHER TIPS

Ok, forget the last answer I can't read :) You are working with 3Des keys not RSA keys.

I worked on a bunch of code to share keys between .NET, CryptoAPI and openssl. Found a lot of good example code here for doing the key conversions:

http://www.jensign.com/JavaScience/cryptoutils/index.html

There is some 3des stuff in some of those examples, but it was related to openssl -> .NET iirc.

I also just looked back over the RSA key code and one thing I notice I am doing is using Array.Reverse() on all the key parts of the RSA key (D,DP,DQ,InverseQ,Modulus,P,Q) i guess to convert endian. I remember that being non-obvious when first tackling the problem.

Hope some of that helps. Good luck.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top