Refactor project structure
This commit is contained in:
395
core/anslicensing/base32.cpp
Normal file
395
core/anslicensing/base32.cpp
Normal file
@@ -0,0 +1,395 @@
|
||||
#include "precomp.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "base32.h"
|
||||
|
||||
|
||||
const char BASE32::alphabet[] = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
||||
const char BASE32::values[] = {
|
||||
/* 0 1 2 3 4 5 6 7 8 9 */ /* 0123456789 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 00 -> 09 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 10 -> 19 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 20 -> 29 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 30 -> 39 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, /* - 40 -> 47 */
|
||||
|
||||
-1,-1,24,25,26,27,28,29,30,31, /* 0123456789 - 48 -> 57 */
|
||||
-1,-1,-1,-1,-1,-1,-1, 0, 1, 2, /* :;<=>?@ABC - 58 -> 67 */
|
||||
3, 4, 5, 6, 7,-1, 8, 9,10,11, /* DEFGHIJKLM - 68 -> 77 */
|
||||
12,-1,13,14,15,16,17,18,19,20, /* NOPQRSTUVW - 78 -> 87 */
|
||||
21,22,23, /* XYZ - 88 -> 90 */
|
||||
|
||||
-1,-1,-1,-1,-1,-1, 0, 1, 2, 3, /* abcd - 91 -> 100 */
|
||||
4, 5, 6, 7,-1, 8, 9,10,11,12, /* efghijklmn - 101 -> 110 */
|
||||
-1,13,14,15,16,17,18,19,20,21, /* opqrstuvwx - 111 -> 120 */
|
||||
22,23,-1,-1,-1,-1,-1,-1,-1,-1, /* yz - 121 -> 130 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 131 -> 140 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 141 -> 150 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 151 -> 160 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 161 -> 170 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 171 -> 180 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 181 -> 190 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 191 -> 200 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 201 -> 210 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 211 -> 220 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 221 -> 230 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 231 -> 240 */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 241 -> 250 */
|
||||
-1,-1,-1,-1,-1, /* - 251 -> 255 */
|
||||
};
|
||||
|
||||
BASE32::BASE32()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BASE32::~BASE32()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
string BASE32::encode(unsigned char * buf, int len, bool padding)
|
||||
{
|
||||
int pad;
|
||||
int enclen = encode_pad_length(len, &pad);
|
||||
string encbuf;
|
||||
|
||||
if (!padding)
|
||||
pad = 0;
|
||||
|
||||
encbuf.resize(enclen + pad + 1); /* Allow for trailing NUL */
|
||||
|
||||
encode_exactly(buf, len, encbuf.data(), enclen);
|
||||
|
||||
if (pad)
|
||||
memset(encbuf.data() + enclen, '=', pad);
|
||||
|
||||
encbuf[enclen + pad] = '\0';
|
||||
|
||||
return encbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* encode_exactly
|
||||
*
|
||||
* Encode `len' bytes from `buf' into `enclen' bytes starting from `encbuf'.
|
||||
* Caller must have ensured that there was EXACTLY the needed room in encbuf.
|
||||
*/
|
||||
void BASE32::encode_exactly(const unsigned char *buf, int len, char *encbuf, int enclen)
|
||||
{
|
||||
int i = 0; /* Input accumulator, 0 for trailing pad */
|
||||
unsigned char const *ip = buf + len; /* Input pointer, one byte off end */
|
||||
char *op = encbuf + enclen; /* Output pointer, one byte off end */
|
||||
|
||||
assert(buf);
|
||||
assert(encbuf);
|
||||
assert(len > 0);
|
||||
assert(enclen >= len * 8 / 5);
|
||||
|
||||
/*
|
||||
* In the following picture, we represent how the 5 bytes of input
|
||||
* are split into groups of 5 bits, each group being encoded as a
|
||||
* single base32 digit.
|
||||
*
|
||||
* input byte 0 1 2 3 4
|
||||
* +--------+--------+--------+--------+--------+
|
||||
* |01234012|34012340|12340123|40123401|23401234|
|
||||
* +--------+--------+--------+--------+--------+
|
||||
* <---><----><---><----><----><---><----><--->
|
||||
* output digit 0 1 2 3 4 5 6 7
|
||||
*
|
||||
*
|
||||
* Because of possible padding, which must be done as if the input
|
||||
* was 0, and because the fractional part is at the end, we'll
|
||||
* start encoding from the end. The encoding loop is unrolled for
|
||||
* greater performance (using the infamous Duff's device to directly
|
||||
* switch at the proper stage within the do {} while loop).
|
||||
*/
|
||||
|
||||
switch (len % 5) {
|
||||
case 0:
|
||||
do {
|
||||
assert(op - encbuf >= 8);
|
||||
i = (unsigned char) *--ip; /* Input #4 */
|
||||
*--op = alphabet[i & 0x1f]; /* Ouput #7 */
|
||||
i >>= 5; /* upper <234>, input #4 */
|
||||
/* FALLTHROUGH */
|
||||
case 4:
|
||||
i |= ((unsigned char) *--ip) << 3; /* had 3 bits in `i' */
|
||||
*--op = alphabet[i & 0x1f]; /* Output #6 */
|
||||
i >>= 5; /* upper <401234>, input #3 */
|
||||
*--op = alphabet[i & 0x1f]; /* Output #5 */
|
||||
i >>= 5; /* upper <4>, input #3 */
|
||||
/* FALLTHROUGH */
|
||||
case 3:
|
||||
i |= ((unsigned char) *--ip) << 1; /* had 1 bits in `i' */
|
||||
*--op = alphabet[i & 0x1f]; /* Output #4 */
|
||||
i >>= 5; /* upper <1234>, input #2 */
|
||||
/* FALLTHROUGH */
|
||||
case 2:
|
||||
i |= ((unsigned char) *--ip) << 4; /* had 4 bits in `i' */
|
||||
*--op = alphabet[i & 0x1f]; /* Output #3 */
|
||||
i >>= 5; /* upper <3401234>, input #1 */
|
||||
*--op = alphabet[i & 0x1f]; /* Output #2 */
|
||||
i >>= 5; /* upper <34>, input #1 */
|
||||
/* FALLTHROUGH */
|
||||
case 1:
|
||||
i |= ((unsigned char) *--ip) << 2; /* had 2 bits in `i' */
|
||||
*--op = alphabet[i & 0x1f]; /* Output #1 */
|
||||
i >>= 5; /* upper <01234>, input #0 */
|
||||
*--op = alphabet[i & 0x1f]; /* Output #0 */
|
||||
i >>= 5; /* Holds nothing, MBZ */
|
||||
assert(i == 0);
|
||||
assert(op >= encbuf);
|
||||
} while (op > encbuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* encode_pad_length
|
||||
*
|
||||
* Compute the number of base32 digits and amount of padding necessary
|
||||
* to encode `len' bytes.
|
||||
*
|
||||
* Returns the number of base32 digits necessary.
|
||||
* Furthermore, if `pad' is a non-NULL pointer, it is filled with the amount
|
||||
* of padding chars that would be necessary.
|
||||
*/
|
||||
int BASE32::encode_pad_length(int len, int *pad)
|
||||
{
|
||||
int ndigits; /* Base32 digits necessary */
|
||||
int npad = 0; /* Final padding chars necessary */
|
||||
int qcount; /* Amount of full quintets */
|
||||
int remainder; /* Amount of input bytes in final quintet */
|
||||
|
||||
assert(len > 0);
|
||||
|
||||
qcount = len / 5;
|
||||
remainder = len - (qcount * 5);
|
||||
|
||||
assert(remainder >= 0);
|
||||
|
||||
switch (remainder) {
|
||||
case 0: npad = 0; break;
|
||||
case 1: npad = 6; break;
|
||||
case 2: npad = 4; break;
|
||||
case 3: npad = 3; break;
|
||||
case 4: npad = 1; break;
|
||||
default: assert(0); /* Not possible */
|
||||
}
|
||||
|
||||
ndigits = qcount * 8; /* Each full quintet encoded on 8 bytes */
|
||||
if (npad != 0)
|
||||
ndigits += (8 - npad);
|
||||
|
||||
if (pad)
|
||||
*pad = npad;
|
||||
|
||||
return ndigits;
|
||||
}
|
||||
|
||||
vector<unsigned char> BASE32::decode( const char * buf, int len, int * outlen )
|
||||
{
|
||||
int declen;
|
||||
vector<unsigned char> decbuf;
|
||||
int decoded;
|
||||
|
||||
if (len == 0 || (len & 0x7)) /* Empty, or padding bytes missing */
|
||||
{
|
||||
decbuf.clear();
|
||||
return decbuf;
|
||||
}
|
||||
|
||||
declen = (len >> 3) * 5;
|
||||
decbuf.resize(declen);
|
||||
|
||||
decoded = decode_into(buf, len, decbuf.data(), declen);
|
||||
|
||||
if (decoded == 0)
|
||||
decbuf.clear();
|
||||
|
||||
if (outlen != NULL)
|
||||
*outlen = decoded;
|
||||
|
||||
return decbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* decode_into
|
||||
*
|
||||
* Decode `len' bytes from `buf' into `declen' bytes starting from `decbuf',
|
||||
* faking the necessary amount of padding if necessary.
|
||||
* Caller must have ensured that there was sufficient room in decbuf.
|
||||
*
|
||||
* Returns the amount of bytes decoded (without trailing padding) if successful,
|
||||
* 0 if the input was not valid base32.
|
||||
*/
|
||||
int BASE32::decode_into(const char *buf, int len, unsigned char *decbuf, int declen)
|
||||
{
|
||||
int padding = 0;
|
||||
|
||||
if (len & 0x7)
|
||||
padding = 8 - (len & 0x7);
|
||||
|
||||
return decode_alphabet(values, buf, len + padding, decbuf, declen, padding);
|
||||
}
|
||||
|
||||
/*
|
||||
* decode_alphabet
|
||||
*
|
||||
* Decode `len' bytes from `buf' into `declen' bytes starting from `decbuf'.
|
||||
* Caller must have ensured that there was sufficient room in decbuf.
|
||||
* Uses the specified decoding alphabet.
|
||||
*
|
||||
* `padding', when non-zero, is the amount of padding that is missing from
|
||||
* the input buffer and which we must assume.
|
||||
*
|
||||
* Return decoded bytes if successful, 0 if the input was not valid base32.
|
||||
*/
|
||||
int BASE32::decode_alphabet(const char valmap[],
|
||||
const char *buf, int len, unsigned char *decbuf, int declen, int padding)
|
||||
{
|
||||
int i = 0; /* Input accumulator, 0 for trailing pad */
|
||||
char const *ip = buf + len; /* Input pointer, one byte off end */
|
||||
int dlen = (len >> 3) * 5; /* Exact decoded length */
|
||||
unsigned char *op; /* Output pointer, one byte off end */
|
||||
int bytes; /* bytes decoded without padding */
|
||||
char v;
|
||||
|
||||
assert(padding >= 0);
|
||||
assert(buf);
|
||||
assert(decbuf);
|
||||
assert(len > 0);
|
||||
assert((len & 0x7) == 0); /* `len' is a multiple of 8 bytes */
|
||||
//assert(declen >= dlen);
|
||||
|
||||
/*
|
||||
* If the last byte of input is '=', there is padding and we need to
|
||||
* zero the tail of the decoding buffer.
|
||||
*
|
||||
* Likewise, when `padding' is non-zero, act as if the '=' were there.
|
||||
*/
|
||||
|
||||
if (buf[len-1] == '=' || padding > 0) {
|
||||
int pad = 0;
|
||||
int n = 0; /* Amount of bytes to zero */
|
||||
int s = 0; /* Amount of bytes to zero */
|
||||
|
||||
/*
|
||||
* Remove and count trailing input padding bytes.
|
||||
*/
|
||||
|
||||
if (padding == 0) {
|
||||
while (*--ip == '=')
|
||||
pad++;
|
||||
ip++; /* Points one byte after real non-padding input */
|
||||
} else {
|
||||
pad = padding;
|
||||
ip -= padding;
|
||||
}
|
||||
|
||||
switch (pad) {
|
||||
case 1: n = 1; s = 0; break;
|
||||
case 3: n = 2; s = 1; break;
|
||||
case 4: n = 3; s = 2; break;
|
||||
case 6: n = 4; s = 3; break;
|
||||
default:
|
||||
return 0; /* Cannot be valid base32 */
|
||||
}
|
||||
|
||||
memset(decbuf + (dlen - n), 0, n);
|
||||
op = decbuf + (dlen - s);
|
||||
bytes = dlen - n;
|
||||
} else {
|
||||
op = decbuf + dlen;
|
||||
bytes = dlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* In the following picture, we represent how the 8 bytes of input,
|
||||
* each consisting of only 5 bits of information forming a base32 digit,
|
||||
* are concatenated back into 5 bytes of binary information.
|
||||
*
|
||||
* input digit 0 1 2 3 4 5 6 7
|
||||
* <---><----><---><----><----><---><----><--->
|
||||
* +--------+--------+--------+--------+--------+
|
||||
* |01234012|34012340|12340123|40123401|23401234|
|
||||
* +--------+--------+--------+--------+--------+
|
||||
* output byte 0 1 2 3 4
|
||||
*
|
||||
*
|
||||
* Because of possible padding, which must be done as if the input
|
||||
* was 0, and because the fractional part is at the end, we'll
|
||||
* start decoding from the end. The decoding loop is unrolled for
|
||||
* greater performance (using the infamous Duff's device to directly
|
||||
* switch at the proper stage within the do {} while loop).
|
||||
*/
|
||||
|
||||
switch ((ip - buf) % 8) {
|
||||
case 0:
|
||||
do {
|
||||
i = valmap[(unsigned char) *--ip]; /* Input #7 */
|
||||
if (i < 0)
|
||||
return 0;
|
||||
/* FALLTHROUGH */
|
||||
case 7:
|
||||
v = valmap[(unsigned char) *--ip]; /* Input #6 */
|
||||
if (v < 0)
|
||||
return 0;
|
||||
i |= v << 5; /* had 5 bits */
|
||||
*--op = i & 0xff; /* Output #4 */
|
||||
i >>= 8; /* lower <01> of output #3 */
|
||||
/* FALLTHROUGH */
|
||||
case 6:
|
||||
v = valmap[(unsigned char) *--ip]; /* Input #5 */
|
||||
if (v < 0)
|
||||
return 0;
|
||||
i |= v << 2; /* had 2 bits */
|
||||
/* FALLTHROUGH */
|
||||
case 5:
|
||||
v = valmap[(unsigned char) *--ip]; /* Input #4 */
|
||||
if (v < 0)
|
||||
return 0;
|
||||
i |= v << 7; /* had 7 bits */
|
||||
*--op = i & 0xff; /* Output #3 */
|
||||
i >>= 8; /* lower <0123> of output #2 */
|
||||
/* FALLTHROUGH */
|
||||
case 4:
|
||||
v = valmap[(unsigned char) *--ip]; /* Input #3 */
|
||||
if (v < 0)
|
||||
return 0;
|
||||
i |= v << 4; /* had 4 bits */
|
||||
*--op = i & 0xff; /* Output #2 */
|
||||
i >>= 8; /* lower <0> of output #1 */
|
||||
/* FALLTHROUGH */
|
||||
case 3:
|
||||
v = valmap[(unsigned char) *--ip]; /* Input #2 */
|
||||
if (v < 0)
|
||||
return 0;
|
||||
i |= v << 1; /* had 1 bit */
|
||||
/* FALLTHROUGH */
|
||||
case 2:
|
||||
v = valmap[(unsigned char) *--ip]; /* Input #1 */
|
||||
if (v < 0)
|
||||
return 0;
|
||||
i |= v << 6; /* had 6 bits */
|
||||
*--op = i & 0xff; /* Output #1 */
|
||||
i >>= 8; /* lower <012> of output #0 */
|
||||
/* FALLTHROUGH */
|
||||
case 1:
|
||||
v = valmap[(unsigned char) *--ip]; /* Input #0 */
|
||||
if (v < 0)
|
||||
return 0;
|
||||
i |= v << 3; /* had 3 bits */
|
||||
*--op = i & 0xff; /* Output #0 */
|
||||
i >>= 8; /* Holds nothing, MBZ */
|
||||
assert(i == 0);
|
||||
assert(op >= decbuf);
|
||||
} while (op > decbuf);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
Reference in New Issue
Block a user