#ifndef LLARP_ENCODE_HPP #define LLARP_ENCODE_HPP #include #include #include #include namespace llarp { // from https://en.wikipedia.org/wiki/Base32#z-base-32 static const char zbase32_alpha[] = {'y', 'b', 'n', 'd', 'r', 'f', 'g', '8', 'e', 'j', 'k', 'm', 'c', 'p', 'q', 'x', 'o', 't', '1', 'u', 'w', 'i', 's', 'z', 'a', '3', '4', '5', 'h', '7', '6', '9'}; static const std::unordered_map< char, uint8_t > zbase32_reverse_alpha = { {'y', 0}, {'b', 1}, {'n', 2}, {'d', 3}, {'r', 4}, {'f', 5}, {'g', 6}, {'8', 7}, {'e', 8}, {'j', 9}, {'k', 10}, {'m', 11}, {'c', 12}, {'p', 13}, {'q', 14}, {'x', 15}, {'o', 16}, {'t', 17}, {'1', 18}, {'u', 19}, {'w', 20}, {'i', 21}, {'s', 22}, {'z', 23}, {'a', 24}, {'3', 25}, {'4', 26}, {'5', 27}, {'h', 28}, {'7', 29}, {'6', 30}, {'9', 31}}; template < int a, int b > static size_t DecodeSize(size_t sz) { auto d = div(sz, a); if(d.rem) d.quot++; return b * d.quot; } static size_t Base32DecodeSize(size_t sz) { return DecodeSize< 5, 8 >(sz); } template < typename Stack, typename V > bool Base32Decode(const Stack& stack, V& value) { int tmp = 0, bits = 0; size_t idx = 0; const size_t len = Base32DecodeSize(value.size()); const size_t outLen = value.size(); for(size_t i = 0; i < len; i++) { char ch = stack[i]; if(ch) { auto itr = zbase32_reverse_alpha.find(ch); if(itr == zbase32_reverse_alpha.end()) return false; ch = itr->second; } else { return idx == outLen; } tmp |= ch; bits += 5; if(bits >= 8) { if(idx >= outLen) return false; value[idx] = tmp >> (bits - 8); bits -= 8; idx++; } tmp <<= 5; } return idx == outLen; } /// adapted from i2pd template < typename V, typename Stack > const char* Base32Encode(const V& value, Stack& stack) { size_t ret = 0, pos = 1; int bits = 8; uint32_t tmp = value[0]; size_t len = value.size(); while(ret < sizeof(stack) && (bits > 0 || pos < len)) { if(bits < 5) { if(pos < len) { tmp <<= 8; tmp |= value[pos] & 0xFF; pos++; bits += 8; } else // last byte { tmp <<= (5 - bits); bits = 5; } } bits -= 5; int ind = (tmp >> bits) & 0x1F; if(ret < sizeof(stack)) { stack[ret] = zbase32_alpha[ind]; ret++; } else return nullptr; } return &stack[0]; } /// encode V as hex to stack /// null terminate /// return pointer to base of stack buffer on success otherwise returns /// nullptr template < typename V, typename Stack > const char* HexEncode(const V& value, Stack& stack) { size_t idx = 0; char* ptr = &stack[0]; char* end = ptr + sizeof(stack); while(idx < value.size()) { auto wrote = snprintf(ptr, end - ptr, "%.2x", value[idx]); if(wrote == -1) return nullptr; ptr += wrote; idx++; } *ptr = 0; return &stack[0]; } int char2int(char input); template < typename OutputIt > bool HexDecode(const char* src, OutputIt target, size_t sz) { while(*src && src[1] && sz) { *(target++) = char2int(*src) * 16 + char2int(src[1]); src += 2; --sz; } return sz == 0; } static const char base64_table[] = { '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', '+', '/'}; template < typename OStream_t > void Base64Encode(OStream_t& out, const uint8_t* src, size_t len) { size_t i = 0; size_t j = 0; uint8_t buf[4] = {0}; uint8_t tmp[3] = {0}; while(len--) { tmp[i++] = *(src++); if(3 == i) { buf[0] = (tmp[0] & 0xfc) >> 2; buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4); buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6); buf[3] = tmp[2] & 0x3f; // encode for(i = 0; i < 4; ++i) { out << base64_table[buf[i]]; } // reset i = 0; } } // remainder if(i > 0) { // fill `tmp' with `\0' at most 3 times for(j = i; j < 3; ++j) { tmp[j] = 0; } // encode remainder buf[0] = (tmp[0] & 0xfc) >> 2; buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4); buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6); buf[3] = tmp[2] & 0x3f; for(j = 0; (j < i + 1); ++j) { out << base64_table[buf[j]]; } // pad while((i++ < 3)) { out << '='; } } } } // namespace llarp #endif