anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

base64.cpp (5053B)

      1 /* base64 routines.
      2  *
      3  * (C) 2003-2022 Anope Team
      4  * Contact us at team@anope.org
      5  *
      6  * Please read COPYING and README for further details.
      7  *
      8  * Based on the original code of Epona by Lara.
      9  * Based on the original code of Services by Andy Church.
     10  */
     11 
     12 #include "services.h"
     13 #include "anope.h"
     14 
     15 static const Anope::string Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     16 static const char Pad64 = '=';
     17 
     18 /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
     19    The following encoding technique is taken from RFC 1521 by Borenstein
     20    and Freed.  It is reproduced here in a slightly edited form for
     21    convenience.
     22 
     23    A 65-character subset of US-ASCII is used, enabling 6 bits to be
     24    represented per printable character. (The extra 65th character, "=",
     25    is used to signify a special processing function.)
     26 
     27    The encoding process represents 24-bit groups of input bits as output
     28    strings of 4 encoded characters. Proceeding from left to right, a
     29    24-bit input group is formed by concatenating 3 8-bit input groups.
     30    These 24 bits are then treated as 4 concatenated 6-bit groups, each
     31    of which is translated into a single digit in the base64 alphabet.
     32 
     33    Each 6-bit group is used as an index into an array of 64 printable
     34    characters. The character referenced by the index is placed in the
     35    output string.
     36 
     37 						 Table 1: The Base64 Alphabet
     38 
     39 	  Value Encoding  Value Encoding  Value Encoding  Value Encoding
     40 		  0 A			17 R			34 i			51 z
     41 		  1 B			18 S			35 j			52 0
     42 		  2 C			19 T			36 k			53 1
     43 		  3 D			20 U			37 l			54 2
     44 		  4 E			21 V			38 m			55 3
     45 		  5 F			22 W			39 n			56 4
     46 		  6 G			23 X			40 o			57 5
     47 		  7 H			24 Y			41 p			58 6
     48 		  8 I			25 Z			42 q			59 7
     49 		  9 J			26 a			43 r			60 8
     50 		 10 K			27 b			44 s			61 9
     51 		 11 L			28 c			45 t			62 +
     52 		 12 M			29 d			46 u			63 /
     53 		 13 N			30 e			47 v
     54 		 14 O			31 f			48 w		 (pad) =
     55 		 15 P			32 g			49 x
     56 		 16 Q			33 h			50 y
     57 
     58    Special processing is performed if fewer than 24 bits are available
     59    at the end of the data being encoded.  A full encoding quantum is
     60    always completed at the end of a quantity.  When fewer than 24 input
     61    bits are available in an input group, zero bits are added (on the
     62    right) to form an integral number of 6-bit groups.  Padding at the
     63    end of the data is performed using the '=' character.
     64 
     65    Since all base64 input is an integral number of octets, only the
     66 		 -------------------------------------------------
     67    following cases can arise:
     68 
     69 	   (1) the final quantum of encoding input is an integral
     70 		   multiple of 24 bits; here, the final unit of encoded
     71 	   output will be an integral multiple of 4 characters
     72 	   with no "=" padding,
     73 	   (2) the final quantum of encoding input is exactly 8 bits;
     74 		   here, the final unit of encoded output will be two
     75 	   characters followed by two "=" padding characters, or
     76 	   (3) the final quantum of encoding input is exactly 16 bits;
     77 		   here, the final unit of encoded output will be three
     78 	   characters followed by one "=" padding character.
     79    */
     80 
     81 void Anope::B64Encode(const Anope::string &src, Anope::string &target)
     82 {
     83 	size_t src_pos = 0, src_len = src.length();
     84 	unsigned char input[3] = { '\0', '\0', '\0' };
     85 
     86 	target.clear();
     87 
     88 	while (src_len - src_pos > 2)
     89 	{
     90 		input[0] = src[src_pos++];
     91 		input[1] = src[src_pos++];
     92 		input[2] = src[src_pos++];
     93 
     94 		target += Base64[input[0] >> 2];
     95 		target += Base64[((input[0] & 0x03) << 4) + (input[1] >> 4)];
     96 		target += Base64[((input[1] & 0x0f) << 2) + (input[2] >> 6)];
     97 		target += Base64[input[2] & 0x3f];
     98 	}
     99 
    100 	/* Now we worry about padding */
    101 	if (src_pos != src_len)
    102 	{
    103 		input[0] = input[1] = input[2] = 0;
    104 		for (size_t i = 0; i < src_len - src_pos; ++i)
    105 			input[i] = src[src_pos + i];
    106 
    107 		target += Base64[input[0] >> 2];
    108 		target += Base64[((input[0] & 0x03) << 4) + (input[1] >> 4)];
    109 		if (src_pos == src_len - 1)
    110 			target += Pad64;
    111 		else
    112 			target += Base64[((input[1] & 0x0f) << 2) + (input[2] >> 6)];
    113 		target += Pad64;
    114 	}
    115 }
    116 
    117 /* skips all whitespace anywhere.
    118    converts characters, four at a time, starting at (or after)
    119    src from base - 64 numbers into three 8 bit bytes in the target area.
    120  */
    121 
    122 void Anope::B64Decode(const Anope::string &src, Anope::string &target)
    123 {
    124 	target.clear();
    125 
    126 	unsigned state = 0;
    127 	Anope::string::const_iterator ch = src.begin(), end = src.end();
    128 	for (; ch != end; ++ch)
    129 	{
    130 		if (isspace(*ch)) /* Skip whitespace anywhere */
    131 			continue;
    132 
    133 		if (*ch == Pad64)
    134 			break;
    135 
    136 		size_t pos = Base64.find(*ch);
    137 		if (pos == Anope::string::npos) /* A non-base64 character */
    138 			return;
    139 
    140 		switch (state)
    141 		{
    142 			case 0:
    143 				target += pos << 2;
    144 				state = 1;
    145 				break;
    146 			case 1:
    147 				target[target.length() - 1] |= pos >> 4;
    148 				target += (pos & 0x0f) << 4;
    149 				state = 2;
    150 				break;
    151 			case 2:
    152 				target[target.length() - 1] |= pos >> 2;
    153 				target += (pos & 0x03) << 6;
    154 				state = 3;
    155 				break;
    156 			case 3:
    157 				target[target.length() - 1] |= pos;
    158 				state = 0;
    159 		}
    160 	}
    161 	if (!target.empty() && !target[target.length() - 1])
    162 		target.erase(target.length() - 1);
    163 }