mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-02-21 10:01:46 +00:00
Add base64 code (unpadded standard alphabet)
This commit is contained in:
parent
1a2ff884b3
commit
91a37f8868
@ -1,10 +1,10 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2019 ZeroTier,Inc. https://www.zerotier.com/
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
@ -13,7 +13,7 @@
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* along with this program. If not,see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
@ -69,7 +69,7 @@ static unsigned long _Utils_itoa(unsigned long n,char *s)
|
||||
if (n == 0)
|
||||
return 0;
|
||||
unsigned long pos = _Utils_itoa(n / 10,s);
|
||||
if (pos >= 22) // sanity check, should be impossible
|
||||
if (pos >= 22) // sanity check,should be impossible
|
||||
pos = 22;
|
||||
s[pos] = '0' + (char)(n % 10);
|
||||
return pos + 1;
|
||||
@ -99,7 +99,7 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
|
||||
* CSPRNG we use. There have been several bugs at the OS or OS distribution
|
||||
* level in the past that resulted in systematically weak or predictable
|
||||
* keys due to random seeding problems. This mitigates that by grabbing
|
||||
* a bit of extra entropy and further randomizing the result, and comes
|
||||
* a bit of extra entropy and further randomizing the result,and comes
|
||||
* at almost no cost and with no real downside if the random source is
|
||||
* good. */
|
||||
if (!s20Initialized) {
|
||||
@ -171,7 +171,7 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
|
||||
#endif // __WINDOWS__ or not
|
||||
}
|
||||
|
||||
int Utils::b32d(const char *encoded, uint8_t *result, int bufSize)
|
||||
int Utils::b32d(const char *encoded,uint8_t *result,int bufSize)
|
||||
{
|
||||
int buffer = 0;
|
||||
int bitsLeft = 0;
|
||||
@ -247,4 +247,83 @@ int Utils::b32e(const uint8_t *data,int length,char *result,int bufSize)
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned int Utils::b64e(const uint8_t *in,unsigned int inlen,char *out,unsigned int outlen)
|
||||
{
|
||||
static const char base64en[64] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' };
|
||||
unsigned int i = 0,j = 0;
|
||||
uint8_t l = 0;
|
||||
int s = 0;
|
||||
for (;i<inlen;++i) {
|
||||
uint8_t c = in[i];
|
||||
switch (s) {
|
||||
case 0:
|
||||
s = 1;
|
||||
if (j >= outlen) return 0;
|
||||
out[j++] = base64en[(c >> 2) & 0x3f];
|
||||
break;
|
||||
case 1:
|
||||
s = 2;
|
||||
if (j >= outlen) return 0;
|
||||
out[j++] = base64en[((l & 0x3) << 4) | ((c >> 4) & 0xf)];
|
||||
break;
|
||||
case 2:
|
||||
s = 0;
|
||||
if (j >= outlen) return 0;
|
||||
out[j++] = base64en[((l & 0xf) << 2) | ((c >> 6) & 0x3)];
|
||||
if (j >= outlen) return 0;
|
||||
out[j++] = base64en[c & 0x3f];
|
||||
break;
|
||||
}
|
||||
l = c;
|
||||
}
|
||||
switch (s) {
|
||||
case 1:
|
||||
if (j >= outlen) return 0;
|
||||
out[j++] = base64en[(l & 0x3) << 4];
|
||||
//out[j++] = '=';
|
||||
//out[j++] = '=';
|
||||
break;
|
||||
case 2:
|
||||
if (j >= outlen) return 0;
|
||||
out[j++] = base64en[(l & 0xf) << 2];
|
||||
//out[j++] = '=';
|
||||
break;
|
||||
}
|
||||
if (j >= outlen) return 0;
|
||||
out[j] = 0;
|
||||
return j;
|
||||
}
|
||||
|
||||
unsigned int Utils::b64d(const char *in,unsigned char *out,unsigned int outlen)
|
||||
{
|
||||
static const uint8_t base64de[256] = { 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,62,255,255,255,63,52,53,54,55,56,57,58,59,60,61,255,255,255,255,255,255,255,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,255,255,255,255,255,255,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,255,255,255,255,255 };
|
||||
unsigned int i = 0;
|
||||
unsigned int j = 0;
|
||||
while ((in[i] != '=')&&(in[i] != 0)) {
|
||||
if (j >= outlen)
|
||||
break;
|
||||
uint8_t c = base64de[(unsigned char)in[i]];
|
||||
if (c != 255) {
|
||||
switch (i & 0x3) {
|
||||
case 0:
|
||||
out[j] = (c << 2) & 0xff;
|
||||
break;
|
||||
case 1:
|
||||
out[j++] |= (c >> 4) & 0x3;
|
||||
out[j] = (c & 0xf) << 4;
|
||||
break;
|
||||
case 2:
|
||||
out[j++] |= (c >> 2) & 0xf;
|
||||
out[j] = (c & 0x3) << 6;
|
||||
break;
|
||||
case 3:
|
||||
out[j++] |= c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
@ -245,6 +245,10 @@ public:
|
||||
static int b32d(const char *encoded, uint8_t *result, int bufSize);
|
||||
static int b32e(const uint8_t *data,int length,char *result,int bufSize);
|
||||
|
||||
static inline unsigned int b64MaxEncodedSize(const unsigned int s) { return ((((s + 2) / 3) * 4) + 1); }
|
||||
static unsigned int b64e(const uint8_t *in,unsigned int inlen,char *out,unsigned int outlen);
|
||||
static unsigned int b64d(const char *in,uint8_t *out,unsigned int outlen);
|
||||
|
||||
/**
|
||||
* Tokenize a string (alias for strtok_r or strtok_s depending on platform)
|
||||
*
|
||||
|
40
selftest.cpp
40
selftest.cpp
@ -712,6 +712,46 @@ static int testOther()
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cout << "[other] Testing base32... "; std::cout.flush();
|
||||
for(unsigned int i=1;i<1024;++i) {
|
||||
Utils::getSecureRandom(buf,(unsigned int)sizeof(buf));
|
||||
int l = Utils::b32e((const uint8_t *)buf,i,buf2,sizeof(buf2));
|
||||
if (l <= 0) {
|
||||
std::cout << "FAIL (encode returned 0)" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
int l2 = Utils::b32d(buf2,(uint8_t *)buf3,sizeof(buf3));
|
||||
if (l2 != (int)i) {
|
||||
std::cout << "FAIL (decode returned wrong count)" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
if (memcmp(buf,buf3,i) != 0) {
|
||||
std::cout << "FAIL (decode result incorrect)" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
std::cout << "PASS" << std::endl;
|
||||
|
||||
std::cout << "[other] Testing base64... "; std::cout.flush();
|
||||
for(unsigned int i=1;i<1024;++i) {
|
||||
Utils::getSecureRandom(buf,(unsigned int)sizeof(buf));
|
||||
unsigned int l = Utils::b64e((const uint8_t *)buf,i,buf2,sizeof(buf2));
|
||||
if (l == 0) {
|
||||
std::cout << "FAIL (encode returned 0)" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
unsigned int l2 = Utils::b64d(buf2,(uint8_t *)buf3,sizeof(buf3));
|
||||
if (l2 != i) {
|
||||
std::cout << "FAIL (decode returned wrong count)" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
if (memcmp(buf,buf3,i) != 0) {
|
||||
std::cout << "FAIL (decode result incorrect)" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
std::cout << "PASS" << std::endl;
|
||||
|
||||
std::cout << "[other] Testing InetAddress encode/decode..."; std::cout.flush();
|
||||
std::cout << " " << InetAddress("127.0.0.1/9993").toString(buf);
|
||||
std::cout << " " << InetAddress("feed:dead:babe:dead:beef:f00d:1234:5678/12345").toString(buf);
|
||||
|
Loading…
x
Reference in New Issue
Block a user