it-swarm.com.de

Wie codiere ich eine Zeichenfolge in base64, indem ich nur boost verwendet?

Ich versuche, eine einfache ASCII - Zeichenfolge in base64 (grundlegende HTTP-Authentifizierung mit boost :: asio) zu codieren und keinen neuen Code einzufügen oder Bibliotheken zu verwenden, die über boost hinausgehen.

Die einfache Signatur würde folgendermaßen aussehen: string Base64Encode (const string & text);

Wieder ist mir klar, dass der Algorithmus einfach ist und es gibt viele Bibliotheken/Beispiele, die dies tun, aber ich suche nach einem sauberen Boost-Beispiel. Ich habe Boost-Serialisierung gefunden, aber keine klaren Beispiele dort oder von Google . http://www.boost.org/doc/libs/1_46_1/libs/serialization/doc/dataflow.html

Ist dies möglich, ohne den eigentlichen base64-Algorithmus explizit zu meinem Code hinzuzufügen?

40
MattiasF

Ich habe das Beispiel in dem von Ihnen angegebenen Link verbessert:

#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/insert_linebreaks.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/archive/iterators/ostream_iterator.hpp>
#include <sstream>
#include <string>


int main()
{
    using namespace boost::archive::iterators;

    std::string test = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce ornare ullamcorper ipsum ac gravida.";

    std::stringstream os;
    typedef 
        insert_linebreaks<         // insert line breaks every 72 characters
            base64_from_binary<    // convert binary values to base64 characters
                transform_width<   // retrieve 6 bit integers from a sequence of 8 bit bytes
                    const char *,
                    6,
                    8
                >
            > 
            ,72
        > 
        base64_text; // compose all the above operations in to a new iterator

    std::copy(
        base64_text(test.c_str()),
        base64_text(test.c_str() + test.size()),
        ostream_iterator<char>(os)
    );

    std::cout << os.str();
}

Auf diese Weise wird die mit String kodierte base64 mit einem Zeilenumbruch alle 72 Zeichen auf der Konsole formatiert und kann in eine E-Mail gestellt werden. Wenn Sie die Zeilenumbrüche nicht mögen, bleiben Sie einfach dabei:

    typedef 
        base64_from_binary<
           transform_width<
                const char *,
                6,
                8
            >
        > 
        base64_text;
38
Tobias Schlegel

Hier ist meine Lösung. Es verwendet dieselbe grundlegende Technik wie die anderen Lösungen auf dieser Seite, löst jedoch das Problem der Polsterung auf eine meiner Meinung nach elegantere Weise. Diese Lösung verwendet auch C++ 11.

Ich denke, dass der größte Teil des Codes selbsterklärend ist. Das mathematische Bit in der encode-Funktion berechnet die Anzahl der '=' - Zeichen, die hinzugefügt werden müssen. Das Modulo 3 von val.size () ist der Rest, aber was wir wirklich wollen, ist der Unterschied zwischen val.size () und der nächsten Zahl, die durch drei teilbar ist. Da wir den Rest haben, können wir den Rest einfach von 3 abziehen, aber dies lässt 3 übrig, falls wir 0 wollen, also müssen wir noch einmal 3 modulo. 

#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/algorithm/string.hpp>

std::string decode64(const std::string &val) {
    using namespace boost::archive::iterators;
    using It = transform_width<binary_from_base64<std::string::const_iterator>, 8, 6>;
    return boost::algorithm::trim_right_copy_if(std::string(It(std::begin(val)), It(std::end(val))), [](char c) {
        return c == '\0';
    });
}

std::string encode64(const std::string &val) {
    using namespace boost::archive::iterators;
    using It = base64_from_binary<transform_width<std::string::const_iterator, 6, 8>>;
    auto tmp = std::string(It(std::begin(val)), It(std::end(val)));
    return tmp.append((3 - val.size() % 3) % 3, '=');
}
34
ltc

Eine andere Lösung, die Boost-Base64-Codierung verwendet, ist:

