【问题标题】:RSA_private_decrypt crashes when called for the second timeRSA_private_decrypt 在第二次调用时崩溃
【发布时间】:2019-03-20 12:35:34
【问题描述】:

请看下面的方法:

int BCVirtualCard::decrypt(std::string from, std::string *to, int keyId, bool padding)
{
    if (to == nullptr)
    {
        NSCAssert(NO, @"Invalid params");
        return 0;
    }

    NSString* privateKey            = [m_storage privateKeyForSlot:keyId];
    NSArray<NSString*>* components  = [privateKey componentsSeparatedByString:@"_"];
    const NSInteger componentsCount = 4;

    if (components.count != componentsCount)
    {
        *to = "";
        return 0;
    }

    const char* d = [components[0] UTF8String];
    const char* n = [components[1] UTF8String];
    const char* p = [components[2] UTF8String];
    const char* q = [components[3] UTF8String];

    RSA* rsa = RSA_new();

    BN_hex2bn(&rsa->d, d);
    BN_hex2bn(&rsa->n, n);
    BN_hex2bn(&rsa->p, p);
    BN_hex2bn(&rsa->q, q);

    unsigned char* _to = (unsigned char *)calloc(1, sizeof(unsigned char));

    int decryptedSize = RSA_private_decrypt((int)from.length(), (unsigned char *)from.c_str(), _to, rsa, RSA_NO_PADDING);

    free(_to);

    if (decryptedSize <= 0)
    {
        ERR_print_errors_cb(test, NULL);

        *to = "";
        return 0;
    }

    _to = (unsigned char *)calloc(decryptedSize, sizeof(unsigned char));

    RSA_private_decrypt((int)from.length(), (unsigned char *)from.c_str(), _to, rsa, RSA_NO_PADDING);

    *to = std::string((char *)_to, strlen((char *)_to));

    free(_to);

    RSA_free(rsa);

    return 1;
}

这里的字符串from应该被解密并写入字符串to。对于解密,我使用RSA_private_decrypt 函数。我叫了两次。第一次是为了确定解密文本的大小,第二次是为了将解密的文本写入_to 缓冲区。当我第二次调用它时,它通常会像这样崩溃:

malloc: Heap corruption detected, free list is damaged at 0x280ff3d70
*** Incorrect guard value: 0
No1BCmail(2171,0x170efb000) malloc: *** set a breakpoint in malloc_error_break to debug

断点打开了,这让我找到了崩溃的地方。但是我无法理解它崩溃的原因。我第二次尝试重新创建RSA 结构并使用分配给_to 的大小,但没有任何帮助。你能看出这里有什么问题吗?谢谢

【问题讨论】:

  • _to 实际上是空终止的吗?如果不是,您应该使用*to = std::string((char *)_to, decryptedSize);
  • 另外,根据this,您对解密的第一个调用是 UB:to 必须指向足够大的内存部分以保存解密数据(小于 RSA_size(rsa ))。
  • @NathanOliver 至于你的第二条评论——这就是我两次调用 RSA_private_decrypt 的全部原因。我根本不知道应该为 _to 缓冲区分配的大小。我需要先得到它。你看到了吗?
  • 看起来使用 RSA_size(rsa) 应该给你一个缓冲区大小来使用。它从rsa-&gt;n 获取该值。所以你可以做unsigned char* _to = new unsigned char[RSA_size(rsa)]; ...; delete _to
  • @NathanOliver 我不太擅长 RSA。你的意思是解密文本的大小总是小于或等于n?对吗?

标签: c++ objective-c openssl rsa objective-c++


【解决方案1】:

RSA_private_decrypt 要求to 参数指向足够大小的缓冲区。您的第一次调用仅使用大小为 1 的缓冲区,该缓冲区太小并且是未定义的行为。您需要做的是使用RSA_size(rsa)rsa 获取大小,然后您可以使用它为_to 分配空间。这意味着您不需要调用该函数两次,因为您在第一次时就已经有了大小

如果要构建的字符串而不是使用strlen 作为_to 可能不会以空值终止,则您还应该使用decryptedSize 作为长度。

把所有这些放在一起,你应该看起来像

int BCVirtualCard::decrypt(std::string from, std::string *to, int keyId, bool padding)
{
    if (to == nullptr)
    {
        NSCAssert(NO, @"Invalid params");
        return 0;
    }

    NSString* privateKey            = [m_storage privateKeyForSlot:keyId];
    NSArray<NSString*>* components  = [privateKey componentsSeparatedByString:@"_"];
    const NSInteger componentsCount = 4;

    if (components.count != componentsCount)
    {
        *to = "";
        return 0;
    }

    const char* d = [components[0] UTF8String];
    const char* n = [components[1] UTF8String];
    const char* p = [components[2] UTF8String];
    const char* q = [components[3] UTF8String];

    RSA* rsa = RSA_new();

    BN_hex2bn(&rsa->d, d);
    BN_hex2bn(&rsa->n, n);
    BN_hex2bn(&rsa->p, p);
    BN_hex2bn(&rsa->q, q);

    auto _to = std::make_unique<unsigned char[]>(RSA_size(rsa)); // use smart pointers so you don't have to worry about releasing the memory

    int decryptedSize = RSA_private_decrypt((int)from.length(), (unsigned char *)from.c_str(), _to.get(), rsa, RSA_NO_PADDING);

    if (decryptedSize <= 0)
    {
        ERR_print_errors_cb(test, NULL);    
        *to = "";
        return 0;
    }

    *to = std::string((char *)_to.get(), decryptedSize);
    return 1;
}

【讨论】:

    猜你喜欢
    • 2015-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-21
    • 1970-01-01
    相关资源
    最近更新 更多