You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
211 lines
6.5 KiB
211 lines
6.5 KiB
/* base64 contains the needed support for base64 alphabet system, */
|
|
/* as described in RFC1521 */
|
|
/*
|
|
Copyright 2003,04 Aris Adamantiadis
|
|
|
|
This file is part of the SSH Library
|
|
|
|
The SSH 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.
|
|
|
|
The SSH 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 the SSH Library; see the file COPYING. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
/* just the dirtiest part of code i ever made */
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "priv.h"
|
|
static char alphabet[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|
"0123456789+/" ;
|
|
|
|
/* transformations */
|
|
#define SET_A(n,i) do { n |= (i&63) <<18; } while (0)
|
|
#define SET_B(n,i) do { n |= (i&63) <<12; } while (0)
|
|
#define SET_C(n,i) do { n |= (i&63) << 6; } while (0)
|
|
#define SET_D(n,i) do { n |= (i&63); } while (0)
|
|
|
|
#define GET_A(n) ((n & 0xff0000) >> 16)
|
|
#define GET_B(n) ((n & 0xff00) >> 8)
|
|
#define GET_C(n) (n & 0xff)
|
|
|
|
static int _base64_to_bin(unsigned char dest[3], char *source,int num);
|
|
static int get_equals(char *string);
|
|
|
|
/* first part : base 64 to binary */
|
|
|
|
/* base64_to_bin translates a base64 string into a binary one. important, if something went wrong (ie incorrect char)*/
|
|
/* it returns NULL */
|
|
BUFFER *base64_to_bin(char *source){
|
|
int len;
|
|
int equals;
|
|
BUFFER *buffer=buffer_new();
|
|
unsigned char block[3];
|
|
|
|
/* get the number of equals signs, which mirrors the padding */
|
|
equals=get_equals(source);
|
|
if(equals>2){
|
|
buffer_free(buffer);
|
|
return NULL;
|
|
}
|
|
|
|
len=strlen(source);
|
|
while(len>4){
|
|
if(_base64_to_bin(block,source,3)){
|
|
buffer_free(buffer);
|
|
return NULL;
|
|
}
|
|
buffer_add_data(buffer,block,3);
|
|
len-=4;
|
|
source+=4;
|
|
}
|
|
/* depending of the number of bytes resting, there are 3 possibilities (from the rfc) */
|
|
switch(len){
|
|
/* (1) the final quantum of encoding input is an integral
|
|
multiple of 24 bits; here, the final unit of encoded output will be
|
|
an integral multiple of 4 characters with no "=" padding */
|
|
case 4:
|
|
if(equals!=0){
|
|
buffer_free(buffer);
|
|
return NULL;
|
|
}
|
|
if(_base64_to_bin(block,source,3)){
|
|
buffer_free(buffer);
|
|
return NULL;
|
|
}
|
|
buffer_add_data(buffer,block,3);
|
|
return buffer;
|
|
/*(2) the final quantum of encoding input is exactly 8 bits; here, the final
|
|
unit of encoded output will be two characters followed by two "="
|
|
padding characters */
|
|
case 2:
|
|
if(equals!=2){
|
|
buffer_free(buffer);
|
|
return NULL;
|
|
}
|
|
if(_base64_to_bin(block,source,1)){
|
|
buffer_free(buffer);
|
|
return NULL;
|
|
}
|
|
buffer_add_data(buffer,block,1);
|
|
return buffer;
|
|
/* the final quantum of encoding input is
|
|
exactly 16 bits; here, the final unit of encoded output will be three
|
|
characters followed by one "=" padding character */
|
|
case 3:
|
|
if(equals!=1){
|
|
buffer_free(buffer);
|
|
return NULL;
|
|
}
|
|
if(_base64_to_bin(block,source,2)){
|
|
buffer_free(buffer);
|
|
return NULL;
|
|
}
|
|
buffer_add_data(buffer,block,2);
|
|
return buffer;
|
|
default:
|
|
/* 4,3,2 are the only padding size allowed */
|
|
buffer_free(buffer);
|
|
return NULL;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#define BLOCK(letter,n) do { ptr=strchr(alphabet,source[n]);\
|
|
if(!ptr) return -1;\
|
|
i=ptr-alphabet;\
|
|
SET_##letter(*block,i);\
|
|
} while(0)
|
|
/* returns 0 if ok, -1 if not (ie invalid char into the stuff) */
|
|
static int to_block4(unsigned long *block, char *source,int num){
|
|
char *ptr;
|
|
unsigned int i;
|
|
*block=0;
|
|
if(num<1)
|
|
return 0;
|
|
BLOCK(A,0); /* 6 bits */
|
|
BLOCK(B,1); /* 12 */
|
|
if(num<2)
|
|
return 0;
|
|
BLOCK(C,2); /* 18 */
|
|
if(num < 3)
|
|
return 0;
|
|
BLOCK(D,3); /* 24 */
|
|
return 0;
|
|
}
|
|
|
|
/* num = numbers of final bytes to be decoded */
|
|
static int _base64_to_bin(unsigned char dest[3], char *source,int num){
|
|
unsigned long block;
|
|
if(to_block4(&block,source,num))
|
|
return -1;
|
|
dest[0]=GET_A(block);
|
|
dest[1]=GET_B(block);
|
|
dest[2]=GET_C(block);
|
|
return 0;
|
|
}
|
|
|
|
/* counts the number of "=" signs, and replace them by zeroes */
|
|
static int get_equals(char *string){
|
|
char *ptr=string;
|
|
int num=0;
|
|
while((ptr=strchr(ptr,'='))){
|
|
num++;
|
|
*ptr=0;
|
|
ptr++;
|
|
}
|
|
|
|
return num;
|
|
}
|
|
|
|
/* thanks sysk for debugging my mess :) */
|
|
#define BITS(n) ((1<<n)-1)
|
|
static void _bin_to_base64(unsigned char *dest, unsigned char source[3], int len){
|
|
switch (len){
|
|
case 1:
|
|
dest[0]=alphabet[(source[0]>>2)];
|
|
dest[1]=alphabet[((source[0] & BITS(2)) << 4)];
|
|
dest[2]='=';
|
|
dest[3]='=';
|
|
break;
|
|
case 2:
|
|
dest[0]=alphabet[source[0]>>2];
|
|
dest[1]=alphabet[(source[1]>>4) | ((source[0] & BITS(2)) << 4)];
|
|
dest[2]=alphabet[(source[1]&BITS(4)) << 2];
|
|
dest[3]='=';
|
|
break;
|
|
case 3:
|
|
dest[0]=alphabet[(source[0]>>2)];
|
|
dest[1]=alphabet[(source[1]>>4) | ((source[0] & BITS(2)) << 4)];
|
|
dest[2]=alphabet[ (source[2] >> 6) | (source[1]&BITS(4)) << 2];
|
|
dest[3]=alphabet[source[2]&BITS(6)];
|
|
break;
|
|
}
|
|
}
|
|
|
|
char *bin_to_base64(unsigned char *source, int len){
|
|
int flen=len + (3 - (len %3)); /* round to upper 3 multiple */
|
|
char *buffer;
|
|
char *ptr;
|
|
flen=(4 * flen)/3 + 1 ;
|
|
ptr=buffer=malloc(flen);
|
|
while(len>0){
|
|
_bin_to_base64(ptr,source,len>3?3:len);
|
|
ptr+=4;
|
|
source +=3;
|
|
len -=3;
|
|
}
|
|
ptr[0]=0;
|
|
return buffer;
|
|
}
|