// Copyright (c) 2020-2021, The Monero Project // // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, are // permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright notice, this list // of conditions and the following disclaimer in the documentation and/or other // materials provided with the distribution. // // 3. Neither the name of the copyright holder nor the names of its contributors may be // used to endorse or promote products derived from this software without specific // prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include "mpi.h" namespace openpgp { size_t bits_to_bytes(size_t bits) { constexpr const uint16_t bits_in_byte = 8; return (bits + bits_in_byte - 1) / bits_in_byte; } std::string strip_line_breaks(const std::string &string) { std::string result; result.reserve(string.size()); for (const auto &character : string) { if (character != '\r' && character != '\n') { result.push_back(character); } } return result; } struct packet_tag { enum type : uint8_t { signature = 2, public_key = 6, user_id = 13, public_subkey = 14, }; const type packet_type; const size_t length; }; template < typename byte_container, typename = typename std::enable_if<(sizeof(typename byte_container::value_type) == 1)>::type> class deserializer { public: deserializer(byte_container buffer) : buffer(std::move(buffer)) , cursor(0) { } bool empty() const { return buffer.size() - cursor == 0; } packet_tag read_packet_tag() { const auto tag = read_big_endian(); constexpr const uint8_t format_mask = 0b11000000; constexpr const uint8_t format_old_tag = 0b10000000; if ((tag & format_mask) != format_old_tag) { throw std::runtime_error("invalid packet tag"); } const packet_tag::type packet_type = static_cast((tag & 0b00111100) >> 2); const uint8_t length_type = tag & 0b00000011; size_t length; switch (length_type) { case 0: length = read_big_endian(); break; case 1: length = read_big_endian(); break; case 2: length = read_big_endian(); break; default: throw std::runtime_error("unsupported packet length type"); } return {packet_type, length}; } mpi read_mpi() { const size_t bit_length = read_big_endian(); return mpi(read_span(bits_to_bytes(bit_length))); } std::vector read(size_t size) { if (buffer.size() - cursor < size) { throw std::runtime_error("insufficient buffer size"); } const size_t offset = cursor; cursor += size; return {&buffer[offset], &buffer[cursor]}; } template ::value>::type> T read_big_endian() { if (buffer.size() - cursor < sizeof(T)) { throw std::runtime_error("insufficient buffer size"); } T result = 0; for (size_t read = 0; read < sizeof(T); ++read) { result = (result << 8) | static_cast(buffer[cursor++]); } return result; } epee::span read_span(size_t size) { if (buffer.size() - cursor < size) { throw std::runtime_error("insufficient buffer size"); } const size_t offset = cursor; cursor += size; return {reinterpret_cast(&buffer[offset]), size}; } private: byte_container buffer; size_t cursor; }; } // namespace openpgp