c++的加密库--crypto++/openssl库

因为最近用到AES,RSA,SHA之类的密码学算法,用的是crypto++这个库,所以在这里记录一下
现在我觉得是openssl库好用,真香!


crypto++
https://www.cryptopp.com/
Crypto ++ Library是一个加密方案的免费C ++类库。


一.安装依赖库
首先需要下载这个库
sudo apt-get install libcrypto++
我用的是clion
在cmakelist.txt的最后添加依赖
target_link_libraries(your_program_name crypto++)
之后就能用了

#include "crypto++/files.h"
#include "crypto++/rsa.h"
#include "crypto++/randpool.h"
#include "crypto++/hex.h"
#include "crypto++/base64.h"
#include "crypto++/sha.h"

using namespace CryptoPP;

使用时注意使用命名空间

aes https://blog.csdn.net/csdn49532/article/details/50686222


二.RSA
网上的例子有很多,但是没有用自己已有的公钥去加密的,我尝试用自己另外的公钥去加密,一直在报错,都是格式问题
下面这段是参考别人的

//------------------------
// Generate RSA Key
//------------------------
void CKeyController::GenerateRSAKey(unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed)
{
    RandomPool randPool;
    randPool.Put((byte *)seed, strlen(seed));

    RSAES_OAEP_SHA_Decryptor priv(randPool, keyLength);
    Base64Encoder privFile(new FileSink(privFilename));
    priv.DEREncode(privFile);
    privFile.MessageEnd();

    RSAES_OAEP_SHA_Encryptor pub(priv);
    Base64Encoder pubFile(new FileSink(pubFilename));
    pub.DEREncode(pubFile);
    pubFile.MessageEnd();

}

//------------------------
// RSA encrypt choose Base64Encoder/HexEncoder/null
//------------------------
string CKeyController::RSAEncryptString(const char *pubFilename, const char *seed, const char *message){
    FileSource pubFile(pubFilename, true, new HexDecoder);
    RSAES_OAEP_SHA_Encryptor pub(pubFile);

    RandomPool randPool;
    randPool.Put((byte *)seed, strlen(seed));

    string result;
    StringSource(message, true, new PK_EncryptorFilter(randPool, pub, new HexEncoder(new StringSink(result))));//16进制编码器
    return result;
}
//------------------------
// RSA decrypt
//------------------------
string CKeyController::RSADecryptString(const char *privFilename, const char *ciphertext){
    FileSource privFile(privFilename, true, new HexDecoder);

    RSAES_OAEP_SHA_Decryptor priv(privFile);

    string result;
    StringSource(ciphertext, true, new HexDecoder(new PK_DecryptorFilter(GlobalRNG(), priv, new StringSink(result))));//Base64 Hex
    return result;
}
//------------------------
// define gobal rng
//------------------------
RandomPool & CKeyController::GlobalRNG()
{
    static RandomPool randomPool;
    return randomPool;
}

替换成自己的公钥去加密会报BER decode error
这里的密钥内部保存是ASN.1 DER的编码方式
StringSource参数:(原始字符串, 长度, 变换方式filter)

terminate called after throwing an instance of 'CryptoPP::InputRejecting::InputRejected'
  what():  BufferedTransformation: this object doesn't allow input

这个问题就没解决

https://blog.csdn.net/rain_qingtian/article/details/43267793
我发现好像搞反了,RSA公钥算法的话是公钥加密私钥解密,但是用在签名上的话是私钥签名用公钥验证,好气
签名的官方文档,好好看这篇
https://www.cryptopp.com/wiki/Rsa_signature_schemes

尝试了好几天了,没法替换私钥,总是格式问题
把自己的私钥放进去,然后就会无法解析,报错BER
记录我的各种尝试

