diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2017-11-07 14:24:30 -0800 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2018-03-07 07:04:07 -0800 |
commit | b3ea8ccb7af475703b97246a2baf2e105d24d6f9 (patch) | |
tree | 7d0f9685476bd35d332ebd7a43c0193bcb8c040d /src/utilstrencodings.cpp | |
parent | 3296a3bb7fc0a6c47b60c79e968dbf8175d6b716 (diff) |
Simplify Base32 and Base64 conversions
Diffstat (limited to 'src/utilstrencodings.cpp')
-rw-r--r-- | src/utilstrencodings.cpp | 297 |
1 files changed, 54 insertions, 243 deletions
diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index ebafe078f4..d1025fc7bf 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -127,46 +127,11 @@ std::string EncodeBase64(const unsigned char* pch, size_t len) { static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - std::string strRet; - strRet.reserve((len+2)/3*4); - - int mode=0, left=0; - const unsigned char *pchEnd = pch+len; - - while (pch<pchEnd) - { - int enc = *(pch++); - switch (mode) - { - case 0: // we have no bits - strRet += pbase64[enc >> 2]; - left = (enc & 3) << 4; - mode = 1; - break; - - case 1: // we have two bits - strRet += pbase64[left | (enc >> 4)]; - left = (enc & 15) << 2; - mode = 2; - break; - - case 2: // we have four bits - strRet += pbase64[left | (enc >> 6)]; - strRet += pbase64[enc & 63]; - mode = 0; - break; - } - } - - if (mode) - { - strRet += pbase64[left]; - strRet += '='; - if (mode == 1) - strRet += '='; - } - - return strRet; + std::string str; + str.reserve(((len + 2) / 3) * 4); + ConvertBits<8, 6, true>([&](int v) { str += pbase64[v]; }, pch, pch + len); + while (str.size() % 4) str += '='; + return str; } std::string EncodeBase64(const std::string& str) @@ -193,68 +158,32 @@ std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid) -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; - if (pfInvalid) - *pfInvalid = false; - - std::vector<unsigned char> vchRet; - vchRet.reserve(strlen(p)*3/4); - - int mode = 0; - int left = 0; - - while (1) - { - int dec = decode64_table[(unsigned char)*p]; - if (dec == -1) break; - p++; - switch (mode) - { - case 0: // we have no bits and get 6 - left = dec; - mode = 1; - break; - - case 1: // we have 6 bits and keep 4 - vchRet.push_back((left<<2) | (dec>>4)); - left = dec & 15; - mode = 2; - break; - - case 2: // we have 4 bits and get 6, we keep 2 - vchRet.push_back((left<<4) | (dec>>2)); - left = dec & 3; - mode = 3; - break; - - case 3: // we have 2 bits and get 6 - vchRet.push_back((left<<6) | dec); - mode = 0; - break; - } + const char* e = p; + std::vector<uint8_t> val; + val.reserve(strlen(p)); + while (*p != 0) { + int x = decode64_table[(unsigned char)*p]; + if (x == -1) break; + val.push_back(x); + ++p; } - if (pfInvalid) - switch (mode) - { - case 0: // 4n base64 characters processed: ok - break; - - case 1: // 4n+1 base64 character processed: impossible - *pfInvalid = true; - break; - - case 2: // 4n+2 base64 characters processed: require '==' - if (left || p[0] != '=' || p[1] != '=' || decode64_table[(unsigned char)p[2]] != -1) - *pfInvalid = true; - break; - - case 3: // 4n+3 base64 characters processed: require '=' - if (left || p[0] != '=' || decode64_table[(unsigned char)p[1]] != -1) - *pfInvalid = true; - break; + std::vector<unsigned char> ret; + ret.reserve((val.size() * 3) / 4); + bool valid = ConvertBits<6, 8, false>([&](unsigned char c) { ret.push_back(c); }, val.begin(), val.end()); + + const char* q = p; + while (valid && *p != 0) { + if (*p != '=') { + valid = false; + break; } + ++p; + } + valid = valid && (p - e) % 4 == 0 && p - q < 4; + if (pfInvalid) *pfInvalid = !valid; - return vchRet; + return ret; } std::string DecodeBase64(const std::string& str) @@ -267,59 +196,11 @@ std::string EncodeBase32(const unsigned char* pch, size_t len) { static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567"; - std::string strRet; - strRet.reserve((len+4)/5*8); - - int mode=0, left=0; - const unsigned char *pchEnd = pch+len; - - while (pch<pchEnd) - { - int enc = *(pch++); - switch (mode) - { - case 0: // we have no bits - strRet += pbase32[enc >> 3]; - left = (enc & 7) << 2; - mode = 1; - break; - - case 1: // we have three bits - strRet += pbase32[left | (enc >> 6)]; - strRet += pbase32[(enc >> 1) & 31]; - left = (enc & 1) << 4; - mode = 2; - break; - - case 2: // we have one bit - strRet += pbase32[left | (enc >> 4)]; - left = (enc & 15) << 1; - mode = 3; - break; - - case 3: // we have four bits - strRet += pbase32[left | (enc >> 7)]; - strRet += pbase32[(enc >> 2) & 31]; - left = (enc & 3) << 3; - mode = 4; - break; - - case 4: // we have two bits - strRet += pbase32[left | (enc >> 5)]; - strRet += pbase32[enc & 31]; - mode = 0; - } - } - - static const int nPadding[5] = {0, 6, 4, 3, 1}; - if (mode) - { - strRet += pbase32[left]; - for (int n=0; n<nPadding[mode]; n++) - strRet += '='; - } - - return strRet; + std::string str; + str.reserve(((len + 4) / 5) * 8); + ConvertBits<8, 5, true>([&](int v) { str += pbase32[v]; }, pch, pch + len); + while (str.size() % 8) str += '='; + return str; } std::string EncodeBase32(const std::string& str) @@ -346,102 +227,32 @@ std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid) -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; - if (pfInvalid) - *pfInvalid = false; - - std::vector<unsigned char> vchRet; - vchRet.reserve((strlen(p))*5/8); - - int mode = 0; - int left = 0; - - while (1) - { - int dec = decode32_table[(unsigned char)*p]; - if (dec == -1) break; - p++; - switch (mode) - { - case 0: // we have no bits and get 5 - left = dec; - mode = 1; - break; - - case 1: // we have 5 bits and keep 2 - vchRet.push_back((left<<3) | (dec>>2)); - left = dec & 3; - mode = 2; - break; - - case 2: // we have 2 bits and keep 7 - left = left << 5 | dec; - mode = 3; - break; - - case 3: // we have 7 bits and keep 4 - vchRet.push_back((left<<1) | (dec>>4)); - left = dec & 15; - mode = 4; - break; - - case 4: // we have 4 bits, and keep 1 - vchRet.push_back((left<<4) | (dec>>1)); - left = dec & 1; - mode = 5; - break; - - case 5: // we have 1 bit, and keep 6 - left = left << 5 | dec; - mode = 6; - break; - - case 6: // we have 6 bits, and keep 3 - vchRet.push_back((left<<2) | (dec>>3)); - left = dec & 7; - mode = 7; - break; - - case 7: // we have 3 bits, and keep 0 - vchRet.push_back((left<<5) | dec); - mode = 0; - break; - } + const char* e = p; + std::vector<uint8_t> val; + val.reserve(strlen(p)); + while (*p != 0) { + int x = decode32_table[(unsigned char)*p]; + if (x == -1) break; + val.push_back(x); + ++p; } - if (pfInvalid) - switch (mode) - { - case 0: // 8n base32 characters processed: ok - break; - - case 1: // 8n+1 base32 characters processed: impossible - case 3: // +3 - case 6: // +6 - *pfInvalid = true; - break; - - case 2: // 8n+2 base32 characters processed: require '======' - if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || p[4] != '=' || p[5] != '=' || decode32_table[(unsigned char)p[6]] != -1) - *pfInvalid = true; - break; - - case 4: // 8n+4 base32 characters processed: require '====' - if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || decode32_table[(unsigned char)p[4]] != -1) - *pfInvalid = true; - break; - - case 5: // 8n+5 base32 characters processed: require '===' - if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || decode32_table[(unsigned char)p[3]] != -1) - *pfInvalid = true; - break; - - case 7: // 8n+7 base32 characters processed: require '=' - if (left || p[0] != '=' || decode32_table[(unsigned char)p[1]] != -1) - *pfInvalid = true; - break; + std::vector<unsigned char> ret; + ret.reserve((val.size() * 5) / 8); + bool valid = ConvertBits<5, 8, false>([&](unsigned char c) { ret.push_back(c); }, val.begin(), val.end()); + + const char* q = p; + while (valid && *p != 0) { + if (*p != '=') { + valid = false; + break; } + ++p; + } + valid = valid && (p - e) % 8 == 0 && p - q < 8; + if (pfInvalid) *pfInvalid = !valid; - return vchRet; + return ret; } std::string DecodeBase32(const std::string& str) |