如何从 RSA_private_encrypt 获得人类可读的 std::string

How to get human readable std::string from RSA_private_encrypt

我用 RSA 加密了我的字符串,但它现在是一个 unsigned char *。如何创建可以为用户输出的人类可读 std::string?我想在亚马逊签名 url 中使用它。这是来自 GitHub

的代码的主要内容
unsigned char* RSA_SHA1_Sign(std::string policy, RSA *privateKey) throw(std::runtime_error)
{

    //sha1 digest the data
    unsigned char hash[SHA_DIGEST_LENGTH] = {'0'};
    SHA1((const unsigned char *)policy.c_str(), policy.length(), hash);

    // Sign the data
    int rsaSize = RSA_size(privateKey);
//    std::unique_ptr<unsigned char[]> signedData(new unsigned char[size]);//if c++11 available
unsigned char *signedData = (unsigned char *)malloc(sizeof(unsigned char) * rsaSize);
    unsigned int signedSize = 0;

    //use RSA_sign instead of RSA_private_encrypt
    if(!RSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, signedData, &signedSize, privateKey)){
        throw std::runtime_error("Failed to sign");
    }

    return signedData;
}

std::string base64Encode(unsigned char *signedData)
{
    //prepare
    BIO *b64 = BIO_new(BIO_f_base64());
    BIO *bmem = BIO_new(BIO_s_mem());
    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
    b64 = BIO_push(b64, bmem);

    //write
    BIO_write(b64, signedData, 256);
    BIO_flush(b64);


    //create string
    BUF_MEM *bptr;
    BIO_get_mem_ptr(b64, &bptr);
    std::string base64String(bptr->data);

    BIO_free_all(b64);
    return base64String;
}
int main(int argc, const char * argv[]) {

    RSA *privateKey = createRSAFromPrivateKeyFile("/path/to/privatekey");
    std::string sourceString = "testing";
    std::string signature = RSA_SHA1_Sign(sourceString, privateKey);
    std::string encodedSignature = base64Encode(signature);
    std::cout << "RESULT: " << encodedSignature << std::endl;

    return 0;
}

更新:我使用了错误的符号函数。更新后,使用 base64 编码给了我正确的字符串。

RSA_PKCS1_PADDING PKCS #1 v1.5 padding. This function does not handle the algorithmIdentifier specified in PKCS #1. When generating or verifying PKCS #1 signatures, RSA_sign(3) and RSA_verify(3) should be used.

首先,将它放入一个 std::string 对象中,这通常会有帮助:

std::string s{private_key, size};

但是,要使其与亚马逊的方案兼容,您需要选择(或编写自己的)Base64 库和 URL 编码器以转义特殊的 URL 字符。粗略搜索 Google 或 Whosebug 将为您提供这方面所需的内容,写出如何在 C++ 中进行 Base64 编码和 URL 转义超出了这个问题的范围。

此外,由于您使用的是 C++,请考虑 std::unique_ptr<unsigned char[]> 而不是直接 malloc();

std::unique_ptr<unsigned char[]> signedData{new unsigned char[size]};

要保存所有数据,请使用此 std::string 构造函数:std::string( char *data, int size )。该大小将很有用,因为输出可能包含空字符。

要通过 url 将其发送到亚马逊,再次考虑使用 base64 编码,因为加密数据可能包含 NULL 和其他恶作剧。