1
0
mirror of https://github.com/danog/ton.git synced 2024-12-02 09:28:02 +01:00
ton/crypto/common/util.cpp
2019-09-07 14:33:36 +04:00

213 lines
7.2 KiB
C++

/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include "util.h"
#include <limits>
namespace td {
std::size_t compute_base64_encoded_size(size_t bindata_size) {
return ((bindata_size + 2) / 3) << 2;
}
const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const char base64_url_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
const unsigned char base64_dec_table[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0x7e, 0, 0xbe, 0, 0x7f, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc,
0xfd, 0, 0, 0, 1, 0, 0, 0, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,
0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0, 0, 0, 0,
0xbf, 0, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0, 0, 0, 0, 0};
std::size_t buff_base64_encode(td::MutableSlice buffer, td::Slice raw, bool base64_url) {
std::size_t orig_size = raw.size(), res_size = compute_base64_encoded_size(orig_size);
if (res_size > buffer.size()) {
return 0;
}
const char *table = base64_url ? base64_url_table : base64_table;
char *wptr = buffer.data();
unsigned x;
std::size_t i;
for (i = 0; i < orig_size - 2; i += 3) {
x = (((unsigned)(unsigned char)raw[i]) << 16) | (((unsigned)(unsigned char)raw[i + 1]) << 8) |
((unsigned)(unsigned char)raw[i + 2]);
*wptr++ = table[(x >> 18) & 0x3f];
*wptr++ = table[(x >> 12) & 0x3f];
*wptr++ = table[(x >> 6) & 0x3f];
*wptr++ = table[x & 0x3f];
}
switch (orig_size - i) {
case 1:
x = (((unsigned)(unsigned char)raw[i]) << 16);
*wptr++ = table[(x >> 18) & 0x3f];
*wptr++ = table[(x >> 12) & 0x3f];
*wptr++ = '=';
*wptr++ = '=';
break;
case 2:
x = (((unsigned)(unsigned char)raw[i]) << 16) | (((unsigned)(unsigned char)raw[i + 1]) << 8);
*wptr++ = table[(x >> 18) & 0x3f];
*wptr++ = table[(x >> 12) & 0x3f];
*wptr++ = table[(x >> 6) & 0x3f];
*wptr++ = '=';
}
CHECK(wptr == buffer.data() + res_size);
return res_size;
}
std::string str_base64_encode(std::string raw, bool base64_url) {
return str_base64_encode(td::Slice{raw}, base64_url);
}
std::string str_base64_encode(td::Slice raw, bool base64_url) {
std::size_t res_size = compute_base64_encoded_size(raw.size());
std::string s;
s.resize(res_size);
if (res_size) {
buff_base64_encode(td::MutableSlice{const_cast<char *>(s.data()), s.size()}, raw, base64_url);
}
return s;
}
bool is_valid_base64(std::string encoded, bool allow_base64_url) {
return is_valid_base64(td::Slice{encoded}, allow_base64_url);
}
bool is_valid_base64(td::Slice encoded, bool allow_base64_url) {
const unsigned char *ptr = (const unsigned char *)encoded.data(), *end = ptr + encoded.size();
if (encoded.size() & 3) {
return false;
}
unsigned mode = (allow_base64_url ? 0xc0 : 0x40);
while (ptr < end && (base64_dec_table[*ptr] & mode)) {
ptr++;
}
std::size_t d = end - ptr;
if (d > 2) {
return false;
}
while (ptr < end && *ptr == '=') {
ptr++;
}
return ptr == end;
}
td::int32 decoded_base64_size(std::string encoded, bool allow_base64_url) {
return decoded_base64_size(td::Slice{encoded}, allow_base64_url);
}
td::int32 decoded_base64_size(td::Slice encoded, bool allow_base64_url) {
const unsigned char *ptr = (const unsigned char *)encoded.data(), *end = ptr + encoded.size();
if (encoded.size() & 3) {
return -1;
}
if (encoded.size() > static_cast<size_t>(std::numeric_limits<td::int32>::max())) {
return -1;
}
if (end == ptr) {
return 0;
}
auto s = static_cast<td::int32>((encoded.size() >> 2) * 3);
if (end[-1] == '=') {
s--;
if (end[-2] == '=') {
s--;
}
}
return s;
}
std::size_t buff_base64_decode(td::MutableSlice buffer, td::Slice encoded, bool allow_base64_url) {
if ((encoded.size() & 3) || !encoded.size()) {
return 0;
}
std::size_t n = (encoded.size() >> 2);
const unsigned char *ptr = (const unsigned char *)encoded.data(), *end = ptr + encoded.size();
unsigned q = (end[-1] == '=' ? (end[-2] == '=' ? 2 : 1) : 0);
if (buffer.size() + q < n * 3) {
return 0;
}
unsigned char *wptr = (unsigned char *)buffer.data(), *wend = wptr + buffer.size();
unsigned mode = (allow_base64_url ? 0xc0 : 0x40);
for (std::size_t i = 0; i < n; i++) {
unsigned x = 0;
for (std::size_t j = 0; j < 4; j++) {
unsigned z = base64_dec_table[ptr[4 * i + j]];
if (!(z & mode) && z != 1 && (i < n - 1 || j + q < 4)) {
return 0;
}
x = (x << 6) | (z & 0x3f);
}
if (i < n - 1) {
*wptr++ = (unsigned char)(x >> 16);
*wptr++ = (unsigned char)(x >> 8);
*wptr++ = (unsigned char)x;
} else {
for (; q < 3; q++) {
*wptr++ = (unsigned char)(x >> 16);
x <<= 8;
}
break;
}
}
CHECK(wptr <= wend);
return wptr - (unsigned char *)buffer.data();
}
td::BufferSlice base64_decode(std::string encoded, bool allow_base64_url) {
return base64_decode(td::Slice{encoded}, allow_base64_url);
}
td::BufferSlice base64_decode(td::Slice encoded, bool allow_base64_url) {
auto s = decoded_base64_size(encoded, allow_base64_url);
if (s <= 0) {
return td::BufferSlice{};
}
td::BufferSlice res{static_cast<std::size_t>(s)};
auto r = buff_base64_decode(res.as_slice(), encoded, allow_base64_url);
if (!r) {
return td::BufferSlice{};
}
CHECK(r == static_cast<std::size_t>(s));
return res;
}
std::string str_base64_decode(std::string encoded, bool allow_base64_url) {
return str_base64_decode(td::Slice{encoded}, allow_base64_url);
}
std::string str_base64_decode(td::Slice encoded, bool allow_base64_url) {
auto s = decoded_base64_size(encoded, allow_base64_url);
if (s <= 0) {
return std::string{};
}
std::string res;
res.resize(static_cast<std::size_t>(s));
auto r = buff_base64_decode(td::MutableSlice{const_cast<char *>(res.data()), res.size()}, encoded, allow_base64_url);
if (!r) {
return std::string{};
}
CHECK(r == static_cast<std::size_t>(s));
return res;
}
} // namespace td