string CKeyController::SignMessage_by( const std::string& privateKeyFileName, const std::string& message )
{
    std::string signedMessage = "";

    ////////////////////////////////////////
    string encString;
    string prikey="MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCGzWIxRW4gO5V6npTs2X/VuqjVDMntifmSwOTQ68emYZjYnSx85NovrmjtWPhgWzCGu2CV09ihe5nwX2JXWXNbDbxgK3J+5spSEcGmH5SQgiWB2TfdrbXOqGZ6ogZ2zIKju36Cp1oFY8gnUYoSCOpYqb9CoVlqG0A1n9z6Qi4u7s256pZi7fSzTwMrLJgHCI2nbqTw7deQCqRPeulwQNh6n1ftmJStqfztf7XJUc211oRPgun+e7DUQt1Ork3CwYREdjsXsCcbm8KRsb5LNYzNnsA/wtFUb4Fn5F/JtyveU3i4uZcvZQf6r3eUpaEMTbbrj7gx0YMKR6ShnIM9+4+JAgMBAAECggEARwpyFxlKAj6kdiygu3mcPxzR4QWOXVr7ZfW2IMxBOVPx4yZhzaglvD8kGQFsVAt6tWaGbi9o2SF0bRM3lmUTwAarIduDyZEDSuEEtvGpr8aG0bmSEYd8at6gszw0P+Njbbpf36cmb/S4BNCZ/QspxXQf0ZOKtbqKyjfnkxPRlvWLK2JokD+aYSa7VuP83D9MXmn28LP6VALcFYGuiljXMsBcT1hWV3nS8SqzW5+gHNP5EBiSzmQU9wChrRiwqLNVkZq574uTYXQGEBdDkeB6fNL+mzSCia692SZTOO13g2YcfL/8BJ1tI8YnitLxDZ6CJvKswHGnbShK86Pz6SlmKQKBgQC9X8E/0XytzHDuxjXmG+c21C1TGnULlkwnsAcETMdz0LN24uyXkI5VTSQ5jImd5044elQttzxWNsakAyiTrCrQey1C3gASJtkpEXDfZnLNTx6OgN2vHQtcFZMc6nsQm3KpF6j/ZLUtcrRj9m9RdCOkYDjSBlVe5FLU7KZUx66BOwKBgQC2Ooti2kIK0ERg0PLQGVJIxiIaxos3NtsNbGZUneHzuIbMqRgD7yqb/zDVAK1bV5yTnHuEtbndyXT8CxBV4Xz+uxD/JXEHB0t9htrtQ8ER93Smg8wcut9xS/EUJslN4TBrCkx2X5nEbyP7V+1CBqrlmefSvearUxklEL8oPhPmCwKBgB/JyA2nY49lBvv9x6RlwK0idq1Bfq5AP25WDQd6v+w/9zAYrXBPsqS8+zyxy5P29NlkJ2c5H+a08Sks4o3PU6yFULatv0NMxB0xsUm+z7yI8G8pUI0JihOeB4DOF3RVM60QrKyaQhNr8r3o6wy4Oxdnk4Il0ATKvODDDLSkhDVrAoGBAKH2FrydT+VchemmzKi4WLHlp5o0rLc+QiMEHU9Ho/OCJgzwnS+h+jT78uLd3zY4ACoSApZJDhFZZGg/TR2HdBjTGqArHvIoQagnm50Vgxv82+jDaz59uOpxnKtUbcaSRv5cAOmUvo4gWdKiq3TriCjZSXm83q+XA9o1sDCMPBNRAoGAKk8DZjOpjFvN2PNdPNRgexhy7mVsIFtzlt/0CuAJYuqelg1H22cUnnALs1LLZ2qEF5uzyZgChA7z19cGSKsAR2hWg9QXSpxmqZnPSCgm2yc71ok49p+JlZ6DtjKn4az4nF2koyfpSuh1FRYhLT4h8cMXDna385V/RZzhOrYN8ho=";
    //StringSource privString( prikey.c_str(), true, new Base64Decoder(new StringSink(encString)));
    StringSource privString( prikey.c_str(), true, new FileSink("prikey"));
    RSAES_OAEP_SHA_Decryptor decryptor;
    Base64Encoder decFile(new StringSink(prikey));
    decryptor.DEREncode(decFile);
    decFile.MessageEnd();


    FileSource privFile( "prikey", true, new Base64Decoder(new StringSink(encString)));
    RSASSA_PKCS1v15_SHA_Signer priv;

    //

  /*  HexEncoder pubFile(new FileSink("pubkey", true));
    pubFile.Put((const byte*)encString.c_str(),encString.size());
    decryptor.DEREncode(pubFile);
    pubFile.MessageEnd();*/

   /* HexDecoder decoder;
    decoder.Put( (byte*)encString.c_str(), encString.size() );
    decoder.MessageEnd();*/

  //  priv.AccessKey().Load(decoder);

    AutoSeededRandomPool rng;
  //  StringSource s1(message, true, new SignerFilter(rng, priv, new Base64Encoder(new StringSink(signedMessage))));

    return encString;
}

