blob: ea450583dc97a3020ceead7fcf7f8eeab2fd76a7 [file] [log] [blame]
/*
* Copyright (C) Tildeslash Ltd. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
*
* You must obey the GNU Affero General Public License in all respects
* for all of the code used other than OpenSSL.
*/
#include "config.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "monit.h"
#include "base64.h"
/**
* Implementation of base64 encoding/decoding.
*
* @file
*/
/* ----------------------------------------------------------------- Private */
/**
* Base64 encode one byte
*/
static char encode(unsigned char u) {
if(u < 26) return 'A'+u;
if(u < 52) return 'a'+(u-26);
if(u < 62) return '0'+(u-52);
if(u == 62) return '+';
return '/';
}
/**
* Decode a base64 character
*/
static unsigned char decode(char c) {
if(c >= 'A' && c <= 'Z') return(c - 'A');
if(c >= 'a' && c <= 'z') return(c - 'a' + 26);
if(c >= '0' && c <= '9') return(c - '0' + 52);
if(c == '+') return 62;
return 63;
}
/**
* Return TRUE if 'c' is a valid base64 character, otherwise FALSE
*/
static int is_base64(char c) {
if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') || (c == '+') ||
(c == '/') || (c == '=')) {
return TRUE;
}
return FALSE;
}
/* ------------------------------------------------------------------ Public */
/**
* Base64 encode and return size data in 'src'. The caller must free the
* returned string.
* @param size The size of the data in src
* @param src The data to be base64 encode
* @return encoded string otherwise NULL
*/
char *encode_base64(size_t size, unsigned char *src) {
int i;
char *out, *p;
if(!src)
return NULL;
if(!size)
size= strlen((char *)src);
out= CALLOC(sizeof(char), size*4/3+4);
p= out;
for(i=0; i<size; i+=3) {
unsigned char b1=0, b2=0, b3=0, b4=0, b5=0, b6=0, b7=0;
b1 = src[i];
if(i+1<size)
b2 = src[i+1];
if(i+2<size)
b3 = src[i+2];
b4= b1>>2;
b5= ((b1&0x3)<<4)|(b2>>4);
b6= ((b2&0xf)<<2)|(b3>>6);
b7= b3&0x3f;
*p++= encode(b4);
*p++= encode(b5);
if(i+1<size) {
*p++= encode(b6);
} else {
*p++= '=';
}
if(i+2<size) {
*p++= encode(b7);
} else {
*p++= '=';
}
}
return out;
}
/**
* Decode the base64 encoded string 'src' into the memory pointed to by
* 'dest'. The dest buffer is <b>not</b> NUL terminated.
* @param dest Pointer to memory for holding the decoded string.
* Must be large enough to recieve the decoded string.
* @param src A base64 encoded string.
* @return TRUE (the length of the decoded string) if decode
* succeeded otherwise FALSE.
*/
size_t decode_base64(unsigned char *dest, const char *src) {
if(src && *src) {
unsigned char *p= dest;
size_t k, l = strlen(src)+1;
unsigned char *buf= CALLOC(1, l);
/* Ignore non base64 chars as per the POSIX standard */
for(k=0, l=0; src[k]; k++) {
if(is_base64(src[k])) {
buf[l++]= src[k];
}
}
for(k=0; k<l; k+=4) {
char c1='A', c2='A', c3='A', c4='A';
unsigned char b1=0, b2=0, b3=0, b4=0;
c1= buf[k];
if(k+1<l) {
c2= buf[k+1];
}
if(k+2<l) {
c3= buf[k+2];
}
if(k+3<l) {
c4= buf[k+3];
}
b1= decode(c1);
b2= decode(c2);
b3= decode(c3);
b4= decode(c4);
*p++=((b1<<2)|(b2>>4) );
if(c3 != '=') {
*p++=(((b2&0xf)<<4)|(b3>>2) );
}
if(c4 != '=') {
*p++=(((b3&0x3)<<6)|b4 );
}
}
FREE(buf);
return(p-dest);
}
return FALSE;
}