使用 SecTransform API(或其他系统 API)在 OS X 上进行 RSA public 密钥解密

RSA public key decryption on OS X using SecTransform API (or other system API)

我正在尝试替换我对 OpenSSL 的使用,OpenSSL 早已被弃用,并且已使用安全转换从 10.11 SDK 中删除 API。我使用 OpenSSL 只是为了验证许可证密钥。我遇到的问题 运行 是许可证密钥是使用 OpenSSL 的 rsa_private_encrypt() 函数生成的(服务器端),而不是(可能更合适)rsa_sign()。在当前的 OpenSSL 代码中,我使用 rsa_public_decrypt() 验证它们,如下所示:

int decryptedSize = RSA_public_decrypt([signature length], [signature bytes], checkDigest, rsaKey, RSA_PKCS1_PADDING);
BOOL success = [[NSData dataWithBytes:checkDigest length:decryptedSize] isEqualToData:[digest sha1Hash]]) 

不幸的是,我无法使用 SecTransform APIs 复制它。我有以下内容:

SecTransformRef decryptor = CFAutorelease(SecDecryptTransformCreate(pubKey, &error));
if (error) { showSecError(error); return NO; }
SecTransformSetAttribute(decryptor, kSecTransformInputAttributeName, (CFDataRef)signatureData, &error);
if (error) { showSecError(error); return NO; }

CFDataRef result = SecTransformExecute(decryptor, &error);
if (error) { showSecError(error); return NO; }
return CFEqual(result, (CFDataRef)[digest sha1Hash]);

调用 SecTransformExecute() 失败并出现 CSSMERR_CSP_INVALID_KEY_CLASS 错误。

我是不是遗漏了什么,或者 Security.framework 中没有与 OpenSSL 的 RSA_public_decrypt() 等效的东西?也许可以使用 SecVerifyTransform(我也无法让它工作,但 OpenSSL 的 RSA_sign() 也是如此)。我当然愿意使用另一个系统 API(例如 CDSA/CSSM),如果它能让我做到这一点。

不幸的是,由于此代码需要验证现有的许可证代码,我不能简单地更改我的许可证生成代码以使用 RSA_sign() 或类似代码。

我想出了如何使用 CDSA/CSSM 来做到这一点。代码如下:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"

NSData *ORSDecryptDataWithPublicKey(NSData *dataToDecrypt, SecKeyRef publicKey)
{
    const CSSM_KEY *cssmPubKey = NULL;
    SecKeyGetCSSMKey(publicKey, &cssmPubKey);
    CSSM_CSP_HANDLE handle;
    SecKeyGetCSPHandle(publicKey, &handle);

    CSSM_DATA inputData = {
        .Data = (uint8_t *)[dataToDecrypt bytes],
        .Length = [dataToDecrypt length],
    };

    CSSM_DATA outputData = {
        .Data = NULL,
        .Length = 0,
    };

    CSSM_ACCESS_CREDENTIALS credentials;
    memset(&credentials, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
    CSSM_CC_HANDLE contextHandle;
    CSSM_RETURN result = CSSM_CSP_CreateAsymmetricContext(handle, cssmPubKey->KeyHeader.AlgorithmId, &credentials, cssmPubKey, CSSM_PADDING_PKCS1, &contextHandle);
    if (result) { NSLog(@"Error creating CSSM context: %i", result); return nil; }

    CSSM_CONTEXT_ATTRIBUTE modeAttribute = {
        .AttributeType = CSSM_ATTRIBUTE_MODE,
        .AttributeLength = sizeof(UInt32),
        .Attribute.Uint32 = CSSM_ALGMODE_PUBLIC_KEY,
    };
    result = CSSM_UpdateContextAttributes(contextHandle, 1, &modeAttribute);
    if (result) { NSLog(@"Error setting CSSM context mode: %i", result); return nil; }

    CSSM_SIZE numBytesDecrypted = 0;
    CSSM_DATA remData = {
        .Data = NULL,
        .Length = 0,
    };
    result = CSSM_DecryptData(contextHandle, &inputData, 1, &outputData, 1, &numBytesDecrypted, &remData);
    if (result) { NSLog(@"Error decrypting data using CSSM: %i", result); return nil; }
    CSSM_DeleteContext(contextHandle);

    outputData.Length = numBytesDecrypted;

    return [NSData dataWithBytesNoCopy:outputData.Data length:outputData.Length freeWhenDone:YES];
}

#pragma clang diagnostic pop

请注意,here, while CDSA is deprecated, Apple recommends its use "if none of the other cryptographic service APIs support what you are trying to do". I have filed radar #23063471 要求将此功能添加到 Security.framework。