const std::string base64_padding[] = {"", "==","="};
std::string base64_encode(const std::string& s) {
  namespace bai = boost::archive::iterators;

  std::stringstream os;

  // convert binary values to base64 characters
  typedef bai::base64_from_binary
  // retrieve 6 bit integers from a sequence of 8 bit bytes
  <bai::transform_width<const char *, 6, 8> > base64_enc; // compose all the above operations in to a new iterator

  std::copy(base64_enc(s.c_str()), base64_enc(s.c_str() + s.size()),
            std::ostream_iterator<char>(os));

  os << base64_padding[s.size() % 3];
  return os.str();
}

std::string base64_decode(const std::string& s) {
  namespace bai = boost::archive::iterators;

  std::stringstream os;

  typedef bai::transform_width<bai::binary_from_base64<const char *>, 8, 6> base64_dec;

  unsigned int size = s.size();

  // Remove the padding characters, cf. https://svn.boost.org/trac/boost/ticket/5629
  if (size && s[size - 1] == '=') {
    --size;
    if (size && s[size - 1] == '=') --size;
  }
  if (size == 0) return std::string();

  std::copy(base64_dec(s.data()), base64_dec(s.data() + size),
            std::ostream_iterator<char>(os));

  return os.str();
}

Und hier sind die Testfälle:

    std::string t_e[TESTSET_SIZE] = {
        ""
      , "M"
      , "Ma"
      , "Man"
      , "pleasure."
      , "leasure."
      , "easure."
      , "asure."
      , "sure."
};
std::string t_d[TESTSET_SIZE] = {
        ""
      , "TQ=="
      , "TWE="
      , "TWFu"
      , "cGxlYXN1cmUu"
      , "bGVhc3VyZS4="
      , "ZWFzdXJlLg=="
      , "YXN1cmUu"
      , "c3VyZS4="
};

Hoffe das hilft

14
flare

Nun, da der Boost 1,66 erreicht hat und die Bestie enthalten ist, könnten Sie die Implementierung von Bestie verwenden.

Die wichtigsten Funktionen, die Sie benötigen, sind: boost::beast::detail::base64_encode() boost::beast::detail::base64_decode()

Aus #include < boost/beast/core/detail/base64.hpp >

7
Ben

Für alle, die von Google hierher kommen, hier meine Base64-Kodierungs-/Dekodierungsfunktionen, die auf Boost basieren. Es behandelt die Polsterung gemäß dem obigen Kommentar von DanDan. Die Decodierungsfunktionen werden angehalten, wenn ein ungültiges Zeichen gefunden wird, und es wird ein Zeiger auf dieses Zeichen zurückgegeben. Dies ist besonders nützlich, wenn Sie base64 in Json oder XML analysieren.

///
/// Convert up to len bytes of binary data in src to base64 and store it in dest
///
/// \param dest Destination buffer to hold the base64 data.
/// \param src Source binary data.
/// \param len The number of bytes of src to convert.
///
/// \return The number of characters written to dest.
/// \remarks Does not store a terminating null in dest.
///
uint base64_encode(char* dest, const char* src, uint len)
{
    char tail[3] = {0,0,0};
    typedef base64_from_binary<transform_width<const char *, 6, 8> > base64_enc;

    uint one_third_len = len/3;
    uint len_rounded_down = one_third_len*3;
    uint j = len_rounded_down + one_third_len;

    std::copy(base64_enc(src), base64_enc(src + len_rounded_down), dest);

    if (len_rounded_down != len)
    {
        uint i=0;
        for(; i < len - len_rounded_down; ++i)
        {
            tail[i] = src[len_rounded_down+i];
        }

        std::copy(base64_enc(tail), base64_enc(tail + 3), dest + j);

        for(i=len + one_third_len + 1; i < j+4; ++i)
        {
            dest[i] = '=';
        }

        return i;
    }

    return j;
}

