Ich habe Binärdaten in einer vorzeichenlosen Zeichenvariablen. Ich muss sie in c in PEM base64 konvertieren. Ich habe in der openssl-Bibliothek gesucht, aber keine Funktion gefunden. Hat irgendein Körper eine Idee?
Es macht keinen Sinn, dies zu verwenden, wenn es eine Bibliothek gibt.
Diego Woitasen
11
Sie können die "Abhängigkeit" von libm und math.h sowie die Notwendigkeit von Gleitkommaoperationen (die auf einigen Hardwarekomponenten langsam sind) überspringen, indem Sie *output_length = ((input_length - 1) / 3) * 4 + 4;am Anfang von base64_encode verwenden.
Fabian Henze
9
Mir ist klar, dass es sich um "keine Fehlerprüfung" handelt, aber beachten Sie insbesondere, dass die Decodiertabelle im Decoder zwar ein Array von 256 ist, da char auf den meisten Architekturen signiert ist, Sie jedoch wirklich von -128 bis 127 indizieren. Jedes Zeichen mit dem High Wenn das Bit gesetzt ist, lesen Sie außerhalb des zugewiesenen Speichers. Wenn Sie die Datensuche als vorzeichenloses Zeichen erzwingen, wird dies geklärt. Sie bekommen immer noch Müll für Müll rein, aber Sie werden nicht segfault.
Bitmusher
1
Sie haben ein Array-Out-of-Bound-Problem in build_decoding_table. existieren nicht. encoding_table[64]encoding_table[255]
Bobobobo
3
Die Dekodierung behandelt auch nicht die Situation, in der das Auffüllen "=" fehlt. Zusammen mit allen anderen Fehlern eine ziemlich schlechte Implementierung.
Lothar
56
Ich weiß, dass diese Frage ziemlich alt ist, aber ich war verwirrt über die Menge der angebotenen Lösungen - jede von ihnen behauptete, schneller und besser zu sein. Ich habe ein Projekt auf Github zusammengestellt, um die Base64-Encoder und -Decoder zu vergleichen: https://github.com/gaspardpetit/base64/
Zu diesem Zeitpunkt habe ich mich nicht auf C-Algorithmen beschränkt. Wenn eine Implementierung in C ++ eine gute Leistung erbringt, kann sie problemlos auf C zurückportiert werden. Außerdem wurden Tests mit Visual Studio 2015 durchgeführt. Wenn jemand diese Antwort mit Ergebnissen von clang / aktualisieren möchte gcc, sei mein Gast.
(Die Lösung von René Nyffenegger, die in einer anderen Antwort auf diese Frage gutgeschrieben wird, ist hier als adp_gmbh aufgeführt.)
Hier ist der von Jouni Malinen, den ich leicht modifiziert habe, um einen std :: string zurückzugeben:
/*
* Base64 encoding/decoding (RFC1341)
* Copyright (c) 2005-2011, Jouni Malinen <[email protected]>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/// 2016-12-12 - Gaspard Petit : Slightly modified to return a std::string // instead of a buffer allocated with malloc.#include<string>staticconstunsignedchar base64_table[65]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";/**
* base64_encode - Base64 encode
* @src: Data to be encoded
* @len: Length of the data to be encoded
* @out_len: Pointer to output length variable, or %NULL if not used
* Returns: Allocated buffer of out_len bytes of encoded data,
* or empty string on failure
*/
std::string base64_encode(constunsignedchar*src,size_t len){unsignedchar*out,*pos;constunsignedchar*end,*in;size_t olen;
olen =4*((len +2)/3);/* 3-byte blocks to 4-byte */if(olen < len)return std::string();/* integer overflow */
std::string outStr;
outStr.resize(olen);
out =(unsignedchar*)&outStr[0];
end = src + len;
in = src;
pos = out;while(end - in >=3){*pos++= base64_table[in[0]>>2];*pos++= base64_table[((in[0]&0x03)<<4)|(in[1]>>4)];*pos++= base64_table[((in[1]&0x0f)<<2)|(in[2]>>6)];*pos++= base64_table[in[2]&0x3f];
in +=3;}if(end - in){*pos++= base64_table[in[0]>>2];if(end - in ==1){*pos++= base64_table[(in[0]&0x03)<<4];*pos++='=';}else{*pos++= base64_table[((in[0]&0x03)<<4)|(in[1]>>4)];*pos++= base64_table[(in[1]&0x0f)<<2];}*pos++='=';}return outStr;}
SCHNELLSTE DEKODIERER: Hier sind die Dekodierungsergebnisse und ich muss zugeben, dass ich ein bisschen überrascht bin:
staticconstint B64index[256]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,63,62,62,63,52,53,54,55,56,57,58,59,60,61,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,0,0,0,0,63,0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
std::string b64decode(constvoid* data,constsize_t len){unsignedchar* p =(unsignedchar*)data;int pad = len >0&&(len %4|| p[len -1]=='=');constsize_t L =((len +3)/4- pad)*4;
std::string str(L /4*3+ pad,'\0');for(size_t i =0, j =0; i < L; i +=4){int n = B64index[p[i]]<<18| B64index[p[i +1]]<<12| B64index[p[i +2]]<<6| B64index[p[i +3]];
str[j++]= n >>16;
str[j++]= n >>8&0xFF;
str[j++]= n &0xFF;}if(pad){int n = B64index[p[L]]<<18| B64index[p[L +1]]<<12;
str[str.size()-1]= n >>16;if(len > L +2&& p[L +2]!='='){
n |= B64index[p[L +2]]<<6;
str.push_back(n >>8&0xFF);}}return str;}
Ich glaube wirklich nicht, dass std :: string und die restlichen Funktionen, die Sie verwendet haben, Teile von ANSI C sind. Die Frage nach C-Code und dem Tag C wird in C ++ am besten bewertet.
SF.
4
Ich zitiere mich selbst "Ich habe mich nicht auf C-Algorithmen beschränkt - wenn eine Implementierung in C ++ gut funktioniert, kann sie leicht auf C zurückportiert werden". Fügen Sie einen weiteren char* outStrParameter hinzu und schreiben Sie in diesen Puffer, anstatt einen zurückzugeben, std::stringwenn Sie möchten. Dies ist trivial. Bevor ich dies gepostet habe, gab es hier bereits zwei C ++ - Antworten mit positiven Stimmen.
GaspardP
Wenn man eine Lösung will, die sowohl für das Dekodieren als auch für das Kodieren gut funktioniert, ohne Code von zwei Stellen nehmen zu müssen, würde ich die Apache-Version für C und die Polfosol-Lösung für C ++
DaedalusAlpha
@GaspardP Kann die Dekodierung von Polfosol für die Kodierung von Jouni verwendet werden?
Sam Thomas
33
Sie können es aber auch in openssl tun ( openssl encBefehl macht es ....), schauen Sie sich die BIO_f_base64()Funktion an
Es scheint, dass das OP OpenSSL bereits aus einem anderen Grund verwendet, daher ist dies wahrscheinlich der beste Weg, dies zu tun.
Joshk0
18
Hier ist meine Lösung mit OpenSSL.
/* A BASE-64 ENCODER AND DECODER USING OPENSSL */#include<openssl/pem.h>#include<string.h>//Only needed for strlen().char*base64encode (constvoid*b64_encode_this,int encode_this_many_bytes){
BIO *b64_bio,*mem_bio;//Declares two OpenSSL BIOs: a base64 filter and a memory BIO.
BUF_MEM *mem_bio_mem_ptr;//Pointer to a "memory BIO" structure holding our base64 data.
b64_bio = BIO_new(BIO_f_base64());//Initialize our base64 filter BIO.
mem_bio = BIO_new(BIO_s_mem());//Initialize our memory sink BIO.
BIO_push(b64_bio, mem_bio);//Link the BIOs by creating a filter-sink BIO chain.
BIO_set_flags(b64_bio, BIO_FLAGS_BASE64_NO_NL);//No newlines every 64 characters or less.
BIO_write(b64_bio, b64_encode_this, encode_this_many_bytes);//Records base64 encoded data.
BIO_flush(b64_bio);//Flush data. Necessary for b64 encoding, because of pad characters.
BIO_get_mem_ptr(mem_bio,&mem_bio_mem_ptr);//Store address of mem_bio's memory structure.
BIO_set_close(mem_bio, BIO_NOCLOSE);//Permit access to mem_ptr after BIOs are destroyed.
BIO_free_all(b64_bio);//Destroys all BIOs in chain, starting with b64 (i.e. the 1st one).
BUF_MEM_grow(mem_bio_mem_ptr,(*mem_bio_mem_ptr).length +1);//Makes space for end null.(*mem_bio_mem_ptr).data[(*mem_bio_mem_ptr).length]='\0';//Adds null-terminator to tail.return(*mem_bio_mem_ptr).data;//Returns base-64 encoded data. (See: "buf_mem_st" struct).}char*base64decode (constvoid*b64_decode_this,int decode_this_many_bytes){
BIO *b64_bio,*mem_bio;//Declares two OpenSSL BIOs: a base64 filter and a memory BIO.char*base64_decoded = calloc((decode_this_many_bytes*3)/4+1,sizeof(char));//+1 = null.
b64_bio = BIO_new(BIO_f_base64());//Initialize our base64 filter BIO.
mem_bio = BIO_new(BIO_s_mem());//Initialize our memory source BIO.
BIO_write(mem_bio, b64_decode_this, decode_this_many_bytes);//Base64 data saved in source.
BIO_push(b64_bio, mem_bio);//Link the BIOs by creating a filter-source BIO chain.
BIO_set_flags(b64_bio, BIO_FLAGS_BASE64_NO_NL);//Don't require trailing newlines.int decoded_byte_index =0;//Index where the next base64_decoded byte should be written.while(0< BIO_read(b64_bio, base64_decoded+decoded_byte_index,1)){//Read byte-by-byte.
decoded_byte_index++;//Increment the index until read of BIO decoded data is complete.}//Once we're done reading decoded data, BIO_read returns -1 even though there's no error.
BIO_free_all(b64_bio);//Destroys all BIOs in chain, starting with b64 (i.e. the 1st one).return base64_decoded;//Returns base-64 decoded data with trailing null terminator.}/*Here's one way to base64 encode/decode using the base64encode() and base64decode functions.*/int main(void){char data_to_encode[]="Base64 encode this string!";//The string we will base-64 encode.int bytes_to_encode = strlen(data_to_encode);//Number of bytes in string to base64 encode.char*base64_encoded = base64encode(data_to_encode, bytes_to_encode);//Base-64 encoding.int bytes_to_decode = strlen(base64_encoded);//Number of bytes in string to base64 decode.char*base64_decoded = base64decode(base64_encoded, bytes_to_decode);//Base-64 decoding.
printf("Original character string is: %s\n", data_to_encode);//Prints our initial string.
printf("Base-64 encoded string is: %s\n", base64_encoded);//Prints base64 encoded string.
printf("Base-64 decoded string is: %s\n", base64_decoded);//Prints base64 decoded string.
free(base64_encoded);//Frees up the memory holding our base64 encoded data.
free(base64_decoded);//Frees up the memory holding our base64 decoded data.}
In der Zeile "Fügt einen Nullterminator hinzu" wird der AddressSanitizer-Fehler angezeigt, dass der Schreibvorgang den Heap um 1 Byte überschreitet.
bparker
Vielen Dank, ich habe den Fehler korrigiert und umfangreiche Tests mit zufällig großen Zeichenfolgen von zufälligen Bytes durchgeführt, um sicherzustellen, dass der Code wie angekündigt funktioniert. :)
Schulwitz
1
NETT! Ich habe es mit zusammengestelltcc -o base base.c -lssl -lcrypto . Keine Fehler. Es produzierte diese Ausgabe:Original character string is: Base64 encode this string! Base-64 encoded string is: QmFzZTY0IGVuY29kZSB0aGlzIHN0cmluZyE= Base-64 decoded string is: Base64 encode this string!
klares Licht
@schulwitz Ich habe eine Datei, die mit Python als Zeichenfolge codiert ist, aber wenn ich die Zeichenfolge mit Ihrer Funktion dekodiere und versuche, das dekodierte Ergebnis in eine Datei (in C) zu schreiben, erhalte ich nicht dieselbe Datei zurück. Die codierte Zeichenfolge ist korrekt. `` `const unsigned char * jarFile =" <codierte Datei> "; int main () {print_version (); DATEI * fp; char * out = base64decode (jarFile, strlen (jarFile)); fp = fopen ("file.jar", "wb"); if (fp == NULL) {printf ("Datei öffnen fehlgeschlagen"); return 1; } fwrite (out, sizeof (out), 1, fp); fclose (fp); frei (raus); return 0; } `` `
Sam Thomas
1
@SamThomas Die Verwendung von strlen funktioniert in meinem Beispiel, weil ich einen String erstellt habe, in dem nur ein Nullterminator vorhanden ist (und der sich am Ende des Strings befindet). Siehe: tutorialspoint.com/cprogramming/c_strings.htm Das Einlesen von jarFile mit strlen schlägt fehl, da wahrscheinlich in der Mitte Ihrer Binärdatei ein Nullterminator vorhanden ist, der den Wert bytes_to_decode durcheinander bringt. Siehe: stackoverflow.com/questions/24596189/… Finden Sie die Größe Ihrer Datei auf andere Weise: stackoverflow.com/questions/238603/…
Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert.
Alle Arbeiter sind wesentlich
16
libb64 verfügt sowohl über C- als auch über C ++ - APIs. Es ist leicht und vielleicht die schnellste öffentlich verfügbare Implementierung. Es ist auch eine dedizierte eigenständige Base64-Codierungsbibliothek, die nützlich sein kann, wenn Sie nicht alle anderen Dinge benötigen, die durch die Verwendung einer größeren Bibliothek wie OpenSSL oder glib entstehen.
Hinweis zu libb64: BUFFERSIZE wird in einer make-Datei definiert. Wenn Sie also make / cmake nicht verwenden, müssen Sie es manuell in den Header-Dateien definieren, damit es kompiliert werden kann. Works / kurz getestet VS2012
Tom
3
Wie Tom sagte: #define BUFFERSIZE 16777216Sie können 65536 ersetzen, wenn Sie einen kleineren Puffer benötigen.
Jyz
1
In acht nehmen! Nach einer Stunde Debuggen stellte ich fest, dass libb64 davon ausgeht, dass chares auf dem Zielsystem signiert ist ... Dies ist ein Problem, da base64_decode_valueeine negative Zahl zurückgegeben werden könnte, die dann in char umgewandelt wird.
Noir
Beachten Sie, dass die Sourceforge-Implementierung Zeilenumbrüche hinzufügt, die nicht allgemein unterstützt werden. Eine Gabelung von BuLogics auf Github entfernt sie, und ich habe eine Pull-Anfrage generiert, die auf Ihrem äußerst nützlichen Ergebnis @Noir basiert.
Alkalität
Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert.
Alle Arbeiter sind wesentlich
14
GNU coreutils hat es in lib / base64. Es ist ein wenig aufgebläht, befasst sich aber mit Dingen wie EBCDIC. Sie können auch alleine herumspielen, z.
char base64_digit (n)unsigned n;{if(n <10)return n -'0';elseif(n <10+26)return n -'a';elseif(n <10+26+26)return n -'A';else assert(0);return0;}unsignedchar base64_decode_digit(char c){switch(c){case'=':return62;case'.':return63;default:if(isdigit(c))return c -'0';elseif(islower(c))return c -'a'+10;elseif(isupper(c))return c -'A'+10+26;else assert(0);}return0xff;}unsigned base64_decode(char*s){char*p;unsigned n =0;for(p = s;*p; p++)
n =64* n + base64_decode_digit(*p);return n;}
Wisse alle Personen an diesen Geschenken, dass du nicht "alleine herumspielen" mit "Implementierung eines Standards" verwechseln sollst. Ja.
Ist auch '+'62 und '/'ist 63 in PEM base64, wie von OP angefordert. Hier ist eine Liste der Base64-Codierungsvarianten . Ich sehe keine Base64-Codierungsvariante mit der Reihenfolge der von Ihnen verwendeten Zeichen. Aber die Mathematik hinter dem Algorithmus ist korrekt.
Patrick
2
Wie bereits gesagt:
Seien Sie
Was ist mit Codierung?
Geremia
14
Ich brauchte eine C ++ - Implementierung, die an std :: string arbeitete . Keine der Antworten entsprach meinen Anforderungen. Ich brauchte eine einfache Lösung mit zwei Funktionen zum Codieren und Decodieren, aber ich war zu faul, um meinen eigenen Code zu schreiben, also fand ich Folgendes:
Geben Sie den folgenden Code ein, falls die Site ausfällt:
base64.cpp
/*
base64.cpp and base64.h
Copyright (C) 2004-2008 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger [email protected]
*/#include"base64.h"#include<iostream>staticconst std::string base64_chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZ""abcdefghijklmnopqrstuvwxyz""0123456789+/";staticinlinebool is_base64(unsignedchar c){return(isalnum(c)||(c =='+')||(c =='/'));}
std::string base64_encode(unsignedcharconst* bytes_to_encode,unsignedint in_len){
std::string ret;int i =0;int j =0;unsignedchar char_array_3[3];unsignedchar char_array_4[4];while(in_len--){
char_array_3[i++]=*(bytes_to_encode++);if(i ==3){
char_array_4[0]=(char_array_3[0]&0xfc)>>2;
char_array_4[1]=((char_array_3[0]&0x03)<<4)+((char_array_3[1]&0xf0)>>4);
char_array_4[2]=((char_array_3[1]&0x0f)<<2)+((char_array_3[2]&0xc0)>>6);
char_array_4[3]= char_array_3[2]&0x3f;for(i =0;(i <4); i++)
ret += base64_chars[char_array_4[i]];
i =0;}}if(i){for(j = i; j <3; j++)
char_array_3[j]='\0';
char_array_4[0]=(char_array_3[0]&0xfc)>>2;
char_array_4[1]=((char_array_3[0]&0x03)<<4)+((char_array_3[1]&0xf0)>>4);
char_array_4[2]=((char_array_3[1]&0x0f)<<2)+((char_array_3[2]&0xc0)>>6);
char_array_4[3]= char_array_3[2]&0x3f;for(j =0;(j < i +1); j++)
ret += base64_chars[char_array_4[j]];while((i++<3))
ret +='=';}return ret;}
std::string base64_decode(std::string const& encoded_string){int in_len = encoded_string.size();int i =0;int j =0;int in_ =0;unsignedchar char_array_4[4], char_array_3[3];
std::string ret;while(in_len--&&( encoded_string[in_]!='=')&& is_base64(encoded_string[in_])){
char_array_4[i++]= encoded_string[in_]; in_++;if(i ==4){for(i =0; i <4; i++)
char_array_4[i]= base64_chars.find(char_array_4[i]);
char_array_3[0]=(char_array_4[0]<<2)+((char_array_4[1]&0x30)>>4);
char_array_3[1]=((char_array_4[1]&0xf)<<4)+((char_array_4[2]&0x3c)>>2);
char_array_3[2]=((char_array_4[2]&0x3)<<6)+ char_array_4[3];for(i =0;(i <3); i++)
ret += char_array_3[i];
i =0;}}if(i){for(j = i; j <4; j++)
char_array_4[j]=0;for(j =0; j <4; j++)
char_array_4[j]= base64_chars.find(char_array_4[j]);
char_array_3[0]=(char_array_4[0]<<2)+((char_array_4[1]&0x30)>>4);
char_array_3[1]=((char_array_4[1]&0xf)<<4)+((char_array_4[2]&0x3c)>>2);
char_array_3[2]=((char_array_4[2]&0x3)<<6)+ char_array_4[3];for(j =0;(j < i -1); j++) ret += char_array_3[j];}return ret;}
Es ist nur eine sehr einfache Operation, die sicherstellt, dass der Zielpuffer auf NULL gesetzt ist, falls der Aufrufer dies vor dem Aufruf nicht getan hat, und wenn die Dekodierung möglicherweise fehlgeschlagen ist, hat der zurückgegebene Puffer die Länge Null. Ich habe nicht gesagt, dass ich diese Routine debuggt, verfolgt und profiliert habe, es ist nur eine, die ich seit Jahren verwende. :) Wenn ich es mir jetzt ansehe, muss es wirklich nicht da sein. Warum nennen wir es nicht eine "Übung für den Leser"? hehe .. Vielleicht bearbeite ich es einfach aus. Vielen Dank für den Hinweis!
LarryF
3
Ihre UnBase64Funktion kann den Speicher nach dem Zielpuffer gefährden, wenn dieser Puffer genau die Größe hat, die zum Decodieren der Basis 64-codierten Zeichenfolge erforderlich ist. Nehmen wir zum Beispiel den einfachen Fall, in dem Sie versuchen, die folgende Base 64-codierte Zeichenfolge "BQ ==" in ein einzelnes BYTE zu dekodieren, dh unsigned char Result = 0; UnBase64(&Result, "BQ==", 4); der Stapel wird beschädigt!
Mike Dinescu
3
Ja, hat einen bösen Fehler in unserer App verursacht. Nicht empfehlen.
Harald Maassen
Hallo Larry, danke, dass du deinen Code geteilt hast. Es ist sehr nützlich!
Federico
4
Für den Fall, dass Benutzer eine C ++ - Lösung benötigen, habe ich diese OpenSSL-Lösung zusammengestellt (sowohl zum Codieren als auch zum Decodieren). Sie müssen eine Verknüpfung mit der "Crypto" -Bibliothek (OpenSSL) herstellen. Dies wurde mit valgrind auf Lecks überprüft (obwohl Sie einen zusätzlichen Fehlerprüfcode hinzufügen könnten, um es ein bisschen besser zu machen - ich weiß, dass zumindest die Schreibfunktion auf den Rückgabewert prüfen sollte).
#include<openssl/bio.h>#include<openssl/evp.h>#include<stdlib.h>
string base64_encode(const string &str ){
BIO *base64_filter = BIO_new( BIO_f_base64());
BIO_set_flags( base64_filter, BIO_FLAGS_BASE64_NO_NL );
BIO *bio = BIO_new( BIO_s_mem());
BIO_set_flags( bio, BIO_FLAGS_BASE64_NO_NL );
bio = BIO_push( base64_filter, bio );
BIO_write( bio, str.c_str(), str.length());
BIO_flush( bio );char*new_data;long bytes_written = BIO_get_mem_data( bio,&new_data );
string result( new_data, bytes_written );
BIO_free_all( bio );return result;}
string base64_decode(const string &str ){
BIO *bio,*base64_filter,*bio_out;char inbuf[512];int inlen;
base64_filter = BIO_new( BIO_f_base64());
BIO_set_flags( base64_filter, BIO_FLAGS_BASE64_NO_NL );
bio = BIO_new_mem_buf((void*)str.c_str(), str.length());
bio = BIO_push( base64_filter, bio );
bio_out = BIO_new( BIO_s_mem());while((inlen = BIO_read(bio, inbuf,512))>0){
BIO_write( bio_out, inbuf, inlen );}
BIO_flush( bio_out );char*new_data;long bytes_written = BIO_get_mem_data( bio_out,&new_data );
string result( new_data, bytes_written );
BIO_free_all( bio );
BIO_free_all( bio_out );return result;}
BIO_free_all muss den Kopf - nicht den Schwanz - Ihrer Biokette angeben (dh den base64_filter). Ihre aktuelle Implementierung weist einen Speicherverlust auf.
Schulwitz
@schulwitz Welche Leitung hat das Leck? Bio_free_all gibt die gesamte Kette frei.
Homer6
4
Ich habe eine für die Verwendung mit C ++ geschrieben, sie ist sehr schnell, funktioniert mit Streams, kostenlos und Open Source:
Fühlen Sie sich frei, es zu verwenden, wenn es Ihrem Zweck entspricht.
Bearbeiten: Code inline auf Anfrage hinzugefügt.
Die Leistungssteigerung wird durch die Verwendung einer Nachschlagetabelle zum Codieren und Decodieren erreicht. _UINT8ist ein unsigned charauf den meisten Betriebssystemen.
/** Static Base64 character encoding lookup table */constcharCBase64::encodeCharacterTable[65]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";/** Static Base64 character decoding lookup table */constcharCBase64::decodeCharacterTable[256]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};/*!
\brief Encodes binary data to base 64 character data
\param in The data to encode
\param out The encoded data as characters
*/voidCBase64::Encode(std::istream &in, std::ostringstream &out){char buff1[3];char buff2[4];
_UINT8 i=0, j;while(in.readsome(&buff1[i++],1))if(i==3){
out << encodeCharacterTable[(buff1[0]&0xfc)>>2];
out << encodeCharacterTable[((buff1[0]&0x03)<<4)+((buff1[1]&0xf0)>>4)];
out << encodeCharacterTable[((buff1[1]&0x0f)<<2)+((buff1[2]&0xc0)>>6)];
out << encodeCharacterTable[buff1[2]&0x3f];
i=0;}if(--i){for(j=i;j<3;j++) buff1[j]='\0';
buff2[0]=(buff1[0]&0xfc)>>2;
buff2[1]=((buff1[0]&0x03)<<4)+((buff1[1]&0xf0)>>4);
buff2[2]=((buff1[1]&0x0f)<<2)+((buff1[2]&0xc0)>>6);
buff2[3]= buff1[2]&0x3f;for(j=0;j<(i+1);j++) out << encodeCharacterTable[buff2[j]];while(i++<3) out <<'=';}}/*!
\brief Decodes base 64 character data to binary data
\param in The character data to decode
\param out The decoded data
*/voidCBase64::Decode(std::istringstream &in, std::ostream &out){char buff1[4];char buff2[4];
_UINT8 i=0, j;while(in.readsome(&buff2[i],1)&& buff2[i]!='='){if(++i==4){for(i=0;i!=4;i++)
buff2[i]= decodeCharacterTable[buff2[i]];
out <<(char)((buff2[0]<<2)+((buff2[1]&0x30)>>4));
out <<(char)(((buff2[1]&0xf)<<4)+((buff2[2]&0x3c)>>2));
out <<(char)(((buff2[2]&0x3)<<6)+ buff2[3]);
i=0;}}if(i){for(j=i;j<4;j++) buff2[j]='\0';for(j=0;j<4;j++) buff2[j]= decodeCharacterTable[buff2[j]];
buff1[0]=(buff2[0]<<2)+((buff2[1]&0x30)>>4);
buff1[1]=((buff2[1]&0xf)<<4)+((buff2[2]&0x3c)>>2);
buff1[2]=((buff2[2]&0x3)<<6)+ buff2[3];for(j=0;j<(i-1); j++) out <<(char)buff1[j];}}
@cpburnz Ich habe jetzt ein Inline-Beispiel hinzugefügt und einen Kommentar, warum es schnell ist, danke.
2
Eine kleine Verbesserung des Codes von Ryyst (der die meisten Stimmen erhalten hat) besteht darin, keine dynamisch zugewiesene Dekodierungstabelle zu verwenden, sondern eine statische konstante vorberechnete Tabelle. Dies eliminiert die Verwendung von Zeigern und die Initialisierung der Tabelle und vermeidet auch Speicherverluste, wenn man vergisst, die Decodiertabelle mit base64_cleanup () zu bereinigen (übrigens in base64_cleanup (), nachdem man free (decoding_table) aufgerufen hat decoding_table = NULL, andernfalls stürzt ein versehentlicher Aufruf von base64_decode nach base64_cleanup () ab oder führt zu unbestimmtem Verhalten. Eine andere Lösung könnte darin bestehen, std :: unique_ptr zu verwenden ... aber ich bin zufrieden damit, nur const char [256] auf dem Stapel zu haben und die Verwendung von Zeigern insgesamt zu vermeiden - der Code sieht auf diese Weise sauberer und kürzer aus.
Die Decodiertabelle wird wie folgt berechnet:
constchar encoding_table[]={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'};unsignedchar decoding_table[256];for(int i =0; i <256; i++)
decoding_table[i]='\0';for(int i =0; i <64; i++)
decoding_table[(unsignedchar)encoding_table[i]]= i;for(int i =0; i <256; i++)
cout <<"0x"<<(int(decoding_table[i])<16?"0":"")<< hex <<int(decoding_table[i])<<(i !=255?",":"")<<((i+1)%16==0?'\n':'\0');
cin.ignore();
Dies ist nicht so einfach zu bedienen wie andere oben genannte Optionen. Es kann jedoch in eingebetteten Systemen von Nutzen sein, in denen Sie eine große Datei sichern möchten, ohne einen weiteren großen Puffer zum Speichern der resultierenden base64-Datauri-Zeichenfolge zuzuweisen. (Schade, dass Sie bei datauri den Dateinamen nicht angeben können).
void datauriBase64EncodeBufferless(int(*putchar_fcptr)(int),constchar* type_strptr,constvoid* data_buf,constsize_t dataLength){constchar base64chars[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";constuint8_t*data =(constuint8_t*)data_buf;size_t x =0;uint32_t n =0;int padCount = dataLength %3;uint8_t n0, n1, n2, n3;size_t outcount =0;size_t line =0;
putchar_fcptr((int)'d');
putchar_fcptr((int)'a');
putchar_fcptr((int)'t');
putchar_fcptr((int)'a');
putchar_fcptr((int)':');
outcount +=5;while(*type_strptr !='\0'){
putchar_fcptr((int)*type_strptr);
type_strptr++;
outcount++;}
putchar_fcptr((int)';');
putchar_fcptr((int)'b');
putchar_fcptr((int)'a');
putchar_fcptr((int)'s');
putchar_fcptr((int)'e');
putchar_fcptr((int)'6');
putchar_fcptr((int)'4');
putchar_fcptr((int)',');
outcount +=8;/* increment over the length of the string, three characters at a time */for(x =0; x < dataLength; x +=3){/* these three 8-bit (ASCII) characters become one 24-bit number */
n =((uint32_t)data[x])<<16;//parenthesis needed, compiler depending on flags can do the shifting before conversion to uint32_t, resulting to 0if((x+1)< dataLength)
n +=((uint32_t)data[x+1])<<8;//parenthesis needed, compiler depending on flags can do the shifting before conversion to uint32_t, resulting to 0if((x+2)< dataLength)
n += data[x+2];/* this 24-bit number gets separated into four 6-bit numbers */
n0 =(uint8_t)(n >>18)&63;
n1 =(uint8_t)(n >>12)&63;
n2 =(uint8_t)(n >>6)&63;
n3 =(uint8_t)n &63;/*
* if we have one byte available, then its encoding is spread
* out over two characters
*/
putchar_fcptr((int)base64chars[n0]);
putchar_fcptr((int)base64chars[n1]);
outcount +=2;/*
* if we have only two bytes available, then their encoding is
* spread out over three chars
*/if((x+1)< dataLength){
putchar_fcptr((int)base64chars[n2]);
outcount +=1;}/*
* if we have all three bytes available, then their encoding is spread
* out over four characters
*/if((x+2)< dataLength){
putchar_fcptr((int)base64chars[n3]);
outcount +=1;}/* Breaking up the line so it's easier to copy and paste */int curr_line =(outcount/80);if( curr_line != line ){
line = curr_line;
putchar_fcptr((int)'\r');
putchar_fcptr((int)'\n');}}/*
* create and add padding that is required if we did not have a multiple of 3
* number of characters available
*/if(padCount >0){for(; padCount <3; padCount++){
putchar_fcptr((int)'=');}}
putchar_fcptr((int)'\r');
putchar_fcptr((int)'\n');}
Diese Lösung basiert auf der schulwitz-Antwort (Codierung / Decodierung mit OpenSSL), ist jedoch für C ++ (die ursprüngliche Frage betraf C, aber es gibt hier bereits andere C ++ - Antworten) und verwendet die Fehlerprüfung (daher ist die Verwendung sicherer). ::
#include<openssl/bio.h>
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_memif(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 resultchar*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<char> 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;}}
Beachten Sie, dass base64_decode eine leere Zeichenfolge zurückgibt, wenn die Eingabe eine falsche base64-Sequenz ist (openssl funktioniert auf diese Weise).
hm ... die Verwendung der openssl-Bibliothek zum Decodieren / Codieren von base64
erfordert
-2
Hier ist eine optimierte Version des Encoders für die akzeptierte Antwort, die auch Zeilenumbrüche für MIME und andere Protokolle unterstützt (Simlar-Optimierung kann auf den Decoder angewendet werden):
char*base64_encode(constunsignedchar*data,size_t input_length,size_t*output_length,bool addLineBreaks)*output_length =4*((input_length +2)/3);if(addLineBreaks)*output_length +=*output_length /38;// CRLF after each 76 charschar*encoded_data = malloc(*output_length);if(encoded_data == NULL)return NULL;UInt32 octet_a;UInt32 octet_b;UInt32 octet_c;UInt32 triple;int lineCount =0;int sizeMod = size -(size %3);// check if there is a partial triplet// adding all octet triplets, before partial last tripletfor(; offset < sizeMod;){
octet_a = data[offset++];
octet_b = data[offset++];
octet_c = data[offset++];
triple =(octet_a <<0x10)+(octet_b <<0x08)+ octet_c;
encoded_data[mBufferPos++]= encoding_table[(triple >>3*6)&0x3F];
encoded_data[mBufferPos++]= encoding_table[(triple >>2*6)&0x3F];
encoded_data[mBufferPos++]= encoding_table[(triple >>1*6)&0x3F];
encoded_data[mBufferPos++]= encoding_table[(triple >>0*6)&0x3F];if(addLineBreaks){if(++lineCount ==19){
encoded_data[mBufferPos++]=13;
encoded_data[mBufferPos++]=10;
lineCount =0;}}}// last bytesif(sizeMod < size){
octet_a = data[offset++];// first octect always added
octet_b = offset < size ? data[offset++]:(UInt32)0;// conditional 2nd octet
octet_c =(UInt32)0;// last character is definitely padded
triple =(octet_a <<0x10)+(octet_b <<0x08)+ octet_c;
encoded_data[mBufferPos++]= encoding_table[(triple >>3*6)&0x3F];
encoded_data[mBufferPos++]= encoding_table[(triple >>2*6)&0x3F];
encoded_data[mBufferPos++]= encoding_table[(triple >>1*6)&0x3F];
encoded_data[mBufferPos++]= encoding_table[(triple >>0*6)&0x3F];// add padding '='
sizeMod = size %3;// last character is definitely padded
encoded_data[mBufferPos -1]=(byte)'=';if(sizeMod ==1) encoded_data[mBufferPos -2]=(byte)'=';}}
Antworten:
Hier ist die, die ich benutze:
Beachten Sie, dass dies beim Decodieren keine Fehlerprüfung durchführt - nicht Base 64-codierte Daten werden verarbeitet.
quelle
*output_length = ((input_length - 1) / 3) * 4 + 4;
am Anfang von base64_encode verwenden.build_decoding_table
. existieren nicht.encoding_table[64]
encoding_table[255]
Ich weiß, dass diese Frage ziemlich alt ist, aber ich war verwirrt über die Menge der angebotenen Lösungen - jede von ihnen behauptete, schneller und besser zu sein. Ich habe ein Projekt auf Github zusammengestellt, um die Base64-Encoder und -Decoder zu vergleichen: https://github.com/gaspardpetit/base64/
Zu diesem Zeitpunkt habe ich mich nicht auf C-Algorithmen beschränkt. Wenn eine Implementierung in C ++ eine gute Leistung erbringt, kann sie problemlos auf C zurückportiert werden. Außerdem wurden Tests mit Visual Studio 2015 durchgeführt. Wenn jemand diese Antwort mit Ergebnissen von clang / aktualisieren möchte gcc, sei mein Gast.
SCHNELLSTE ENCODER: Die zwei schnellsten Encoder-Implementierungen, die ich gefunden habe, waren Jouni Malinens unter http://web.mit.edu/freebsd/head/contrib/wpa/src/utils/base64.c und der Apache unter https://opensource.apple .com / source / QuickTimeStreamingServer / QuickTimeStreamingServer-452 / CommonUtilitiesLib / base64.c .
Hier ist die Zeit (in Mikrosekunden), um 32 KB Daten mit den verschiedenen Algorithmen zu codieren, die ich bisher getestet habe:
(Die Lösung von René Nyffenegger, die in einer anderen Antwort auf diese Frage gutgeschrieben wird, ist hier als adp_gmbh aufgeführt.)
Hier ist der von Jouni Malinen, den ich leicht modifiziert habe, um einen std :: string zurückzugeben:
SCHNELLSTE DEKODIERER: Hier sind die Dekodierungsergebnisse und ich muss zugeben, dass ich ein bisschen überrascht bin:
Das Polfosol-Snippet aus dem base64-Decodierungs-Snippet in c ++ ist mit dem Faktor fast 2x das schnellste.
Hier ist der Vollständigkeit halber der Code:
quelle
char* outStr
Parameter hinzu und schreiben Sie in diesen Puffer, anstatt einen zurückzugeben,std::string
wenn Sie möchten. Dies ist trivial. Bevor ich dies gepostet habe, gab es hier bereits zwei C ++ - Antworten mit positiven Stimmen.Sie können es aber auch in openssl tun (
openssl enc
Befehl macht es ....), schauen Sie sich dieBIO_f_base64()
Funktion anquelle
Hier ist meine Lösung mit OpenSSL.
quelle
cc -o base base.c -lssl -lcrypto
. Keine Fehler. Es produzierte diese Ausgabe:Original character string is: Base64 encode this string! Base-64 encoded string is: QmFzZTY0IGVuY29kZSB0aGlzIHN0cmluZyE= Base-64 decoded string is: Base64 encode this string!
glib verfügt über Funktionen für die Base64-Codierung: https://developer.gnome.org/glib/stable/glib-Base64-Encoding.html
quelle
libb64 verfügt sowohl über C- als auch über C ++ - APIs. Es ist leicht und vielleicht die schnellste öffentlich verfügbare Implementierung. Es ist auch eine dedizierte eigenständige Base64-Codierungsbibliothek, die nützlich sein kann, wenn Sie nicht alle anderen Dinge benötigen, die durch die Verwendung einer größeren Bibliothek wie OpenSSL oder glib entstehen.
quelle
#define BUFFERSIZE 16777216
Sie können 65536 ersetzen, wenn Sie einen kleineren Puffer benötigen.char
es auf dem Zielsystem signiert ist ... Dies ist ein Problem, dabase64_decode_value
eine negative Zahl zurückgegeben werden könnte, die dann in char umgewandelt wird.GNU coreutils hat es in lib / base64. Es ist ein wenig aufgebläht, befasst sich aber mit Dingen wie EBCDIC. Sie können auch alleine herumspielen, z.
Wisse alle Personen an diesen Geschenken, dass du nicht "alleine herumspielen" mit "Implementierung eines Standards" verwechseln sollst. Ja.
quelle
'+'
62 und'/'
ist 63 in PEM base64, wie von OP angefordert. Hier ist eine Liste der Base64-Codierungsvarianten . Ich sehe keine Base64-Codierungsvariante mit der Reihenfolge der von Ihnen verwendeten Zeichen. Aber die Mathematik hinter dem Algorithmus ist korrekt.Ich brauchte eine C ++ - Implementierung, die an std :: string arbeitete . Keine der Antworten entsprach meinen Anforderungen. Ich brauchte eine einfache Lösung mit zwei Funktionen zum Codieren und Decodieren, aber ich war zu faul, um meinen eigenen Code zu schreiben, also fand ich Folgendes:
http://www.adp-gmbh.ch/cpp/common/base64.html
Credits für den Code gehen an René Nyffenegger.
Geben Sie den folgenden Code ein, falls die Site ausfällt:
base64.cpp
base64.h
Verwendung
quelle
Hier ist der Decoder, den ich seit Jahren benutze ...
quelle
UnBase64
Funktion kann den Speicher nach dem Zielpuffer gefährden, wenn dieser Puffer genau die Größe hat, die zum Decodieren der Basis 64-codierten Zeichenfolge erforderlich ist. Nehmen wir zum Beispiel den einfachen Fall, in dem Sie versuchen, die folgende Base 64-codierte Zeichenfolge "BQ ==" in ein einzelnes BYTE zu dekodieren, dhunsigned char Result = 0; UnBase64(&Result, "BQ==", 4);
der Stapel wird beschädigt!Für den Fall, dass Benutzer eine C ++ - Lösung benötigen, habe ich diese OpenSSL-Lösung zusammengestellt (sowohl zum Codieren als auch zum Decodieren). Sie müssen eine Verknüpfung mit der "Crypto" -Bibliothek (OpenSSL) herstellen. Dies wurde mit valgrind auf Lecks überprüft (obwohl Sie einen zusätzlichen Fehlerprüfcode hinzufügen könnten, um es ein bisschen besser zu machen - ich weiß, dass zumindest die Schreibfunktion auf den Rückgabewert prüfen sollte).
quelle
Ich habe eine für die Verwendung mit C ++ geschrieben, sie ist sehr schnell, funktioniert mit Streams, kostenlos und Open Source:
https://tmplusplus.svn.sourceforge.net/svnroot/tmplusplus/trunk/src/
Fühlen Sie sich frei, es zu verwenden, wenn es Ihrem Zweck entspricht.
Bearbeiten: Code inline auf Anfrage hinzugefügt.
Die Leistungssteigerung wird durch die Verwendung einer Nachschlagetabelle zum Codieren und Decodieren erreicht.
_UINT8
ist einunsigned char
auf den meisten Betriebssystemen.quelle
Eine kleine Verbesserung des Codes von Ryyst (der die meisten Stimmen erhalten hat) besteht darin, keine dynamisch zugewiesene Dekodierungstabelle zu verwenden, sondern eine statische konstante vorberechnete Tabelle. Dies eliminiert die Verwendung von Zeigern und die Initialisierung der Tabelle und vermeidet auch Speicherverluste, wenn man vergisst, die Decodiertabelle mit base64_cleanup () zu bereinigen (übrigens in base64_cleanup (), nachdem man free (decoding_table) aufgerufen hat decoding_table = NULL, andernfalls stürzt ein versehentlicher Aufruf von base64_decode nach base64_cleanup () ab oder führt zu unbestimmtem Verhalten. Eine andere Lösung könnte darin bestehen, std :: unique_ptr zu verwenden ... aber ich bin zufrieden damit, nur const char [256] auf dem Stapel zu haben und die Verwendung von Zeigern insgesamt zu vermeiden - der Code sieht auf diese Weise sauberer und kürzer aus.
Die Decodiertabelle wird wie folgt berechnet:
und der geänderte Code, den ich verwende, ist:
quelle
Dies ist ein Decoder, der speziell geschrieben wurde, um die Notwendigkeit eines Puffers zu vermeiden, indem er direkt in eine Putchar-Funktion schreibt. Dies basiert auf der Implementierung von wikibook https://en.wikibooks.org/wiki/Algorithm_Implementation/Miscellaneous/Base64#C
Dies ist nicht so einfach zu bedienen wie andere oben genannte Optionen. Es kann jedoch in eingebetteten Systemen von Nutzen sein, in denen Sie eine große Datei sichern möchten, ohne einen weiteren großen Puffer zum Speichern der resultierenden base64-Datauri-Zeichenfolge zuzuweisen. (Schade, dass Sie bei datauri den Dateinamen nicht angeben können).
Hier ist der Test
Erwartete Ausgabe:
data:text/plain;charset=utf-8;base64,dGVzdA==
quelle
Die
EVP_EncodeBlock
undEVP_DecodeBlock
Funktionen machen es sehr einfach:quelle
Diese Lösung basiert auf der schulwitz-Antwort (Codierung / Decodierung mit OpenSSL), ist jedoch für C ++ (die ursprüngliche Frage betraf C, aber es gibt hier bereits andere C ++ - Antworten) und verwendet die Fehlerprüfung (daher ist die Verwendung sicherer). ::
Beachten Sie, dass base64_decode eine leere Zeichenfolge zurückgibt, wenn die Eingabe eine falsche base64-Sequenz ist (openssl funktioniert auf diese Weise).
quelle
Hier ist eine optimierte Version des Encoders für die akzeptierte Antwort, die auch Zeilenumbrüche für MIME und andere Protokolle unterstützt (Simlar-Optimierung kann auf den Decoder angewendet werden):
quelle