还是gg,转openssl库看下
https://www.linuxidc.com/Linux/2017-09/147117.htm
貌似这里的链接要注意
c++的加密库--crypto++/openssl库_第1张图片

cmake_minimum_required(VERSION 3.10)
project(untitled_3)

set(CMAKE_CXX_STANDARD 11)
set(INC_DIR /home/parallels/Downloads/openssl-1.1.1/include)
set(LINK_DIR /home/parallels/Downloads/openssl-1.1.1/lib)

include_directories(${INC_DIR})
link_directories(${LINK_DIR})
link_libraries(ssl crypto)


add_executable(untitled_3 main.cpp common_tool.cpp common_tool.h
        Base64.cpp
        Base64.h)
target_link_libraries(untitled_3 openssl)

问题一:
报错 EVP_MD_CTX的问题,是由于函数变动,调用方式也需要改动

/home/parallels/CLionProjects/untitled_3/common_tool.cpp: In static member function ‘static bool common_tool::verify_rsa(RSA*, const string&, const string&)’:
/home/parallels/CLionProjects/untitled_3/common_tool.cpp:57:16: error: aggregate ‘EVP_MD_CTX ctx’ has incomplete type and cannot be defined
     EVP_MD_CTX ctx;
                ^
/home/parallels/CLionProjects/untitled_3/common_tool.cpp:99:28: error: ‘EVP_MD_CTX_cleanup’ was not declared in this scope
     EVP_MD_CTX_cleanup(&ctx);
                            ^

这里写图片描述
解决方案:https://blog.csdn.net/uniom/article/details/54143201

问题二:解决问题一之后的问题
这里写图片描述
代码中是调用的EVP_MD_CTX_create,EVP_MD_CTX_init方法的,但是查看evp.h是有定义过的
这里写图片描述
考虑版本问题吧
我用的最新版是1.1.1现在打算用1.0.1u,经过测试,就是这个问题,解决
换库很快的,make之后在cmakelist里面改一个库的路径就行
问题三:
在运行的时候又报错了,然后把问题一的时候修改的内容换回来,就可以了
是在EVP_MD_CTX_init(&ctx);的时候有信号量问题,之前是改成指针所以有问题,改回来了

urlencode
https://www.codeguru.com/cpp/cpp/algorithms/strings/article.php/c12759/URI-Encoding-and-Decoding.htm


参考的是与java对接的c++,https://blog.csdn.net/richerg85/article/details/51723124
贴一下完整的代码,是我运行,需要的依赖和问题前面都介绍了
c++的加密库--crypto++/openssl库_第2张图片
这是结构
这里的pem密钥是openssl生成的,然后拷贝到目录下的

OpenSSL> genrsa -out rsa_private_key.pem   1024  #生成私钥
OpenSSL> pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt -out rsa_private_key_pkcs8.pem #Java开发者需要将私钥转换成PKCS8格式
OpenSSL> rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem #生成公钥
OpenSSL> exit #退出OpenSSL程序

这里看一下pem文件的内部,就是多加了前缀和后缀,中间的内容可以替换,我就是替换的自己的密钥

