/* Copyright (C) 2021 Gentoo-libre Install This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 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 General Public License along with this program. If not, see . */ #include #include #include //for CHAR_BIT #include "decode.h"//for stripNewlines() //macros for writing bits #define BITMASK(b) (1 << ((b) % CHAR_BIT)) #define BITSLOT(b) ((b) / CHAR_BIT) #define BITSET(a, b) ((a)[BITSLOT(b)] |= BITMASK(b)) #define BITCLEAR(a, b) ((a)[BITSLOT(b)] &= ~BITMASK(b)) //#define BITTEST(a, b) ((a)[BITSLOT(b)] & BITMASK(b)) //#define BITNSLOTS(nb) ((nb + CHAR_BIT - 1) / CHAR_BIT) //base64Decode: Decodes base64 into binary output data. Takes a pointer to a '\0' terminated input string and the size of the string, not including '\0' (e.g. strlen(string)) int base64Decode(unsigned char *string, int size) { if (!size){return -1;}//Catches the case of feeding the function a negative or 0 length. //strip newlines from input string, since handling them in body is too painful/slow size = stripNewlines(string, size); //printf("%d\n", size); //printf("%s\n", string); //printf("%d\n", size%4); if (size % 4 != 0){return -1;}//if the number of base64 characters sent can't be perfectly divided by 4, the base64 string is invalid. int base64value;//input char converted to it's matching base64 value int i;//i is located at the position of the char currently being processed int outputPos = 0;//i and the output string doesn't match up //needs +1 to work "correctly" (for 4 chars anyway) for (i=0; i+1= 'a')){base64value = string[i] - 71; goto firstChar;} if ((string[i] <= 'Z')&&(string[i] >= 'A')){base64value = string[i] - 65; goto firstChar;} if ((string[i] <= '9')&&(string[i] >= '0')){base64value = string[i] + 4; goto firstChar;} if (string[i] == '+'){base64value = 62; goto firstChar;} if (string[i] == '/'){base64value = 63; goto firstChar;} else{return -1;}//not a base64 character firstChar:; //printf("%d\n", base64value); //clear the output byte ready for bitset string[outputPos] = '\0'; /* | string[0] | |X|X|X|X|X|X|X|X| |7|6|5|4|3|2|1|0| |-|-|-|-|-|-| */ //bitset the output char to the correct value if (base64value >= 32){BITSET(string+outputPos,7); base64value -= 32;}//if base64value >= 32, the h if (base64value >= 16){BITSET(string+outputPos,6); base64value -= 16;} if (base64value >= 8){BITSET(string+outputPos,5); base64value -= 8;} if (base64value >= 4){BITSET(string+outputPos,4); base64value -= 4;} if (base64value >= 2){BITSET(string+outputPos,3); base64value -= 2;} if (base64value >= 1){BITSET(string+outputPos,2);} ++i; if ((string[i] <= 'z')&&(string[i] >= 'a')){base64value = string[i] - 71; goto secondChar;} if ((string[i] <= 'Z')&&(string[i] >= 'A')){base64value = string[i] - 65; goto secondChar;} if ((string[i] <= '9')&&(string[i] >= '0')){base64value = string[i] + 4; goto secondChar;} if (string[i] == '+'){base64value = 62; goto secondChar;} if (string[i] == '/'){base64value = 63; goto secondChar;} else{return -1;}//not a base64 character secondChar:; //printf("%d\n", base64value); /* | string0] | |7|6|5|4|3|2|1|0| |-|-| */ if (base64value >= 32){BITSET(string+outputPos,1); base64value -= 32;} if (base64value >= 16){BITSET(string+outputPos,0); base64value -= 16;} ++outputPos; //clear the output byte ready for bitset string[outputPos] = '\0'; /* | string[0] | string[1] | |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0| |-|-|-|-| */ //bits 4-7 of second char if (base64value >= 8){BITSET(string+outputPos,7); base64value -= 8;} if (base64value >= 4){BITSET(string+outputPos,6); base64value -= 4;} if (base64value >= 2){BITSET(string+outputPos,5); base64value -= 2;} if (base64value >= 1){BITSET(string+outputPos,4);} ++i; if ((string[i] <= 'z')&&(string[i] >= 'a')){base64value = string[i] - 71; goto thirdChar;} if ((string[i] <= 'Z')&&(string[i] >= 'A')){base64value = string[i] - 65; goto thirdChar;} if ((string[i] <= '9')&&(string[i] >= '0')){base64value = string[i] + 4; goto thirdChar;} if (string[i] == '+'){base64value = 62; goto thirdChar;} if (string[i] == '/'){base64value = 63; goto thirdChar;} if (string[i] == '='){return outputPos;}//if padding character detected, just return else{return -1;}//not a base64 character thirdChar:; //printf("%d\n", base64value); /* | string[0] | string[1] | |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0| |-|-|-|-| */ if (base64value >= 32){BITSET(string+outputPos,3); base64value -= 32;} if (base64value >= 16){BITSET(string+outputPos,2); base64value -= 16;} if (base64value >= 8){BITSET(string+outputPos,1); base64value -= 8;} if (base64value >= 4){BITSET(string+outputPos,0); base64value -= 4;} ++outputPos; //clear the output byte ready for bitset string[outputPos] = '\0'; /* | string[0] | string[1] | string[2] | |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0| |-|-| */ if (base64value >= 2){BITSET(string+outputPos,7); base64value -= 2;} if (base64value >= 1){BITSET(string+outputPos,6); --base64value;} ++i; if ((string[i] <= 'z')&&(string[i] >= 'a')){base64value = string[i] - 71; goto forthChar;} if ((string[i] <= 'Z')&&(string[i] >= 'A')){base64value = string[i] - 65; goto forthChar;} if ((string[i] <= '9')&&(string[i] >= '0')){base64value = string[i] + 4; goto forthChar;} if (string[i] == '+'){base64value = 62; goto forthChar;} if (string[i] == '/'){base64value = 63; goto forthChar;} if (string[i] == '='){return outputPos;}//if padding character detected, just return else{return -1;}//not a base64 character forthChar:; //printf("%d\n", base64value); /* | string[0] | string[1] | string[2] | |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0| |-|-|-|-|-|-| */ if (base64value >= 32){BITSET(string+outputPos,5); base64value -= 32;} if (base64value >= 16){BITSET(string+outputPos,4); base64value -= 16;} if (base64value >= 8){BITSET(string+outputPos,3); base64value -= 8;} if (base64value >= 4){BITSET(string+outputPos,2); base64value -= 4;} if (base64value >= 2){BITSET(string+outputPos,1); base64value -= 2;} if (base64value >= 1){BITSET(string+outputPos,0);} ++outputPos; } return outputPos; }