///
/// Convert null-terminated string src from base64 to binary and store it in dest.
///
/// \param dest Destination buffer
/// \param src Source base64 string
/// \param len Pointer to unsigned int representing size of dest buffer. After function returns this is set to the number of character written to dest.
///
/// \return Pointer to first character in source that could not be converted (the terminating null on success)
///
const char* base64_decode(char* dest, const char* src, uint* len)
{
    uint output_len = *len;

    typedef transform_width<binary_from_base64<const char*>, 8, 6> base64_dec;

    uint i=0;
    try
    {
        base64_dec src_it(src);
        for(; i < output_len; ++i)
        {
            *dest++ = *src_it;
            ++src_it;
        }
    }
    catch(dataflow_exception&)
    {
    }

    *len = i;
    return src + (i+2)/3*4; // bytes in = bytes out / 3 rounded up * 4
}
6
Eloff

Während die Codierung funktioniert, ist der Decoder sicherlich kaputt. Außerdem gibt es einen Fehler: https://svn.boost.org/trac/boost/ticket/5629 . Ich habe keine Lösung dafür gefunden.

3
user434345

Ich habe die Antwort 8 geändert, da sie auf meiner Plattform nicht funktioniert.

const std::string base64_padding[] = {"", "==","="};
std::string *m_ArchiveData;

/// \brief  To Base64 string
bool Base64Encode(string* output) 
{  
    try
    {
        UInt32 iPadding_Mask = 0;
        typedef boost::archive::iterators::base64_from_binary
            <boost::archive::iterators::transform_width<const char *, 6, 8> > Base64EncodeIterator;  
        UInt32 len = m_ArchiveData->size();
        std::stringstream os;

        std::copy(Base64EncodeIterator(m_ArchiveData->c_str()), 
            Base64EncodeIterator(m_ArchiveData->c_str()+len), 
            std::ostream_iterator<char>(os));

        iPadding_Mask = m_ArchiveData->size() % 3;
        os << base64_padding[iPadding_Pask];

        *output = os.str();
        return output->empty() == false;  
    }
    catch (...)
    {
        PLOG_ERROR_DEV("unknown error happens");
        return false;
    }
}  

/// \brief  From Base64 string
bool mcsf_data_header_byte_stream_archive::Base64Decode(const std::string *input) 
{  
    try
    {
        std::stringstream os;
        bool bPaded = false;
        typedef boost::archive::iterators::transform_width<boost::archive::iterators::
            binary_from_base64<const char *>, 8, 6> Base64DecodeIterator;  

        UInt32 iLength = input->length();
        // Remove the padding characters, cf. https://svn.boost.org/trac/boost/ticket/5629
        if (iLength && (*input)[iLength-1] == '=') {
            bPaded = true;
            --iLength;
            if (iLength && (*input)[iLength - 1] == '=') 
            {
                --iLength;
            }
        }
        if (iLength == 0)
        {
            return false;
        }

        if(bPaded)
        {
            iLength --;
        }

        copy(Base64DecodeIterator(input->c_str()) ,
            Base64DecodeIterator(input->c_str()+iLength), 
            ostream_iterator<char>(os)); 

        *m_ArchiveData = os.str();
        return m_ArchiveData->empty() == false;
    }
    catch (...)
    {
        PLOG_ERROR_DEV("unknown error happens");
        return false;
    }
}  
0
Richardicy

Base64 kodiert Text und Daten

const std::string base64_padding[] = {"", "==","="};

std::string base64EncodeText(std::string text) {
    using namespace boost::archive::iterators;
    typedef std::string::const_iterator iterator_type;
    typedef base64_from_binary<transform_width<iterator_type, 6, 8> > base64_enc;
    std::stringstream ss;
    std::copy(base64_enc(text.begin()), base64_enc(text.end()), ostream_iterator<char>(ss));
    ss << base64_padding[text.size() % 3];
    return ss.str();
}

std::string base64EncodeData(std::vector<uint8_t> data) {
    using namespace boost::archive::iterators;
    typedef std::vector<uint8_t>::const_iterator iterator_type;
    typedef base64_from_binary<transform_width<iterator_type, 6, 8> > base64_enc;
    std::stringstream ss;
    std::copy(base64_enc(data.begin()), base64_enc(data.end()), ostream_iterator<char>(ss));
    ss << base64_padding[data.size() % 3];
    return ss.str();
}
0
neoneye