#include "cuEnc64.h"
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#ifndef NULL
#define NULL ((void *)0)
#endif
static const
unsigned char bintoasc[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const
unsigned char asctobin[] =
{
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x3e, 0x80, 0x80, 0x80, 0x3f,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
0x3c, 0x3d, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80
};
#define ENC(c) (bintoasc[((c) & 0x3f)])
#define PAD '='
static void encChunk(const unsigned char *inp,
unsigned char *outp,
int count)
{
unsigned char c1, c2, c3, c4;
c1 = *inp >> 2;
c2 = ((inp[0] << 4) & 0x30) | ((inp[1] >> 4) & 0xf);
c3 = ((inp[1] << 2) & 0x3c) | ((inp[2] >> 6) & 0x3);
c4 = inp[2] & 0x3f;
*outp++ = ENC(c1);
*outp++ = ENC(c2);
if (count == 1) {
*outp++ = PAD;
*outp = PAD;
} else {
*outp++ = ENC(c3);
if (count == 2) {
*outp = PAD;
}
else {
*outp = ENC(c4);
}
}
}
unsigned char *cuEnc64(const unsigned char *inbuf,
unsigned inlen,
unsigned *outlen) {
return cuEnc64WithLines(inbuf, inlen, 0, outlen);
}
unsigned char *cuEnc64WithLines(const unsigned char *inbuf,
unsigned inlen,
unsigned linelen,
unsigned *outlen)
{
unsigned outTextLen;
unsigned len; unsigned olen = 0; unsigned char *outbuf;
unsigned char endbuf[3];
unsigned i;
unsigned char *outp;
unsigned numLines;
unsigned thisLine;
outTextLen = ((inlen + 2) / 3) * 4;
if(linelen) {
if((linelen & 0x03) != 0) {
linelen = (linelen + 3) & 0xfffffffc;
}
numLines = (outTextLen + linelen - 1)/ linelen;
}
else {
numLines = 1;
}
len = outTextLen + (2 * numLines) + 1;
outbuf = (unsigned char*)malloc(len);
outp = outbuf;
thisLine = 0;
while(inlen) {
if(inlen < 3) {
for(i=0; i<3; i++) {
if(i < inlen) {
endbuf[i] = inbuf[i];
}
else {
endbuf[i] = 0;
}
}
encChunk(endbuf, outp, inlen);
inlen = 0;
}
else {
encChunk(inbuf, outp, 3);
inlen -= 3;
inbuf += 3;
}
outp += 4;
thisLine += 4;
olen += 4;
if((linelen != 0) && (thisLine >= linelen) && inlen) {
*outp++ = '\n';
olen++;
thisLine = 0;
}
}
*outp++ = '\n';
*outp = '\0';
olen += 2;
*outlen = olen;
return outbuf;
}
static inline int isWhite(unsigned char c)
{
switch(c) {
case '\n':
case '\r':
case ' ':
case '\t':
case '\0':
return 1;
default:
return 0;
}
}
static unsigned char *stringCleanse(const unsigned char *inbuf,
unsigned inlen,
unsigned *outlen)
{
unsigned char *news; unsigned newsDex; unsigned i;
news = (unsigned char*)malloc(inlen);
newsDex = 0;
for(i=0; i<inlen; i++) {
if(!isWhite(inbuf[i])) {
news[newsDex++] = inbuf[i];
}
}
*outlen = newsDex;
return news;
}
unsigned char *cuDec64(const unsigned char *inbuf,
unsigned inlen,
unsigned *outlen)
{
unsigned char *outbuf;
unsigned char *outp; unsigned obuflen;
const unsigned char *bp;
unsigned olen = 0; unsigned char c1, c2, c3, c4;
unsigned char j;
unsigned thisOlen;
unsigned char *news; unsigned newsLen;
news = stringCleanse(inbuf, inlen, &newsLen);
if((newsLen & 0x03) != 0) {
free(news);
return (unsigned char*) NULL;
}
inlen = newsLen;
bp = news;
obuflen = (inlen / 4) * 3;
outbuf = (unsigned char*)malloc(obuflen);
outp = outbuf;
while (inlen) {
if (*bp & 0x80 || (c1 = asctobin[*bp]) & 0x80) {
goto errorOut;
}
inlen--;
bp++;
if (*bp & 0x80 || (c2 = asctobin[*bp]) & 0x80){
goto errorOut;
}
inlen--;
bp++;
if (*bp == PAD) {
c3 = c4 = 0;
thisOlen = 1;
if (c2 & 0xf) {
goto errorOut;
}
bp++;
inlen--;
if (*bp == PAD) {
bp++;
inlen--;
if(inlen > 0) {
goto errorOut;
}
}
else {
goto errorOut;
}
} else if (*bp & 0x80 || (c3 = asctobin[*bp]) & 0x80) {
goto errorOut;
} else {
bp++;
inlen--;
if (*bp == PAD) {
c4 = 0;
thisOlen = 2;
if (c3 & 3) {
goto errorOut;
}
} else if (*bp & 0x80 || (c4 = asctobin[*bp]) & 0x80) {
goto errorOut;
} else {
thisOlen = 3;
}
bp++;
inlen--;
}
j = (c1 << 2) | (c2 >> 4);
*outp++ = j;
if(thisOlen > 1) {
j = (c2 << 4) | (c3 >> 2);
*outp++ = j;
if(thisOlen == 3) {
j = (c3 << 6) | c4;
*outp++ = j;
}
}
olen += thisOlen;
}
free(news);
*outlen = olen;
return outbuf;
errorOut:
free(news);
free(outbuf);
return (unsigned char*) NULL;
}
int cuIsValidEnc64(const unsigned char *inbuf,
unsigned inlen)
{
int padChars = 0; int validEncChars = 0;
unsigned char c;
while(inlen) {
c = *inbuf++;
inlen--;
if(isWhite(c)) {
continue;
}
if(c == PAD) {
if(++padChars > 2) {
return 0; }
}
else if(padChars > 0) {
return 0; }
else if((c & 0x80) || ((asctobin[c]) & 0x80)) {
return 0; }
validEncChars++;
}
if((validEncChars & 0x03) != 0) {
return 0;
}
else {
return 1;
}
}
static const char *findStr(
const char *inText,
unsigned inTextLen,
const char *str) {
const char *cp;
size_t srchStrLen = strlen(str);
char c = str[0];
const char *endCp = inText + inTextLen - srchStrLen;
for(cp=inText; cp<=endCp; cp++) {
if(*cp == c) {
if(!memcmp(cp, str, srchStrLen)) {
return cp;
}
}
}
return NULL;
}
static const char *getLine(
const char *inText,
unsigned inTextLen, unsigned *consumed)
{
*consumed = 0;
const char *cp = inText;
const char *newline = NULL;
while(inTextLen) {
char c = *cp;
if((c == '\r') || (c == '\n')) {
if(newline == NULL) {
newline = cp;
}
}
else if(newline != NULL) {
break;
}
(*consumed)++;
inTextLen--;
cp++;
}
ptrdiff_t linelen;
if(newline) {
linelen = newline - inText;
}
else {
linelen = *consumed;
}
char *rtn = (char *)malloc(linelen + 1);
memmove(rtn, inText, linelen);
rtn[linelen] = 0;
return rtn;
}
#define UNSUPPORTED_FORMAT_ERR -25256
int cuConvertPem(
const unsigned char *inbuf,
unsigned inlen,
unsigned char **outbuf, unsigned *outlen) {
unsigned lenToGo = (inlen) ? inlen : 0;
const char *currCp = (inbuf) ? (const char *)inbuf : NULL;
const char *currLine = NULL; unsigned consumed;
int ortn = 0;
const char *start64;
unsigned base64Len;
const char *end64;
unsigned char *decData;
unsigned decDataLen;
const char *startLine = findStr(currCp, lenToGo, "-----BEGIN");
if(startLine != NULL) {
consumed = (unsigned)(startLine - currCp);
lenToGo -= consumed;
currCp = startLine;
currLine = getLine(startLine, lenToGo, &consumed);
if(currLine == NULL) {
ortn = UNSUPPORTED_FORMAT_ERR;
goto errOut;
}
currCp += consumed;
lenToGo -= consumed;
free((void *)currLine);
}
for( ; ; ) {
currLine = getLine(currCp, lenToGo, &consumed);
if(currLine == NULL) {
ortn = UNSUPPORTED_FORMAT_ERR;
goto errOut;
}
int skipThis = 0;
size_t lineLen = strlen(currLine);
if(lineLen == 0) {
skipThis = 1;
}
free((void *)currLine);
if(!skipThis) {
break;
}
currCp += consumed;
lenToGo -= consumed;
}
if(lenToGo == 0) {
ortn = UNSUPPORTED_FORMAT_ERR;
goto errOut;
}
start64 = currCp;
base64Len = lenToGo; end64 = findStr(currCp, lenToGo, "-----END");
if(end64 != NULL) {
if(end64 == start64) {
ortn = UNSUPPORTED_FORMAT_ERR;
goto errOut;
}
base64Len = (unsigned)(end64 - start64);
}
decData = cuDec64((const unsigned char *)start64, base64Len, &decDataLen);
if(decData == NULL) {
ortn = UNSUPPORTED_FORMAT_ERR;
goto errOut;
}
if(outlen) {
*outlen = decDataLen;
}
if(outbuf) {
*outbuf = decData;
}
else {
free((void *)decData);
}
errOut:
return ortn;
}