mirror of
https://git.wownero.com/wowlet/wowlet.git
synced 2024-08-15 01:03:14 +00:00
173 lines
4.5 KiB
C
173 lines
4.5 KiB
C
|
// Copyright (c) 2020, 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<uint8_t>();
|
||
|
|
||
|
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<packet_tag::type>((tag & 0b00111100) >> 2);
|
||
|
const uint8_t length_type = tag & 0b00000011;
|
||
|
|
||
|
size_t length;
|
||
|
switch (length_type)
|
||
|
{
|
||
|
case 0:
|
||
|
length = read_big_endian<uint8_t>();
|
||
|
break;
|
||
|
case 1:
|
||
|
length = read_big_endian<uint16_t>();
|
||
|
break;
|
||
|
case 2:
|
||
|
length = read_big_endian<uint32_t>();
|
||
|
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<uint16_t>();
|
||
|
return mpi(read_span(bits_to_bytes(bit_length)));
|
||
|
}
|
||
|
|
||
|
std::vector<uint8_t> 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 <typename T, typename = typename std::enable_if<std::is_integral<T>::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<uint8_t>(buffer[cursor++]);
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
epee::span<const uint8_t> 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<const uint8_t *>(&buffer[offset]), size};
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
byte_container buffer;
|
||
|
size_t cursor;
|
||
|
};
|
||
|
|
||
|
} // namespace openpgp
|