c++ - 使用安全转换生成 RSA 签名并使用 OpenSSL/C++ 验证

标签 c++ cocoa openssl rsa

我正在尝试实现一项功能,其中 Linux 服务器将随机数据连同一些证书信息(如主题或问题)发送到 OSx 客户端,OSx 客户端从钥匙串(keychain)存储中获取证书,根据证书信息进行过滤,提取私钥并用SHA256算法对随机数据进行签名。

然后客户端将 base64 编码证书和签名数据(base64 编码)发送回服务器。 Linux 服务器使用 OpenSSL 库(从证书中获取公钥)来验证签名数据。

我面临的问题是服务器无法验证签名数据,而对于 Windows 客户端,服务器能够验证签名数据。

我在 macOS (10.13.4) 上使用以下安全 API

std::string osxPrivateKey::signData(const uint8_t* pData, uint32_t nDataSize, vector<uint8_t>& aSignature) {
    const char* str = (const char*)pData;
    unsigned char *result = new unsigned char[CC_SHA256_DIGEST_LENGTH];
    CC_SHA256(str, strlen(str), result);

    CFDataRef myData = CFDataCreate(NULL, result, CC_SHA256_DIGEST_LENGTH);
    CFErrorRef error;

    osxObject<SecTransformRef> signer;
    SecTransformRef signerRef = SecSignTransformCreate(m_oKey.get(), &error);
    signer.set(signerRef);

    //SecTransformSetAttribute(signer.get(), kSecTransformDebugAttributeName, kCFBooleanTrue, &error);
    SecTransformSetAttribute(signer.get(), kSecTransformInputAttributeName, myData, &error);
    //SecTransformSetAttribute(signer.get(), kSecInputIsAttributeName , kSecInputIsPlainText, &error);
    SecTransformSetAttribute(signer.get(), kSecInputIsAttributeName , kSecInputIsDigest, &error);
    //SecTransformSetAttribute(signer.get(), kSecInputIsAttributeName , kSecInputIsRaw, &error);
    SecTransformSetAttribute(signer.get(), kSecPaddingKey, kSecPaddingPKCS1Key, &error);
    //SecTransformSetAttribute(signer.get(), kSecPaddingKey, kSecPaddingPKCS5Key, &error);
    SecTransformSetAttribute(signer.get(), kSecEncodeLineLengthAttribute, kSecLineLength64, &error);
    SecTransformSetAttribute(signer.get(), kSecDigestTypeAttribute, kSecDigestSHA2, NULL);

    int digestLength = 256;
    CFNumberRef dLen = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &digestLength);
    SecTransformSetAttribute(signer.get(), kSecDigestLengthAttribute, dLen, &error);
    CFRelease(dLen);

    CFDataRef signature = (CFDataRef)SecTransformExecute(signer.get(), &error);


    unsigned char* signData = new unsigned char[1024];
    int size = CFDataGetLength(signature);
    CFDataGetBytes(signature, CFRangeMake(0,CFDataGetLength(signature)), (UInt8*)(signData));

    char* encodeBase64SignData = new char[1024];
    //internal library to convert binary to base64 encoding
    hc::encodeBase64((const char*)signData, size, encodeBase64SignData, 1023);
    encodeBase64SignData[1023] = '\0';

    delete encodeBase64SignData;
    delete signData;

    return string(encodeBase64SignData);
}

在服务器上,以下代码用于验证签名

bool verifySignature(const EVP_PKEY * pkey, const BLOB & data, const BLOB & signature, size_t signatureLen, DSStr & strErr)
{
    bool     result = false;
    EVP_MD_CTX* ctx = NULL;
    {// scope
        OSSL_CHECK(ctx = EVP_MD_CTX_create());
        const EVP_MD* md = NULL;;
        OSSL_CHECK(md = EVP_get_digestbyname("SHA256"));
        OSSL_CHECK(EVP_DigestInit_ex(ctx, md, NULL) == 1);
        OSSL_CHECK(EVP_DigestVerifyInit(ctx, NULL, md, NULL, (EVP_PKEY*)pkey) == 1);
        if (EVP_PKEY_id((EVP_PKEY*)pkey) == EVP_PKEY_RSA) {
            OSSL_CHECK(EVP_PKEY_CTX_set_rsa_padding(ctx->pctx, RSA_PKCS1_PADDING) == 1);

        }
        OSSL_CHECK(EVP_DigestVerifyUpdate(ctx, &data[0], data.size()) == 1);
        ERR_clear_error();
        OSSL_CHECK(EVP_DigestVerifyFinal(ctx, (unsigned char*)&signature[0], signatureLen) == 1);
        result = true;
    }// scope
OSSL_CHECK_failed:
    if (ctx)  EVP_MD_CTX_destroy(ctx);
    return result;
}

由于我是 macOS 的新手,我不确定我是否遗漏了什么。我非常感谢任何帮助,因为我从一周开始就阻止了这个。

最佳答案

您输入了一个名为 pHash 的参数,然后将其散列到 result 中。如果它已经是一个散列,您已经对其进行了双重散列,这肯定会给您错误的签名。

此外,您使用 strlen(pHash) 作为长度对其进行哈希处理,完全忽略了 nHashSize 参数。

因为你的函数被命名为 signHash 并且参数被命名为 pHash,有人怀疑你的意思是

CFDataRef myData = CFDataCreate(NULL, pHash, nHashSize);

关于c++ - 使用安全转换生成 RSA 签名并使用 OpenSSL/C++ 验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50705695/

相关文章:

node.js - Node TLS 套接字 : DEPTH_ZERO_SELF_SIGNED_CERT error

C++ 双重声明或无声明问题

c++ - 与裸 __m128 相比,SSE vector 包装器类型的性能

c++ - 在这种情况下如何使用双缓冲区?

objective-c - ARC 在 NSTableview 重新加载数据之前释放我的 NSmutablearray

Golang OpenSSL 错误的 iv 大小

c++ - 使用来自 Objective C 的 OpenCV decomposeHomographyMat

objective-c - 鼠标移动到 View 上时未调用

objective-c - 在 View Controller 中处理发送给第一响应者的消息

ruby - 加密空字符串