密钥结构的转换
一个程序同时用到CryptoAPI和openssl,如何将CryptoAPI中的密钥的句柄HCRYPTKEY转换成openssl的RSA结构?
如果HCRYPTKEY表示RSA公钥,则可以利用CryptExportKey导出公钥,根据MSDN介绍的Public Key BLOBs格式把modulus和pubexp转换为RSA里对应的域就行了。
如果HCRYPTKEY表示RSA私钥,且私钥可以导出,可以利用CryptExportKey导出私钥,并填充RSA里对应的域。
如果HCRYPTKEY表示RSA私钥,且私钥不可以导出,需要实现一个RSA_METHOD,这样才可能使用openssl的RSA结构实现解密和签名。
将密钥结构进行转换举例:
要把PFX文件导入到EKey的问题,可以分两步来做第一步是从PFX文件中获取到私钥和证书,第二步是把私钥和证书写入EKey。
第一步可以有两种方法:一种是使用openssl来分解PFX文件来获取,这样可以获得PKCS#1格式的RSA私钥。另一种是使用PFXImportCertStore导PFX文件到一个临时的certstore,注意要设置私钥可导出标志,然后在certstore里找到带私钥的证书导出其私钥。导出的私钥的格式MSDN private key blobs中有说明,大致如下
BLOBHEADER blobheader;
RSAPUBKEY rsapubkey;
BYTE modulus[rsapubkey.bitlen/8];
BYTE prime1[rsapubkey.bitlen/16];
BYTE prime2[rsapubkey.bitlen/16];
BYTE exponent1[rsapubkey.bitlen/16];
BYTE exponent2[rsapubkey.bitlen/16];
BYTE coefficient[rsapubkey.bitlen/16];
BYTE privateExponent[rsapubkey.bitlen/8];
注意字节序是little-endian。
可能有些系统不支持PFXImportCertStore函数
第二步也可以有两种方式一种是使用明华提供的ECLib库把私钥和证书写入EKey。第二种方法是用CryptAcquireContext创建个新容器,再用CryptImportKey把私钥导入可能需要修改导出的私钥的格式,指定是导入到AT_KEYEXCHANGE还是AT_SIGNATURE位置。最后把证书写入容器即可。
下面的代码进行了初始化:
rsa->e = BN_new();
rsa->n = BN_new();
rsa->p = BN_new();
rsa->q = BN_new();
rsa->dmp1 = BN_new();
rsa->dmq1 = BN_new();
rsa->iqmp = BN_new();
rsa->d = BN_new();
CryptExportKey导出的各个参数是little-endian的,而BN_bin2bn要求的输入是big-endian的,需要将参数反转一下使用BN_bin2bn。