|
/***************************************************************************
|
|
begin : Thu May 06 2004
|
|
copyright : (C) 2004 by Martin Preuss
|
|
email : martin@libchipcard.de
|
|
|
|
***************************************************************************
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Lesser General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2.1 of the License, or (at your option) any later version. *
|
|
* *
|
|
* This library is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
* Lesser General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Lesser General Public *
|
|
* License along with this library; if not, write to the Free Software *
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
|
|
* MA 02111-1307 USA *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#define DISABLE_DEBUGLOG
|
|
|
|
|
|
#include "base64.h"
|
|
#include <gwenhywfar/misc.h>
|
|
#include <gwenhywfar/debug.h>
|
|
#include <gwenhywfar/text.h>
|
|
#include <string.h>
|
|
|
|
|
|
static const char GWEN_Base64_Alphabet[]=
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
|
|
|
|
|
int GWEN_Base64_Encode(const unsigned char *src, unsigned int size,
|
|
GWEN_BUFFER *dst,
|
|
unsigned int maxLineLength)
|
|
{
|
|
unsigned int by3;
|
|
unsigned int i;
|
|
unsigned int l;
|
|
uint32_t triplet;
|
|
unsigned char c1, c2, c3, c4;
|
|
|
|
if (maxLineLength) {
|
|
if (maxLineLength<4) {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "I need at least 4 bytes per line");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
by3=size/3;
|
|
/* first encode full triplets */
|
|
l=0;
|
|
for (i=0; i<by3; i++) {
|
|
triplet=(src[0]<<16)+(src[1]<<8)+src[2];
|
|
src+=3;
|
|
c4=triplet & 0x3f;
|
|
triplet>>=6;
|
|
c3=triplet & 0x3f;
|
|
triplet>>=6;
|
|
c2=triplet & 0x3f;
|
|
triplet>>=6;
|
|
c1=triplet & 0x3f;
|
|
if (maxLineLength) {
|
|
if (l+4>maxLineLength) {
|
|
GWEN_Buffer_AppendByte(dst, '\n');
|
|
l=0;
|
|
}
|
|
l+=4;
|
|
}
|
|
GWEN_Buffer_AppendByte(dst, GWEN_Base64_Alphabet[c1]);
|
|
GWEN_Buffer_AppendByte(dst, GWEN_Base64_Alphabet[c2]);
|
|
GWEN_Buffer_AppendByte(dst, GWEN_Base64_Alphabet[c3]);
|
|
GWEN_Buffer_AppendByte(dst, GWEN_Base64_Alphabet[c4]);
|
|
}
|
|
if (maxLineLength) {
|
|
if (l+4>=maxLineLength) {
|
|
GWEN_Buffer_AppendByte(dst, '\n');
|
|
l=0;
|
|
}
|
|
}
|
|
|
|
/* then encode remainder */
|
|
switch (size % 3) {
|
|
case 0:
|
|
/* no remainder */
|
|
break;
|
|
|
|
case 1:
|
|
/* 1 remainder, leads to two trailing "=" */
|
|
triplet=(src[0]<<4);
|
|
c2=triplet & 0x3f;
|
|
triplet>>=6;
|
|
c1=triplet & 0x3f;
|
|
GWEN_Buffer_AppendByte(dst, GWEN_Base64_Alphabet[c1]);
|
|
GWEN_Buffer_AppendByte(dst, GWEN_Base64_Alphabet[c2]);
|
|
GWEN_Buffer_AppendString(dst, "==");
|
|
break;
|
|
|
|
case 2:
|
|
/* 2 remainders, leads to one trailing "=" */
|
|
triplet=(src[0]<<10)+(src[1]<<2);
|
|
c3=triplet & 0x3f;
|
|
triplet>>=6;
|
|
c2=triplet & 0x3f;
|
|
triplet>>=6;
|
|
c1=triplet & 0x3f;
|
|
GWEN_Buffer_AppendByte(dst, GWEN_Base64_Alphabet[c1]);
|
|
GWEN_Buffer_AppendByte(dst, GWEN_Base64_Alphabet[c2]);
|
|
GWEN_Buffer_AppendByte(dst, GWEN_Base64_Alphabet[c3]);
|
|
GWEN_Buffer_AppendByte(dst, '=');
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int GWEN_Base64_Decode(const unsigned char *src, unsigned int size,
|
|
GWEN_BUFFER *dst)
|
|
{
|
|
unsigned int i;
|
|
const char *p = "0";
|
|
uint32_t v;
|
|
int lastWasEq;
|
|
int sizeGiven;
|
|
|
|
/* first decode full triplets */
|
|
sizeGiven=(size!=0);
|
|
lastWasEq=0;
|
|
for (;;) {
|
|
if ((sizeGiven && size==0) || lastWasEq || !*src)
|
|
break;
|
|
v=0;
|
|
|
|
while (*src && ((p=strchr(GWEN_Base64_Alphabet, *src))==0))
|
|
src++;
|
|
if (!*src)
|
|
break;
|
|
for (i=0; i<4; i++) {
|
|
/* get next valid character */
|
|
if (lastWasEq) {
|
|
while (*src && *src!='=')
|
|
src++;
|
|
}
|
|
else {
|
|
while (*src && ((p=strchr(GWEN_Base64_Alphabet, *src))==0))
|
|
src++;
|
|
}
|
|
if (!*src) {
|
|
if (i==0 && !sizeGiven) {
|
|
return 0;
|
|
}
|
|
else {
|
|
DBG_ERROR(GWEN_LOGDOMAIN, "Premature end reached (%d)", i);
|
|
return -1;
|
|
}
|
|
}
|
|
if (*src=='=')
|
|
lastWasEq++;
|
|
v<<=6;
|
|
v+=(p-GWEN_Base64_Alphabet) & 0x3f;
|
|
src++;
|
|
} /* for */
|
|
|
|
/* now we have a triplet */
|
|
if (sizeGiven) {
|
|
switch (size) {
|
|
case 1:
|
|
GWEN_Buffer_AppendByte(dst, (v>>16) & 0xff);
|
|
size--;
|
|
break;
|
|
case 2:
|
|
GWEN_Buffer_AppendByte(dst, (v>>16) & 0xff);
|
|
GWEN_Buffer_AppendByte(dst, (v>>8) & 0xff);
|
|
size-=2;
|
|
break;
|
|
default:
|
|
GWEN_Buffer_AppendByte(dst, (v>>16) & 0xff);
|
|
GWEN_Buffer_AppendByte(dst, (v>>8) & 0xff);
|
|
GWEN_Buffer_AppendByte(dst, v & 0xff);
|
|
size-=3;
|
|
break;
|
|
} /* switch */
|
|
}
|
|
else {
|
|
int bytes;
|
|
|
|
bytes=(24-(lastWasEq*6))/8;
|
|
if (bytes) {
|
|
GWEN_Buffer_AppendByte(dst, (v>>16) & 0xff);
|
|
if (bytes>1) {
|
|
GWEN_Buffer_AppendByte(dst, (v>>8) & 0xff);
|
|
if (bytes>2)
|
|
GWEN_Buffer_AppendByte(dst, v & 0xff);
|
|
}
|
|
}
|
|
}
|
|
} /* for full quadruplets */
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|