Page 1
Page 2
Page 3
Page 4
Key Management
The Crypto Api treats symmetric (session)
and asymmetric (pub/priv key pair) differently. Session
keys only live in memory, so if you need to reuse one you
have to handle that yourself. One option might be using
CryptProtectData and CryptUnprotectData to save it to disk.
For key pairs, each named container stores 2 key pairs,
1 for exchanging (e.g. encrypting) and 1 for signing. For
PROV_RSA_FULL, you get 2 RSA key pairs because it can be
used to encrypt and sign. For PROV_DSS_DH, you get DSA for
signing and Diffie-Hellman keys for key exchange. Also,
these key pairs are stored in the registry, so when you
are importing and exporting keys, you have to be careful
not to step on your own keys. To handle this, all session
keys use their own named container, and the key pairs for
that container will end up being 'exponent-of-one' keys
so that the session keys can be exported in the clear. Therefore,
those pub/priv keys should never be used for exchanging
or signing. For RSA and DSA, my implementation uses the
users key by default. I do this for speed, because it takes
some time to generate a key each time. There is a static
property that can be set to make it gen a key each time.
Also, when importing keys, it uses a different container
so as not to destroy the users key. Sometimes I get an error
BAD_KEY_STATE when using the user key (mostly with PROV_DSS_DH
provider). To get around this, I have a ResetKeyState method
in the Key class. This would destroy your key pairs and
create new ones, so you might want to export them to Xml
and save them locally using ProtectData and then import
them later on. To complicate things even more, if you are
sending a message that needs to be signed and encrypted,
then you should use different key pairs. So for RSA (which
can do both), encryption uses the EXCHANGE key pair, while
signing uses SIGNATURE key pair. Better yet, use RSA for
encryption and DSA for signing.
Performance
SmartPhones have processors as low
as 132 megahertz, so we have to think about speed.
When starting out to code this, I was either going to pInvoke
the CryptoApi, or port the Mono implementation that is all
managed. My assumption was that the cost to pInvoke the
CryptoApi was going to be less than doing the ciphers in
all managed code. Also, the different algorithms will perform
differently. MD5 is supposed to be faster than SHA1. RC4
is supposed to be much faster than RC2 (although RC4 doesnt
exist on the full framework). Symmetric algorithms are much
faster than asymmetric algorithms, so the rule of thumb
is to encrypt the data with symmetric, then encrypt the
symmetric key (which is small) with an asymmetric algorithm. Next,
dont sign big chunks of data; instead take a hash of the
data and just sign the hash. Finally, if you are encrypting
a large chunk of data with a symmetric key, then you will
want to display progress to the user. My wrapper does not
currently allow for the data to be encrypted in chunks,
but it could be extended to do so because the CryptoApi
does. If performance is a real big issue, an eVC wrapper
could be written which exposes methods consisting of multiple
CryptoApi calls to reduce the number of pInvokes required
for each cipher.
Conclusion
So we now have interoperability between
the desktop and the device with almost all of the System.Security.Cryptography
namespace. MACTripleDES seems to be broken on CE, so use
HMACSHA1 instead. PasswordDeriveBytes is partially compatible
with RC2 / SHA1, and DES / MD5 is close (except for salting);
although this might not be compatible on other platforms
outside of the CryptoApi. Finally, the CryptoApi providers
on the SmartPhone offer no way to do the hashes (SHA 256/384/512)
nor Rijndael (symmetric) encryption.
Books
I'm a crypto wannabe, so I referred
to these books during writing this
- Cryptography for Visual Basic, Bondi
- Cryptography (RSA Security's Official
Guide), Burnett and Paine
- Programming .NET Security, Freeman
and Jones
- Writing Secure Code, Howard and
LeBlanc
- .NET Security, Bock and Stromquist
...
- Practical Cryptography, Schneier
and Ferguson
- Java Cryptography, Jonathon Knudsen
- and the CryptoApi documentation
Source
- bNb.Sec (CE class lib) wrapper over
CryptoApi, with helper classes
- System.Security.Cryptography (CE
class lib) wraps bNb.Sec for full framework interoperability
- spCrypt (SmartPhone WinForm) client
unit testing
- /wsCyrpto (ASP.NET Web Service)
web service test harness for compatibility with desktop
Future
I wrote this with the intention of asking
for volunteers to help move it into OpenNetCF.org workgroup
to continue work on it. With the MS announcement that they
will be adding Cryptography to .NETcf, I'm less interested,
but could be persuaded otherwise? Also, I have a follow
up article (why I wrote this library in the 1st place)
that will be released within a couple of weeks ...
Previous Page