-----BEGIN RSA PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCvuKK4Hd+R39cNPHPC6a2MMpUIkfYiBX0+3iFePiffZueU94weBfgK3XE5RV2B8WQsXA3LTRvgS7uluU2niCF/zcQ5uYi7CFM07iXRktr93z2fmgUbeSqL//NBBX8jouROdmB/mG6hXX9xjcoO4SHkJ/jLQftcv3ZIuJdkW3b5epHF1S+he+Cf8DssZskUNzhW5pVonMK/HoNJngwEboReAQhTQM8GRugKCPryff3JntORKlUhuj8edK0bHJCakdeu+m5cG0FriByVIyD/y00u2+30TxYY5gXwlAhI4Fq8rfQ9Kpk4iiVp8fjtyGO3Wl8GuUbSCaAynsbp6pWmp1/7AgMBAAECggEAJOhN3QgBPj1aiOAqnETCe9Df9pXZsZmfjcXQEmBRtZ2ChIpd9qxgRb/vGQ1Vr4ZI+Pw4tXuzoC+n8Q3znn18M8C/NzSd4FLGTza54MPMlUf/RHdwHS4c3pzatcx2wMBk3YoFiKc2jVP7AZm7V9a3bJlsqxxntDpOmMWUnrKLUaiwARbFIaR4UXe6smSW/haC3cB5W579CRW7Qynpy+6xEs6pNfRNFm2P8tPfsMwHdb/btLKZnDfO9qCoV3rHK+8pu4teu4rehpz/wOEPOXLidDNZ1NR98gQ+MPk3kaur+IQZLEsA/OSPIxF1yx3BF1DSGLSxFG9fq+9i45uXVLB+2QKBgQDxRvowG9u6BPJ6ztV0JxI19Zc/Boxd+tgYxP4xcNgEoKrv4k3j/9e6LIuRn0R2WprvqR5THEG2b6IeaXCjPFD+e4jeJ+9ypT6c8M0cW3raosQWNQgCntUgYi4WXJNOfStjVsEhFId+xG5QdjxI7suVUCIqEBNPqPgRuVPxiejefwKBgQC6cZlvu+bS0rWptgOSSWr+eDwa7IAUkjuC4hzenXkO8+OM+5YwLVj8II6kXGYQ81oVQUFcCd7pdU5mvkKYYZN8LgLYSnV0P+hWHXeybgGhorF19MJY2yl/cyUL/9fGtQKeSIM431+7nQECrLVelw1DuWcKb7a+uXceePsp8AA4hQKBgErwE5bLoEQ3cySHhy6LUBGoVLCDlSc/WMzgql6qwL03NcBJ1o1hEhzF5xd0kyv7WjHjogKIPTSvmXe+ofhhLHrN3aW6W5mND1RpShtrok2zzhljoThHIsTrGYtid3IiWE6DTHq8yJSr5+NfxbuVR2/5spLD6WuNfHbsy9CyV7x7AoGBAJZ9iU8SCU+UesPAwgM7NZyvKjzFNuDj5BtSLeFWlFeIbtzmWiULBW+FS/3JAy2db9IGOR50bTRd1mnCGvjqkeRDM1KoT0QFLaEM6gfhGXoBW2KNrK2SQV25cGbOHLoscy+V8i1ex+Qk56LkCwWNwUwwA8b9wzERfN/g4ULJkTQNAoGAVnbKNCeRMqu1cj0qFYh/aTlu2uu7DJQDvylhnccuDOgpwA+GZAJdb+Q6ACNBGGObtJMK1hwxH2Sg0qH96Pgj7PhmyVIX8051VWXudeJn52l0Dml5/xwGhE/JAA199kXd7KgE8D+mU33Bi3PUctqBNlndYohk5CRTCxX3hPzt450=
-----END RSA PRIVATE KEY-----

main.cpp

#include 
#include 
#include "common_tool.h"


static void ERR(const char* string);

