/*
* The protocol (specifically simple auth extension) needs to encode
* data in base64. There are libraries to do this, but I coded it up
* to avoid creating a library dependence.
*/
/* Return the base 64 character for the value 0-63. RFC 4648 */
inline char base64char(unsigned char val)
{
if(val <= 25) return 'A' + val;
if(val <= 51) return 'a' - 26 + val;
if(val <= 61) return '0' + val - 52;
if(val == 62) return '+';
return '/';
}
/*
Create a authorization string containing the account and password
encoded with base64. This absurdity is defined in RFCs 4954 and 4616
in some of the most remarkably opaque writing imaginable.
*/
string authstring(string acct, string passwd)
{
// The basic string is a an (empty) "authorization identity,"
// an account and password all separated by a null characters.
string authstring = string(1,'\0') + acct + string(1,'\0') + passwd;
/* Now we need to create the base64 version.
Encode a block of bytes into a base64 string.
Each group of three bytes is coded as four characters.
aaaaaabb ccccdddd eeffffff
aaaaaa bbcccc ddddee ffffff
3 2 1 0 Phase
The algorithm below cycles through the four phases, which directs
how to generate generate the output character. */
// Scan the range of characters inside the created string.
unsigned char *scan =
reinterpret_cast<unsigned char *>(authstring.data());
unsigned char *end = scan + authstring.size();
int phase = 0; // Current phase (see above).
string ret = ""; // Return value.
ret.reserve(4*((authstring.size()+2)/3));
// Should be size of result.
// Process the input characters.
while(scan < end) {
// The next input byte, or 0 if none.
unsigned char next = scan < end-1 ? scan[1] : 0;
// Increment the phase. Well, decrement except 0 wraps to 3.
phase = phase?phase-1:3;
// Extract the character based on the phase. Also controls
// increment of the input pointer, which differs by phase.
switch(phase) {
case 3:
ret += base64char(*scan >> 2);
break;
case 2:
ret += base64char(((*scan++ & 0x3) << 4) | (next >> 4));
break;
case 1:
ret += base64char(((*scan++ & 0xf) << 2) |
((next & 0xc0) >> 6));
break;
case 0:
ret += base64char(*scan++ & 0x3f);
}
}
// If there's a partial group at the end, fill with =.
while(phase--) ret += '=';
return ret;
}