.NET Key types: AT_SIGNATURE & AT_KEYEXCHANGE


.NET crypto can make use of the underlying CryptoAPI persistent key 
storage (key container) infrastructure, but the documentation:
 Generating Keys for Encryption and  Decryption

is not very clear on some details.

The following are some details that may be useful to those with some CryptoAPI
background:

- default RSACryptoServiceProvider rsa = RSACryptoServiceProvider() constructor
  generates new RSA public/private transient (memory resident) key-pair each time invoked.

- if rsa.PersistKeyInCsp = true is used with the default RSACryptoServiceProvider
  constructor, a random key container name, prepended with "CLR" is persisted to
  protected CryptoAPI key storage.

- overloaded RSACryptoServiceProvider rsa = RSACryptoServiceProvider(CspParameters cp)
  creates (or reuses) a persistent key container with the name specified
  in cp.KeyContainerName

- for this overloaded constructor, if the only CspParameters field specified is
  KeyContainerName, the RSA key-pair generated (or re-used) is the key pair of
  type AT_KEYEXCHANGE (compare below to Strong Name generated keypairs AT_SIGNATURE).  
  CryptoAPI key containers associated with the Microsoft CSPs can contain
  two types of key-pairs (keyspec): AT_KEYEXCHANGE and AT_SIGNATURE which the
  WinCrypt.h header file defines as 1 and 2 respectively.

- although not clearly documented, it appears that the key type is specified
  using the property:  CspParameters.KeyNumber with:
     CspParameters.KeyNumber= 1  (AT_KEYEXCHANGE)
     CspParameters.KeyNumber= 2  (AT_SIGNATURE)
  and with AT_EXCHANGE being the default KeyNumber value.

- if a RSACryptoServiceProvider is instantiated twice, once with KeyNumber=1 and then
  2, supplying the same cp.KeyContainerName, then the same CryptoAPI keycontainer
  will be populated with 2 sets of keys in the same named key container. These keypairs
  have different public/private key values. This is similar to the  PSDK sample code 
 for generating a key container with both Signature and Exchange key pairs:


- persistent keypairs created by .NET RSACryptoServiceProvider(CspParameters) are always 
  marked as "exportable"; there is no support in .NET 1.1 to mark the keys as non-exportable.
  Compare this to the PSDK tool makecert.exe which by default creates AT_SIGNATURE keypairs marked
  as non-exportable, with support via the -pe switch to mark the keys as exportable.
 

CryptoAPI, encoded and .NET Public Keys:
-----------------------------------------
The term "public key blob" is used a bit loosely in docs. 
This should help clarify:

(1)The CryptoAPI PUBLICKEYBLOB 
is NOT an ASN.1 encoded key structure. Key modulus and exponent
are stored in little-endian order within a PUBLICKEYBLOB.

(2) The "Public Key" viewable in any of:
     Certificate properties panel
     .NET   X509Certificate.GetPublicKey(
     CAPICOM oCert.PublicKey().EncodedKey
are identical ASN.1 encoded key public key values. Key modulus and exponent
are stored in big-endian order.

(3) The public key embedded in assembly meta-data by strong-naming, and viewable by any of:
     Ildasm.exe as assembly manifest metadata ".publickey = (.." 
     sn.exe -e
     sn.exe -p
     secutil.exe -s
are identical. This public key representation is a shallow "wrapper" around 
the CryptoAPI PUBLICKEYBLOB, (1) above, as defined in the StrongName.h  file 
with signature algorithm, hash algorithm and remaining (CryptoAPI) blob size.

For a given public key, all representations above include the same public key modulus,
key exponent plus other details particular to the representation.

For example, the following shows the byte-size of each public key format above,
for an RSA 1024 bit key pair:
  CryptoAPI public key blob:    148 bytes
  ASN Encoded pub. key  blob:   140 bytes
  .NET strong-name public key:  160 bytes   (12 bytes + 148 byte-CryptoAPI blob)


Sn.exe, CryptoAPI PRIVATEKEYBLOB and .NET keypair files:
--------------------------------------------------------
When .NET keypairs are generated using the Strong Name tool:
   sn.exe -k  "mysigkeys.snk"
a new keyfile holding a new randomly generated 1024 bit
RSA AT_SIGNATURE keypair is created.
The format of this file is an unencrypted CryptoAPI PRIVATEKEYBLOB.

This keypair can be imported into a CryptoAPI keycontainer using:
  sn.exe  -i ...
in which case the key is marked as non-exportable within CSP storage. 

Currently strong-nameing only supports AT_SIGNATURE keys. Therefore, key-container 
keys generated via .NET with RSACryptoServiceProvider(CspParameters cp) and
without cp.KeyNumber specified, will result in the default AT_KEYEXCHANGE keytype.
The AT_KEYEXCHANGE key will fail when attempting to Strong-Name sign at compile time.
However, an undocumented registry setting enables changing the strong name
key type to AT_KEYEXCHANGE via:
   HKLM\\SOFTWARE\\Microsoft\\StrongName\\KeySpec  (DWORD)
which supports values 1 (KEYEXCHANGE) or 2 (KEYSIGNATURE .. the default).


Michel I. Gallant
neutron@istar.ca