Nevertheless I have recently determined sufficient information about the latest format to read and write PVK files in a form that is acceptable to various tools that use PVK files.
This information was not derived using anything other that freely documented structures and the examination of some sample files. There is as always some guesswork involved so this may not be totally accurate just yet.
This description refers to the PVK format used by Xenroll version 5.102.1680.101 and signcode version 5.101.1663.1 it may well be incomplete or inaccurate if other versions are used.
The file consists of three sections. A header, a salt (optional) and the private key in either encrypted or unencrypted form.
DWORD magic;
DWORD reserved;
DWORD keytype;
DWORD encrypted;
DWORD saltlen;
DWORD keylen;
magic is a magic number it appears to be 0xb0b5f11e for the current version.
The meaning of reserved is unknown. It was always zero in the files I tested.
keytype is the type of key. It is 1 for a key exchange key and 2 for a signature key. It must be consistent with the type of key defined in the aiKeyAlg field in the BLOBHEADER structure (CALG_RSA_KEYX and CALG_RSA_SIGN).
encrypted is zero for an unencrypted private key and 1 for an encrypted private key.
saltlen is the salt length. It is zero for an unencrypted key file and 0x10 for an encrypted key file.
keylen is the length of the key data.
In the unencrypted file the whole PRIVATEKEYBLOB is unencrypted. For the encrypted case just the BLOBHEADER structure is unencrypted.
In both cases the encrypted private key is encrypted using 128 bit RC4. The key is derived using salted SHA1.
In the strong version the key is derived by taking the first 16 bytes (128 bits) of SHA1(salt+password) where the + sign denotes concatenation and the password is a null terminated ASCII string (the null character is not included in the derivation).
The weak version is the same except the key is derived by taking the first 5 bytes (40 bits) of SHA1(salt+password) followed by 11 zero bytes.
Since the first four bytes of the magic field of the encrypted RSAPUBKEY part of the encrypted data are always "RSA2" this can be used to check the password is correct.
There is no apparent indication as to which key derivation algorithm is used. My sample code tries both and looks for the "RSA2" string on the decrypted data.
This behaviour is apparently anomalous because the signing tools just use the default CSP and cannot recognize both formats automatically. However if you have applied the domestic patch and the registry fix then you can still access the weakly encrypted files by using the -p option to specify the CSP. That is you would use: -p "Microsoft Base Cryptographic Provider v1.0". If it doesn't work then double check the spelling!
The latest source is here as a gziped
tar
file. The .bin extension is to avoid server problems.
OpenSSL 0.9.9 will include integrated support for PVK conversion.
If there are any problems with these binaries producing errors on
what
appear to be valid PVK files then mail
me at the address on my contact page.