.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