Jump to navigation

Poupou's Corner of the Web

Looking for perfect security? Try a wireless brick.
Otherwise you may find some unperfect stuff here...

Weblog

Mono.Security follow-up

Here's a little update on Mono.Security assembly since it's official introduction.

SymmetricTransform

It's easy to miss but actually none of the class derived from SymmetricAlgorithm (like DES, TripleDES, Rijndael or RC2) encrypt nor decrypt anything. To do so you must create an encryptor (or a decryptor), which are classes implementing the ICryptoTransform interface. Those classes do the "real job".

DES des = DES.Create (); ICryptoTransform enc = des.CreateEncryptor (); // now encrypt using a CryptoStream ICryptoTransform dec = des.CreateDecryptor (); // now decrypt using another CryptoStream

In Microsoft implementation all symmetric algorithms returns a CryptoAPITransform instance, with the notable exception of Rjindael, which is a managed implementation. The CryptoAPITransform is the class that P/Invoke into CryptoAPI to encrypt, or decrypt, the supplied data with the selected options. The transforms can be used as-is but are generally used with a CryptoStream.

Now notice the with the selected options. Apart from the key and IV (optional parameters to the Create[En|De]cryptor methods) what other options are there ?

Well every block cipher transforms has to be able to support, on their own, different mode of operation (like CBC, CFB ...) and padding (e.g. PKCS #7). This is clearly a design flaw in .NET cryptography - as every cryptographic algorithm implementer must develop it's own solution to the same problem. The current design is (most probably) attributable to the fact that much of the framework is based on CryptoAPI (which do not expose modes or padding independently from an algorithm implementation).

However that does mean that every supported algorithm in Mono had to provide such support itself. That didn't make sense and luckily didn't happen. What happened was SymmetricTransform - which until a few days ago this class was well hidden inside Mono's corlib.

In Mono, all [*] SymmetricAlgorithm Create[En|De]cryptor algorithms returns an instance of a class derived from SymmetricTransform. The only thing required in the derived class is to implement the abstract EBC (Electronic Code Book) method - which is the most basic mode of operation. All other modes are implemented using ECB and all the padding methods are algorithm agnostic.

So by including SymmetricTransform as a public class into Mono.Security assembly it becomes much easier to implement new block ciphers (e.g. Twofish) without worrying about modes and padding.

[*] Actually the ARC4Managed class, already present in Mono.Security assembly, didn't and wont use the SymmetricTransform because it is a stream cipher (while others are block ciphers). Stream ciphers works on bytes (not blocks) so they don't need padding or modes.

BigInteger

Another nice thing was hidden since a long time in corlib, BigInteger - an optimized version (thanks again Ben) from Chew Keong TAN. This class is used to implement Mono's DSA and RSA implementations (and the soon to be included Diffie-Hellman).

PKCS12

As promised last time, support for decoding PKCS #12 is now included in Mono.Security.X509 namespace. This is a requirement to support version 1.2 of the .NET framework. PKCS #12 encoding should follow soon.

TLS

Lastly, but very worthy, Carlos has just updated it's TLS implementation to support client-side certificates. Good job Carlos!


2/9/2004 21:08:19 | Comments | Permalink

CryptoStream - is 3rd time a charm ?

This is the first time I see a framework class being used so differently by so many (or so few) people. Everyone seems to use it in a slightly, or in some case very, different way.

For example I like to think that we decrypt when we read from a stream (like a file) and encrypt when we write into it. However the inverse is also perfectly valid. That is, for example, we encrypt when reading from a (memory) stream and write the encrypted result into another (file) stream.

Actually the real difficulty wasn't in the different uses but about the assumptions that I made when implementing CryptoStream - most of them based on the way I used the class.

A few things can be a lot easier with a simpler model, like read/decrypt and write/encrypt, but get more complex when you have to permit all cases. Most problems come from the fact that we must pad the last block of data before encrypting it. This requires that we know the length of the stream. So using Stream.Length and Stream.Position made sense and worked (somewhat) well until someone tried a NetworkStream (which doesn't support either Length nor Position). A similar problem occurs during decryption, as we need to remove the padding of the last block.

The solution is to give very little real control over the actual reading from / writing to the stream. CryptoStream now acts like a buffer to ensure that there is something available when you read in it (but was most probably already encrypted/decrypted in a previous call). The same is true for writing into the stream - this is why it is so important to call FlushFinalBlock (so that CryptoStream knows you finished and can pad the last block).

Well it took me 3 rewrites to get it right or so I like to think (so please don't hesitate to prove me wrong and report any failures into bugzilla) and the last one was quite a surprise. On a positive note each rewrite resulted in a simpler implementation than the previous one.

Warning: I've run into some quite scary stuff when looking for sample code using CryptoStream. Most of it doesn't involve CryptoStream but the key and/or IV generation used as the ICryptoTransform. If you care enough about your data to encrypt it you should take care about how you do it. Conclusion: stick to samples from well-known sites (who review submissions) or well-know authors. Source code containing questions are generally not a good answer!


2/8/2004 23:27:38 | Comments | Permalink

Long time no blog

Parts of the long time were due to:

  • xmas vacations;
  • my last days working for Motus Technologies;
  • an (wrong) ISP password reset that was far more complicated than required;
  • my first days of work for Novell Ximian.

Vacations were fun (and well planned). My last days at Motus were not like I planned (and definitively not fun for me - and probably much worse for many more people). The password reset was just a remainder that a simple problem can be resolved by many phone calls, many questions and many hours waiting (frustrating - but at least I had time to be ;-) without any added value to the customer or to the service provider. Finally my first days full-time on Mono:: are just monogasmic - which I thought was a new word but it seems I've been beaten to it, let's just hope we share the same definition ;-).

Best luck wishes to all my late co-workers :-( It's been fun!


2/5/2004 23:04:29 | Comments | Permalink

The views expressed on this website/weblog are mine alone and do not necessarily reflect the views of my employer.