1 /* base64 contains the needed support for base64 alphabet system, */ 2 /* as described in RFC1521 */ 3 /* 4 Copyright 2003,04 Aris Adamantiadis 5 6 This file is part of the SSH Library 7 8 The SSH Library is free software; you can redistribute it and/or modify 9 it under the terms of the GNU Lesser General Public License as published by 10 the Free Software Foundation; either version 2.1 of the License, or (at your 11 option) any later version. 12 13 The SSH Library is distributed in the hope that it will be useful, but 14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 16 License for more details. 17 18 You should have received a copy of the GNU Lesser General Public License 19 along with the SSH Library; see the file COPYING. If not, write to 20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, 21 MA 02111-1307, USA. */ 22 23 /* just the dirtiest part of code i ever made */ 24 #include <string.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include "libssh/priv.h" 28 static char alphabet[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ" 29 "abcdefghijklmnopqrstuvwxyz" 30 "0123456789+/" ; 31 32 /* transformations */ 33 #define SET_A(n,i) do { n |= (i&63) <<18; } while (0) 34 #define SET_B(n,i) do { n |= (i&63) <<12; } while (0) 35 #define SET_C(n,i) do { n |= (i&63) << 6; } while (0) 36 #define SET_D(n,i) do { n |= (i&63); } while (0) 37 38 #define GET_A(n) ((n & 0xff0000) >> 16) 39 #define GET_B(n) ((n & 0xff00) >> 8) 40 #define GET_C(n) (n & 0xff) 41 42 static int _base64_to_bin(unsigned char dest[3], char *source,int num); 43 static int get_equals(char *string); 44 45 /* first part : base 64 to binary */ 46 47 /* base64_to_bin translates a base64 string into a binary one. important, if something went wrong (ie incorrect char)*/ 48 /* it returns NULL */ 49 BUFFER *base64_to_bin(char *source){ 50 int len; 51 int equals; 52 BUFFER *buffer=buffer_new(); 53 unsigned char block[3]; 54 55 /* get the number of equals signs, which mirrors the padding */ 56 equals=get_equals(source); 57 if(equals>2){ 58 buffer_free(buffer); 59 return NULL; 60 } 61 62 len=strlen(source); 63 while(len>4){ 64 if(_base64_to_bin(block,source,3)){ 65 buffer_free(buffer); 66 return NULL; 67 } 68 buffer_add_data(buffer,block,3); 69 len-=4; 70 source+=4; 71 } 72 /* depending of the number of bytes resting, there are 3 possibilities (from the rfc) */ 73 switch(len){ 74 /* (1) the final quantum of encoding input is an integral 75 multiple of 24 bits; here, the final unit of encoded output will be 76 an integral multiple of 4 characters with no "=" padding */ 77 case 4: 78 if(equals!=0){ 79 buffer_free(buffer); 80 return NULL; 81 } 82 if(_base64_to_bin(block,source,3)){ 83 buffer_free(buffer); 84 return NULL; 85 } 86 buffer_add_data(buffer,block,3); 87 return buffer; 88 /*(2) the final quantum of encoding input is exactly 8 bits; here, the final 89 unit of encoded output will be two characters followed by two "=" 90 padding characters */ 91 case 2: 92 if(equals!=2){ 93 buffer_free(buffer); 94 return NULL; 95 } 96 if(_base64_to_bin(block,source,1)){ 97 buffer_free(buffer); 98 return NULL; 99 } 100 buffer_add_data(buffer,block,1); 101 return buffer; 102 /* the final quantum of encoding input is 103 exactly 16 bits; here, the final unit of encoded output will be three 104 characters followed by one "=" padding character */ 105 case 3: 106 if(equals!=1){ 107 buffer_free(buffer); 108 return NULL; 109 } 110 if(_base64_to_bin(block,source,2)){ 111 buffer_free(buffer); 112 return NULL; 113 } 114 buffer_add_data(buffer,block,2); 115 return buffer; 116 default: 117 /* 4,3,2 are the only padding size allowed */ 118 buffer_free(buffer); 119 return NULL; 120 } 121 return NULL; 122 } 123 124 #define BLOCK(letter,n) do { ptr=strchr(alphabet,source[n]);\ 125 if(!ptr) return -1;\ 126 i=ptr-alphabet;\ 127 SET_##letter(*block,i);\ 128 } while(0) 129 /* returns 0 if ok, -1 if not (ie invalid char into the stuff) */ 130 static int to_block4(unsigned long *block, char *source,int num){ 131 char *ptr; 132 unsigned int i; 133 *block=0; 134 if(num<1) 135 return 0; 136 BLOCK(A,0); /* 6 bits */ 137 BLOCK(B,1); /* 12 */ 138 if(num<2) 139 return 0; 140 BLOCK(C,2); /* 18 */ 141 if(num < 3) 142 return 0; 143 BLOCK(D,3); /* 24 */ 144 return 0; 145 } 146 147 /* num = numbers of final bytes to be decoded */ 148 static int _base64_to_bin(unsigned char dest[3], char *source,int num){ 149 unsigned long block; 150 if(to_block4(&block,source,num)) 151 return -1; 152 dest[0]=GET_A(block); 153 dest[1]=GET_B(block); 154 dest[2]=GET_C(block); 155 return 0; 156 } 157 158 /* counts the number of "=" signs, and replace them by zeroes */ 159 static int get_equals(char *string){ 160 char *ptr=string; 161 int num=0; 162 while((ptr=strchr(ptr,'='))){ 163 num++; 164 *ptr=0; 165 ptr++; 166 } 167 168 return num; 169 } 170 171 /* thanks sysk for debugging my mess :) */ 172 #define BITS(n) ((1<<n)-1) 173 static void _bin_to_base64(unsigned char *dest, unsigned char source[3], int len){ 174 switch (len){ 175 case 1: 176 dest[0]=alphabet[(source[0]>>2)]; 177 dest[1]=alphabet[((source[0] & BITS(2)) << 4)]; 178 dest[2]='='; 179 dest[3]='='; 180 break; 181 case 2: 182 dest[0]=alphabet[source[0]>>2]; 183 dest[1]=alphabet[(source[1]>>4) | ((source[0] & BITS(2)) << 4)]; 184 dest[2]=alphabet[(source[1]&BITS(4)) << 2]; 185 dest[3]='='; 186 break; 187 case 3: 188 dest[0]=alphabet[(source[0]>>2)]; 189 dest[1]=alphabet[(source[1]>>4) | ((source[0] & BITS(2)) << 4)]; 190 dest[2]=alphabet[ (source[2] >> 6) | (source[1]&BITS(4)) << 2]; 191 dest[3]=alphabet[source[2]&BITS(6)]; 192 break; 193 } 194 } 195 196 char *bin_to_base64(unsigned char *source, int len){ 197 int flen=len + (3 - (len %3)); /* round to upper 3 multiple */ 198 char *buffer; 199 char *ptr; 200 flen=(4 * flen)/3 + 1 ; 201 ptr=buffer=malloc(flen); 202 while(len>0){ 203 _bin_to_base64(ptr,source,len>3?3:len); 204 ptr+=4; 205 source +=3; 206 len -=3; 207 } 208 ptr[0]=0; 209 return buffer; 210 } |