RSA 加密解密使用实例

时间:2024-01-28 13:50:19

http://www.dtmao.cc/news_show_692109.shtml

本文不讨论RSA加密解密本身,只记录使用方法及遇到的坑,RSA原理及注意事项可在网上查找。

背景:公司的一个需求,要求对接客户的一个平台,通信方式为MQTT,数据包含Token及json内容,在通信过程中发送的MQTT信息必须带上Token,这个Token是要从客户平台获取,通过http协议,POST方法。

然后POST方法的body信息需要进行RSA加密(提供了公钥和私钥,公钥加密私钥解密),然后再Base64加密。Base64公司代码里已经有了,但RSA加密却没有,只能自己网上搜索。在使用RSA加密过程中遇到了以下几个问题:

1,用RSA加密时,如果密文长度是1024位(128字节)的话,其要加密的明文只能是117字节长度。我的POST方法数据不止117字节,无法满足我目前的需求。

2,Base64编码问题

3,公钥及私钥是客户提供的,但不是标准格式。

关于问题1、问题2:

找了很多网上的例子,实现的都是简单的几个字符的加密及解密,那些长串字符加密的直接拿过来又无法通过编译。最后找到一些拿过来修修改改,终于可以用,记录如下:

/**
** @brief 用公钥进行加密,明文长于117字节时需要进行分段处理
*/
std::string CRSAEnCrypt::rsaPublicKeyEncryptSplit(const std::string &clearText)
{
    std::string result;
    std::string input;
    result.clear();

    for(int i = 0 ; i< clearText.length() / SPLIT_LEN; i++)
    {  
        input.clear();
        input.assign(clearText.begin() + i * SPLIT_LEN, clearText.begin() + i * SPLIT_LEN + SPLIT_LEN);
        result = result + rsaPublicKeyEncrypt(input);
    }

    if(clearText.length() % SPLIT_LEN != 0)
    {
        int32_t tmp = clearText.length() / SPLIT_LEN * SPLIT_LEN;
        input.clear();
        input.assign(clearText.begin() + tmp, clearText.end());
        result = result + rsaPublicKeyEncrypt(input);
    }

    printf("before base64 len: %lu\n", result.length());
    std::string encode_str = base64Encode((uint8_t*)result.c_str(), result.length());
    printf("after base64 len: %lu\n", encode_str.length());
    return encode_str;
}

 网上有些说,分段RSA加密后即进行Base64编码,但我这里是RSA加密完成后再整体进行Base64编码,在进行RSA解码时先Base64解码。

/**
** @brief 用私钥进行解密,分段处理
*/
std::string CRSAEnCrypt::rsaPrivateKeyDecryptSplit(const std::string &Text)
{
    printf("before base64Decode len: %lu\n", Text.length());
    std::string clearText = base64Decode(Text);
    printf("after base64Decode len: %lu\n", clearText.length());
    
    //printf("BaseDecode len: %lu\n", clearText.length());
    std::string result;
    std::string input;
    result.clear();
    for(int i = 0 ; i< clearText.length() / 128; i++)
    {
        input.clear();
        input.assign(clearText.begin() + i * 128, clearText.begin() + i * 128 + 128);
        result = result + rsaPrivateKeyDecrypt(input);
    }

    if(clearText.length() % 128 != 0)
    {
        int tem1 = clearText.length()/128 * 128;
        input.clear();
        input.assign(clearText.begin()+ tem1, clearText.end());
        result = result + rsaPrivateKeyDecrypt(input);
    }

    return result;    
}

使用例子:


int main()
{
    Json::Value postMsg;
    postMsg["userName"] = "zgdxgzt";
    postMsg["password"] = "xcq123456";
    postMsg["tenantId"] = "5fca019cb091f5b7e44c0eec";
    postMsg["client_id"] = "5cf600563f4c000053007383";
    postMsg["client_secret"] = "U2FsdGVkX1+oesjvWS3Z8q7ziFCu+p4tU7OQjl+5m21l7XMbBBJtof4fAL1S8/tJNrGpqIAqtTwXOeiZJFFtHw==";
    postMsg["scope"] = "read";  //固定值
    postMsg["grant_type"] = "password"; //固定值


    CRSAEnCrypt::getInstance()->initkey(privateKey, publicKey);
    std::string sourceStr = jsonToString(postMsg);
    printf("string of json: %s\n", sourceStr.c_str());

    //单独测试base64加密、解密
    // std::string encodeStr = base64Encode((uint8_t *)sourceStr.c_str(), sourceStr.length());
    // printf("decodeStr len: %lu\n", encodeStr.length());
    // std::string decodeStr = base64Decode(encodeStr);
    // printf("decodeStr len: %lu, %s\n", decodeStr.length(), decodeStr.c_str());

    //公钥加密
    std::string rsaEncryptStr = CRSAEnCrypt::getInstance()->rsaPublicKeyEncryptSplit(sourceStr);
    printf("after rsaEncryptStr len: %lu\n", rsaEncryptStr.length());

    //私钥解密
    std::string rsaDecryptStr = CRSAEnCrypt::getInstance()->rsaPrivateKeyDecryptSplit(rsaEncryptStr);
    printf("after rsaDecryptStr: %lu, %s\n", rsaDecryptStr.length(), rsaDecryptStr.c_str());

    return 0;
}

关于第3个问题,公钥和私钥有固定格式,要注意,因客户只提供两个字符串,里面并没有包含固定的头和尾字符,这样可能会导致RSA 读取密钥时出错。正确格式如下:

不同的头尾标识,调用的openssl的库函数可能不同,可自行baidu。

最后一点网上一些例子只贴出部分代码,很多时候下载后根本不能直接用,这不是要流氓吗。。。。

源码下载:

git clone git@github.com:tianyexing2008/c_cpp.git

下载后cd encrypt 目录下make 即可。因代码中用到的json,如果你电脑上已经有json库,可能可以直接编译过,如果没有,这个git里也有json源码,目录json,可cd json后进行make编译libjson.a库,再修改encrypt里的Makefile里指定的头文件目录

及json库目录即可。