static std::string sign(const char *private_key,const std::string &content) {
    BIO *bufio = NULL;
    RSA *rsa = NULL;
    EVP_PKEY *evpKey = NULL;
    bool verify = false;
    EVP_MD_CTX ctx ;
    int result = 0;
    unsigned int size = 0;
    char *sign = NULL;
    std::string signStr = "";

   /* bufio = BIO_new_mem_buf((void*)private_key, -1);
    if (bufio == NULL) {
    	ERR("BIO_new_mem_buf failed");
    	goto safe_exit;
    }*/
    bufio = BIO_new(BIO_s_file());
    BIO_read_filename(bufio, "rsa_private_key_pkcs8.pem");
   // BIO_read_filename(bufio, "rsa_private_key.pem");

    rsa = PEM_read_bio_RSAPrivateKey(bufio, NULL, NULL, NULL);
    if (rsa == NULL) {
        ERR("PEM_read_bio_RSAPrivateKey failed");
        goto safe_exit;
    }

    evpKey = EVP_PKEY_new();
    if (evpKey == NULL) {
        ERR("EVP_PKEY_new failed");
        goto safe_exit;
    }

    if ((result = EVP_PKEY_set1_RSA(evpKey, rsa)) != 1) {
        ERR("EVP_PKEY_set1_RSA failed");
        goto safe_exit;
    }

    EVP_MD_CTX_init(&ctx);

    if (result == 1 && (result = EVP_SignInit_ex(&ctx, EVP_md5(), NULL)) != 1) {
        ERR("EVP_SignInit_ex failed");
    }

    if (result == 1 && (result = EVP_SignUpdate(&ctx, content.c_str(), content.size())) != 1) {
        ERR("EVP_SignUpdate failed");
    }

    size = EVP_PKEY_size(evpKey);
    sign = (char*)malloc(size+1);
    memset(sign, 0, size+1);

    if (result == 1 && (result = EVP_SignFinal(&ctx, (unsigned char*)sign, &size, evpKey)) != 1) {
        ERR("EVP_SignFinal failed");
    }

    if (result == 1) {
        verify = true;
    } else {
        ERR("verify failed");
    }

    signStr = base64_encode((const unsigned char*)sign, size);
    EVP_MD_CTX_cleanup(&ctx);
    //EVP_MD_CTX_destroy(ctx);
    free(sign);

    safe_exit:
    if (rsa != NULL) {
        RSA_free(rsa);
        rsa = NULL;
    }

    if (evpKey != NULL) {
        EVP_PKEY_free(evpKey);
        evpKey = NULL;
    }

    if (bufio != NULL) {
        BIO_free_all(bufio);
        bufio = NULL;
    }

    return signStr;
    //return sign;
}

static void ERR(const char* string) {
    std::cout<<"error  "<<string<<std::endl;
}

int main() {
    std::cout << "Hello, World!" << std::endl;
    std::string message="shadkfkaslkdfj";
    std::string prikey="";
    std::string signtxt=sign("",message);
    std::cout<<signtxt<<std::endl;

    BIO *bufio = NULL;
    RSA *rsa = NULL;
    bufio = BIO_new(BIO_s_file());
    BIO_read_filename(bufio, "rsa_public_key.pem");
    rsa = PEM_read_bio_RSA_PUBKEY(bufio, NULL, NULL, NULL);
    common_tool ct;
    std::cout<<ct.verify_rsa(rsa,message,signtxt)<<std::endl;

    return 0;
}

common_tool.h

//
// Created by parallels on 9/13/18.
//

#ifndef UNTITLED_3_COMMON_TOOL_H
#define UNTITLED_3_COMMON_TOOL_H

#include 

#include "openssl/sha.h"
#include "openssl/rsa.h"
#include "openssl/rand.h"
#include "openssl/objects.h"
#include "openssl/pem.h"


#include "Base64.h"

class common_tool {
public:
    static std::string url_encode(const std::string& szToEncode);
    static std::string url_decode(const std::string& szToDecode);
    static bool verify_rsa(RSA *rsa ,const std::string &content, const std::string &sign);

};


#endif //UNTITLED_3_COMMON_TOOL_H

common_tool.cpp

//
// Created by parallels on 9/13/18.
//

#include "common_tool.h"

std::string common_tool::url_encode(const std::string& szToEncode)
{
    std::string src = szToEncode;
    char hex[] = "0123456789ABCDEF";
    std::string dst;

    for (size_t i = 0; i < src.size(); ++i)
    {
        unsigned char cc = src[i];
        if (isascii(cc))
        {
            if (cc == ' ')
            {
                dst += "%20";
            }
            else
                dst += cc;
        }
        else
        {
            unsigned char c = static_cast<unsigned char>(src[i]);
            dst += '%';
            dst += hex[c / 16];
            dst += hex[c % 16];
        }
    }
    return dst;
}

