crypto-algorithms.c

Basic implementations of standard cryptography algorithms, like AES and SHA-1
git clone git://git.finwo.net/lib/crypto-algorithms.c
Log | Files | Refs | README

base64.c (3926B)


      1 /*********************************************************************
      2 * Filename:   base64.c
      3 * Author:     Brad Conte (brad AT bradconte.com)
      4 * Copyright:
      5 * Disclaimer: This code is presented "as is" without any guarantees.
      6 * Details:    Implementation of the Base64 encoding algorithm.
      7 *********************************************************************/
      8 
      9 /*************************** HEADER FILES ***************************/
     10 #include <stdlib.h>
     11 #include "base64.h"
     12 
     13 /****************************** MACROS ******************************/
     14 #define NEWLINE_INVL 76
     15 
     16 /**************************** VARIABLES *****************************/
     17 // Note: To change the charset to a URL encoding, replace the '+' and '/' with '*' and '-'
     18 static const BYTE charset[]={"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"};
     19 
     20 /*********************** FUNCTION DEFINITIONS ***********************/
     21 BYTE revchar(char ch)
     22 {
     23 	if (ch >= 'A' && ch <= 'Z')
     24 		ch -= 'A';
     25 	else if (ch >= 'a' && ch <='z')
     26 		ch = ch - 'a' + 26;
     27 	else if (ch >= '0' && ch <='9')
     28 		ch = ch - '0' + 52;
     29 	else if (ch == '+')
     30 		ch = 62;
     31 	else if (ch == '/')
     32 		ch = 63;
     33 
     34 	return(ch);
     35 }
     36 
     37 size_t base64_encode(const BYTE in[], BYTE out[], size_t len, int newline_flag)
     38 {
     39 	size_t idx, idx2, blks, blk_ceiling, left_over, newline_count = 0;
     40 
     41 	blks = (len / 3);
     42 	left_over = len % 3;
     43 
     44 	if (out == NULL) {
     45 		idx2 = blks * 4 ;
     46 		if (left_over)
     47 			idx2 += 4;
     48 		if (newline_flag)
     49 			idx2 += len / 57;   // (NEWLINE_INVL / 4) * 3 = 57. One newline per 57 input bytes.
     50 	}
     51 	else {
     52 		// Since 3 input bytes = 4 output bytes, determine out how many even sets of
     53 		// 3 bytes the input has.
     54 		blk_ceiling = blks * 3;
     55 		for (idx = 0, idx2 = 0; idx < blk_ceiling; idx += 3, idx2 += 4) {
     56 			out[idx2]     = charset[in[idx] >> 2];
     57 			out[idx2 + 1] = charset[((in[idx] & 0x03) << 4) | (in[idx + 1] >> 4)];
     58 			out[idx2 + 2] = charset[((in[idx + 1] & 0x0f) << 2) | (in[idx + 2] >> 6)];
     59 			out[idx2 + 3] = charset[in[idx + 2] & 0x3F];
     60 			// The offical standard requires a newline every 76 characters.
     61 			// (Eg, first newline is character 77 of the output.)
     62 			if (((idx2 - newline_count + 4) % NEWLINE_INVL == 0) && newline_flag) {
     63 				out[idx2 + 4] = '\n';
     64 				idx2++;
     65 				newline_count++;
     66 			}
     67 		}
     68 
     69 		if (left_over == 1) {
     70 			out[idx2]     = charset[in[idx] >> 2];
     71 			out[idx2 + 1] = charset[(in[idx] & 0x03) << 4];
     72 			out[idx2 + 2] = '=';
     73 			out[idx2 + 3] = '=';
     74 			idx2 += 4;
     75 		}
     76 		else if (left_over == 2) {
     77 			out[idx2]     = charset[in[idx] >> 2];
     78 			out[idx2 + 1] = charset[((in[idx] & 0x03) << 4) | (in[idx + 1] >> 4)];
     79 			out[idx2 + 2] = charset[(in[idx + 1] & 0x0F) << 2];
     80 			out[idx2 + 3] = '=';
     81 			idx2 += 4;
     82 		}
     83 	}
     84 
     85 	return(idx2);
     86 }
     87 
     88 size_t base64_decode(const BYTE in[], BYTE out[], size_t len)
     89 {
     90 	size_t idx, idx2, blks, blk_ceiling, left_over;
     91 
     92 	if (in[len - 1] == '=')
     93 		len--;
     94 	if (in[len - 1] == '=')
     95 		len--;
     96 
     97 	blks = len / 4;
     98 	left_over = len % 4;
     99 
    100 	if (out == NULL) {
    101 		if (len >= 77 && in[NEWLINE_INVL] == '\n')   // Verify that newlines where used.
    102 			len -= len / (NEWLINE_INVL + 1);
    103 		blks = len / 4;
    104 		left_over = len % 4;
    105 
    106 		idx = blks * 3;
    107 		if (left_over == 2)
    108 			idx ++;
    109 		else if (left_over == 3)
    110 			idx += 2;
    111 	}
    112 	else {
    113 		blk_ceiling = blks * 4;
    114 		for (idx = 0, idx2 = 0; idx2 < blk_ceiling; idx += 3, idx2 += 4) {
    115 			if (in[idx2] == '\n')
    116 				idx2++;
    117 			out[idx]     = (revchar(in[idx2]) << 2) | ((revchar(in[idx2 + 1]) & 0x30) >> 4);
    118 			out[idx + 1] = (revchar(in[idx2 + 1]) << 4) | (revchar(in[idx2 + 2]) >> 2);
    119 			out[idx + 2] = (revchar(in[idx2 + 2]) << 6) | revchar(in[idx2 + 3]);
    120 		}
    121 
    122 		if (left_over == 2) {
    123 			out[idx]     = (revchar(in[idx2]) << 2) | ((revchar(in[idx2 + 1]) & 0x30) >> 4);
    124 			idx++;
    125 		}
    126 		else if (left_over == 3) {
    127 			out[idx]     = (revchar(in[idx2]) << 2) | ((revchar(in[idx2 + 1]) & 0x30) >> 4);
    128 			out[idx + 1] = (revchar(in[idx2 + 1]) << 4) | (revchar(in[idx2 + 2]) >> 2);
    129 			idx += 2;
    130 		}
    131 	}
    132 
    133 	return(idx);
    134 }