.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