std::string common_tool::url_decode(const std::string &SRC) {
    std::string ret;
    char ch;
    int i, ii;
    for (i=0; i<SRC.length(); i++) {
        if (int(SRC[i])==37) {
            sscanf(SRC.substr(i+1,2).c_str(), "%x", &ii);
            ch=static_cast<char>(ii);
            ret+=ch;
            i=i+2;
        } else {
            ret+=SRC[i];
        }
    }
    return (ret);
}
bool common_tool::verify_rsa(/*const char *public_key*/RSA *rsa , const std::string &content, const std::string &sign) {
    BIO *bufio = NULL;
    EVP_PKEY *evpKey = NULL;
    bool verify = false;
    EVP_MD_CTX ctx;
    int result = 0;
    std::string decodedSign = base64_decode(sign);
    char *chDecodedSign = const_cast<char*>(decodedSign.c_str());

    if (rsa == NULL) {
        printf("PEM_read_bio_RSA_PUBKEY failed");
        goto safe_exit;
    }

    evpKey = EVP_PKEY_new();
    if (evpKey == NULL) {
        printf("EVP_PKEY_new failed");
        goto safe_exit;
    }

    if ((result = EVP_PKEY_set1_RSA(evpKey, rsa)) != 1) {
        printf("EVP_PKEY_set1_RSA failed");
        goto safe_exit;
    }

    EVP_MD_CTX_init(&ctx);

    if (result == 1 && (result = EVP_VerifyInit_ex(&ctx,
                                                   EVP_md5(), NULL)) != 1) {
        printf("EVP_VerifyInit_ex failed");
    }

    if (result == 1 && (result = EVP_VerifyUpdate(&ctx,
                                                  content.c_str(), content.size())) != 1) {
        printf("EVP_VerifyUpdate failed");
    }

    if (result == 1 && (result = EVP_VerifyFinal(&ctx, (unsigned char*)chDecodedSign, decodedSign.size(), evpKey)) != 1) {
        printf("EVP_VerifyFinal failed");
    }
    if (result == 1) {
        verify = true;
    } else {
        printf("verify failed");
    }

    EVP_MD_CTX_cleanup(&ctx);
    //EVP_MD_CTX_destroy(&ctx);
    safe_exit:
    if (rsa != NULL) {
        RSA_free(rsa);
        rsa = NULL;
    }

    if (evpKey != NULL) {
        EVP_PKEY_free(evpKey);
        evpKey = NULL;
    }

    if (bufio != NULL) {
        BIO_free_all(bufio);
        bufio = NULL;
    }

    return verify;
}

base64.h

//
// Created by parallels on 9/11/18.
//

#ifndef UNTITLED1_BASE64_H
#define UNTITLED1_BASE64_H

#include 
std::string base64_encode(unsigned char const* , unsigned int len);
std::string base64_decode(std::string const& s);
#endif //UNTITLED1_BASE64_H

这个实现自己找的
上面的代码在和java对接的时候那个url编码有问题,上面的代码编码前后无差,需要更换

unsigned char ToHex(unsigned char x) 
{ 
    return  x > 9 ? x + 55 : x + 48; 
}
 
unsigned char FromHex(unsigned char x) 
{ 
    unsigned char y;
    if (x >= 'A' && x <= 'Z') y = x - 'A' + 10;
    else if (x >= 'a' && x <= 'z') y = x - 'a' + 10;
    else if (x >= '0' && x <= '9') y = x - '0';
    else assert(0);
    return y;
}
 
std::string UrlEncode(const std::string& str)
{
    std::string strTemp = "";
    size_t length = str.length();
    for (size_t i = 0; i < length; i++)
    {
        if (isalnum((unsigned char)str[i]) || 
            (str[i] == '-') ||
            (str[i] == '_') || 
            (str[i] == '.') || 
            (str[i] == '~'))
            strTemp += str[i];
        else if (str[i] == ' ')
            strTemp += "+";
        else
        {
            strTemp += '%';
            strTemp += ToHex((unsigned char)str[i] >> 4);
            strTemp += ToHex((unsigned char)str[i] % 16);
        }
    }
    return strTemp;
}
 
std::string UrlDecode(const std::string& str)
{
    std::string strTemp = "";
    size_t length = str.length();
    for (size_t i = 0; i < length; i++)
    {
        if (str[i] == '+') strTemp += ' ';
        else if (str[i] == '%')
        {
            assert(i + 2 < length);
            unsigned char high = FromHex((unsigned char)str[++i]);
            unsigned char low = FromHex((unsigned char)str[++i]);
            strTemp += high*16 + low;
        }
        else strTemp += str[i];
    }
    return strTemp;
}

实测可用

你可能感兴趣的:(c++)