How do I base64 encode (decode) in C?

后端 未结 17 1842
孤城傲影
孤城傲影 2020-11-22 06:27

I have binary data in an unsigned char variable. I need to convert them to PEM base64 in c. I looked in openssl library but i could not find any function. Does any body have

17条回答
  •  傲寒
    傲寒 (楼主)
    2020-11-22 06:32

    This solution is based on schulwitz answer (encoding/decoding using OpenSSL), but it is for C++ (well, original question was about C, but there are already another C++ answers here) and it uses error checking (so it's safer to use):

    #include 
    
    std::string base64_encode(const std::string &input)
    {
        BIO *p_bio_b64 = nullptr;
        BIO *p_bio_mem = nullptr;
    
        try
        {
            // make chain: p_bio_b64 <--> p_bio_mem
            p_bio_b64 = BIO_new(BIO_f_base64());
            if (!p_bio_b64) { throw std::runtime_error("BIO_new failed"); }
            BIO_set_flags(p_bio_b64, BIO_FLAGS_BASE64_NO_NL); //No newlines every 64 characters or less
    
            p_bio_mem = BIO_new(BIO_s_mem());
            if (!p_bio_mem) { throw std::runtime_error("BIO_new failed"); }
            BIO_push(p_bio_b64, p_bio_mem);
    
            // write input to chain
            // write sequence: input -->> p_bio_b64 -->> p_bio_mem
            if (BIO_write(p_bio_b64, input.c_str(), input.size()) <= 0)
                { throw std::runtime_error("BIO_write failed"); }
    
            if (BIO_flush(p_bio_b64) <= 0)
                { throw std::runtime_error("BIO_flush failed"); }
    
            // get result
            char *p_encoded_data = nullptr;
            auto  encoded_len    = BIO_get_mem_data(p_bio_mem, &p_encoded_data);
            if (!p_encoded_data) { throw std::runtime_error("BIO_get_mem_data failed"); }
    
            std::string result(p_encoded_data, encoded_len);
    
            // clean
            BIO_free_all(p_bio_b64);
    
            return result;
        }
        catch (...)
        {
            if (p_bio_b64) { BIO_free_all(p_bio_b64); }
            throw;
        }
    }
    
    std::string base64_decode(const std::string &input)
    {
        BIO *p_bio_mem = nullptr;
        BIO *p_bio_b64 = nullptr;
    
        try
        {
            // make chain: p_bio_b64 <--> p_bio_mem
            p_bio_b64 = BIO_new(BIO_f_base64());
            if (!p_bio_b64) { throw std::runtime_error("BIO_new failed"); }
            BIO_set_flags(p_bio_b64, BIO_FLAGS_BASE64_NO_NL); //Don't require trailing newlines
    
            p_bio_mem = BIO_new_mem_buf((void*)input.c_str(), input.length());
            if (!p_bio_mem) { throw std::runtime_error("BIO_new failed"); }
            BIO_push(p_bio_b64, p_bio_mem);
    
            // read result from chain
            // read sequence (reverse to write): buf <<-- p_bio_b64 <<-- p_bio_mem
            std::vector buf((input.size()*3/4)+1);
            std::string result;
            for (;;)
            {
                auto nread = BIO_read(p_bio_b64, buf.data(), buf.size());
                if (nread  < 0) { throw std::runtime_error("BIO_read failed"); }
                if (nread == 0) { break; } // eof
    
                result.append(buf.data(), nread);
            }
    
            // clean
            BIO_free_all(p_bio_b64);
    
            return result;
        }
        catch (...)
        {
            if (p_bio_b64) { BIO_free_all(p_bio_b64); }
            throw;
        }
    }
    

    Note that base64_decode returns empty string, if input is incorrect base64 sequence (openssl works in such way).

提交回复
热议问题