通过PKCS#11获取CryptoAPI公钥



在我的C++程序中,我使用CryptoAPI创建了一个公钥/私钥对。

CryptGenKey(eTokenProv,ENCRYPT_ALGORITHM,CRYPT_EXPORTABLE,&k1)

密钥存储在电子令牌中。是否可以使用 PKCS#11 获取公钥?使用以下搜索模板进行搜索后,将找到先前创建的私钥:

    CK_ATTRIBUTE private_search[] = {
       {CKA_PRIVATE, CK_TRUE, sizeof(CK_BBOOL)}
    };

如果我将CKA_PRIVATE设置为 CK_FALSE,则无法获取公钥。我还尝试了其他属性。有没有办法做到这一点?

编辑

正如 owlstead 所建议的那样,我尝试从上一个会话中创建的密钥的模数和公共指数开始创建一个公钥(在 CAPI 中,或者,仅用于此测试,在 PKCS11 中(。我从这些缓冲区中的私钥中获得了模数和公共指数:

CK_BYTE  modulus[128]; //if 1024bit
CK_BYTE  publicExponent[4]; //4 Byte, according to public key blob

但是当我尝试使用以下说明使用密钥创建一个新的公共时:

CK_ATTRIBUTE publicKeyTemplate[] = {
    {CKA_TOKEN, &yes, sizeof(true)},
    {CKA_WRAP, &yes, sizeof(true)},
    {CKA_ENCRYPT, &yes, sizeof(true)},
    {CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)},
    {CKA_MODULUS, &modulus, sizeof(modulus)},
    {CKA_PUBLIC_EXPONENT, &publicExponent, sizeof(publicExponent)}
CK_MECHANISM mechanism = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };
rv = (*functions->C_GenerateKeyPair) (session, &mechanism, publicKeyTemplate, 6, privateKeyTemplate, 6, &hPublicKey, &hPrivateKey); 

我收到错误"无效模板"。概率是模数,因为没有它,我可以创建一个密钥对。我使用函数C_GenerateKeyPair,但我只对公钥感兴趣。我省略了私有模板。这里有什么问题?

CKA_PRIVATE根本不表示私钥。

当 CKA_PRIVATE 属性为 TRUE 时,用户可能无法访问该对象,直到用户 已通过令牌身份验证

相反,您应该查找值为 CKO_PUBLIC_KEYCKO_PRIVATE_KEY 的属性,例如 CKA_CLASS ,可能使用其他属性来进一步过滤结果。

如果您找不到任何CKO_PUBLIC_KEY那么我认为它要么不是在令牌中生成的(密钥已导入,请检查是否设置了CKA_LOCAL(。或者,它可能仅创建为会话对象。最后它可能已被删除。

请注意,RSA 私钥通常包含公共指数,因此您仍然可以仅从私钥对象构造公钥(当然,使用模数和公共指数(。

在设置指向CK_BYTE数组的指针时,删除CK_ATTRIBUTE中的引用符号 - 在您的情况下为模数

CK_ATTRIBUTE publicKeyTemplate[] = {
    {CKA_TOKEN, &yes, sizeof(true)},
    {CKA_WRAP, &yes, sizeof(true)},
    {CKA_ENCRYPT, &yes, sizeof(true)},
    {CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)},
    {CKA_MODULUS, modulus, sizeof(modulus)},
    {CKA_PUBLIC_EXPONENT, &publicExponent, sizeof(publicExponent)}

我还没有测试过你的代码,但是通过设置以下模板并调用C_GetAttributeValue,我能够成功获得CK_OBJECT_HANDLE(私钥/公钥(的模数:

CK_BYTE         modulus[128];
CK_ATTRIBUTE    Modulus = { CKA_MODULUS, modulus, sizeof(modulus) };
if ((rv = (*p11FunctionList->C_GetAttributeValue)(hSession, hPrivKey /*hPubKey*/, &Modulus, 1)) == CKR_OK)
{
  // do something with obtained modulus
}

生成的私钥-公钥对生成如下:

CK_OBJECT_HANDLE    hPrivKey, hPubKey;
CK_BBOOL            bTrue   = TRUE;
CK_ULONG            mod_bits = 1024;
CK_MECHANISM        GenMechanism = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };         
CK_ATTRIBUTE        GenPubTemplate[] = {
            { CKA_MODULUS_BITS, &mod_bits, sizeof(CK_ULONG) },
            { CKA_PUBLIC_EXPONENT, "x01x00x01", 3 },
            { CKA_TOKEN, &bTrue, sizeof(CK_BBOOL) },
            { CKA_ID, (CK_CHAR_PTR)szKeyID, strlen(szKeyID) } }; // szKeyID is a const char *
        CK_ATTRIBUTE         GenPrivTemplate[] = {
            { CKA_TOKEN, &bTrue, sizeof(CK_BBOOL) },
            { CKA_PRIVATE, &bTrue, sizeof(CK_BBOOL) },
            { CKA_SENSITIVE, &bTrue, sizeof(CK_BBOOL) },
            { CKA_ID, (CK_CHAR_PTR)szKeyID, strlen(szKeyID) } }; // szKeyID is a const char *
// hSession is a CK_SESSION_HANDLE of an opened & logged in session 
if ((rv = (*p11FunctionList->C_GenerateKeyPair)(hSession, &GenMechanism, GenPubTemplate, 4, GenPrivTemplate, 4, &hPubKey, &hPrivKey)) == CKR_OK)
{
  // Now get the modulus of a the private / public key as described above 
}

虽然这已经为想要这样做的其他人解决了这个问题,但我们已经为CryptoAPI创建了一个基于PKCS#11的包装器,你可以在这里找到它:

https://github.com/PeculiarVentures/pvpkcs11

有了这个,您可以使用本机PKCS#11接口访问存储在CryptoAPI中的密钥以及证书。

最新更新