spank-olm

WIP Do not look
git clone git://archive.git.mtrnord.blog/MTRNord/spank-olm.git
Log | Files | Refs | README | LICENSE

pickle.cpp (12348B)


      1 #include "pickle.hpp"
      2 
      3 #include <botan/x25519.h>
      4 
      5 /* Convenience macro for checking the return value of internal unpickling
      6  * functions and returning early on failure. */
      7 #ifndef UNPICKLE_OK
      8 #define UNPICKLE_OK(x)                                                                                                 \
      9     do                                                                                                                 \
     10     {                                                                                                                  \
     11         if (!(x))                                                                                                      \
     12             return nullptr;                                                                                            \
     13     }                                                                                                                  \
     14     while (0)
     15 #endif
     16 
     17 
     18 namespace spank_olm
     19 {
     20 
     21     /**
     22      * Serializes a 32-bit unsigned integer into a byte array.
     23      *
     24      * @param pos Pointer to the current position in the byte array.
     25      * @param value The 32-bit unsigned integer to serialize.
     26      * @return Pointer to the position in the byte array after the serialized data.
     27      */
     28     std::uint8_t *pickle(std::uint8_t *pos, std::uint32_t value)
     29     {
     30         for (int i = 3; i >= 0; --i)
     31         {
     32             pos[i] = value & 0xFF;
     33             value >>= 8;
     34         }
     35         return pos + 4;
     36     }
     37 
     38     /**
     39      * Deserializes a 32-bit unsigned integer from a byte array.
     40      *
     41      * @param pos Pointer to the current position in the byte array.
     42      * @param end Pointer to the end of the byte array.
     43      * @param value Reference to the 32-bit unsigned integer to store the deserialized value.
     44      * @return Pointer to the position in the byte array after the deserialized data, or nullptr on failure.
     45      */
     46     std::uint8_t const *unpickle(std::uint8_t const *pos, std::uint8_t const *end, std::uint32_t &value)
     47     {
     48         if (!pos || end < pos + 4)
     49             return nullptr;
     50         value = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) | pos[3];
     51         return pos + 4;
     52     }
     53 
     54     /**
     55      * Serializes a boolean value into a byte array.
     56      *
     57      * @param pos Pointer to the current position in the byte array.
     58      * @param value The boolean value to serialize.
     59      * @return Pointer to the position in the byte array after the serialized data.
     60      */
     61     std::uint8_t *pickle(std::uint8_t *pos, const bool value)
     62     {
     63         *(pos++) = value ? 1 : 0;
     64         return pos;
     65     }
     66 
     67     /**
     68      * Deserializes a boolean value from a byte array.
     69      *
     70      * @param pos Pointer to the current position in the byte array.
     71      * @param end Pointer to the end of the byte array.
     72      * @param value Reference to the boolean value to store the deserialized value.
     73      * @return Pointer to the position in the byte array after the deserialized data, or nullptr on failure.
     74      */
     75     std::uint8_t const *unpickle(std::uint8_t const *pos, std::uint8_t const *end, bool &value)
     76     {
     77         if (!pos || end <= pos)
     78             return nullptr;
     79         value = *(pos++) != 0;
     80         return pos;
     81     }
     82 
     83     /**
     84      * Serializes a Botan::secure_vector<uint8_t> into a byte array.
     85      *
     86      * @param pos Pointer to the current position in the byte array.
     87      * @param value The Botan::secure_vector<uint8_t> to serialize.
     88      * @return Pointer to the position in the byte array after the serialized data.
     89      */
     90     std::uint8_t *pickle(std::uint8_t *pos, const Botan::secure_vector<uint8_t> &value)
     91     {
     92         pos = pickle(pos, static_cast<std::uint32_t>(value.size()));
     93         for (const auto byte : value)
     94         {
     95             *(pos++) = byte;
     96         }
     97         return pos;
     98     }
     99 
    100     /**
    101      * Deserializes a Botan::secure_vector<uint8_t> from a byte array.
    102      *
    103      * @param pos Pointer to the current position in the byte array.
    104      * @param end Pointer to the end of the byte array.
    105      * @param value Reference to the Botan::secure_vector<uint8_t> to store the deserialized value.
    106      * @return Pointer to the position in the byte array after the deserialized data, or nullptr on failure.
    107      */
    108     std::uint8_t const *unpickle(std::uint8_t const *pos, std::uint8_t const *end, Botan::secure_vector<uint8_t> &value)
    109     {
    110         std::uint32_t size;
    111         pos = unpickle(pos, end, size);
    112         if (!pos || end < pos + size)
    113             return nullptr;
    114         value.assign(pos, pos + size);
    115         return pos + size;
    116     }
    117 
    118 
    119     /**
    120      * Serializes a std::vector<uint8_t> into a byte array.
    121      *
    122      * @param pos Pointer to the current position in the byte array.
    123      * @param value The Botan::secure_vector<uint8_t> to serialize.
    124      * @return Pointer to the position in the byte array after the serialized data.
    125      */
    126     std::uint8_t *pickle(std::uint8_t *pos, const std::vector<uint8_t> &value)
    127     {
    128         pos = pickle(pos, static_cast<std::uint32_t>(value.size()));
    129         for (const auto byte : value)
    130         {
    131             *(pos++) = byte;
    132         }
    133         return pos;
    134     }
    135 
    136     /**
    137      * Deserializes a std::vector<uint8_t> from a byte array.
    138      *
    139      * @param pos Pointer to the current position in the byte array.
    140      * @param end Pointer to the end of the byte array.
    141      * @param value Reference to the Botan::secure_vector<uint8_t> to store the deserialized value.
    142      * @return Pointer to the position in the byte array after the deserialized data, or nullptr on failure.
    143      */
    144     std::uint8_t const *unpickle(std::uint8_t const *pos, std::uint8_t const *end, std::vector<uint8_t> &value)
    145     {
    146         std::uint32_t size;
    147         pos = unpickle(pos, end, size);
    148         if (!pos || end < pos + size)
    149             return nullptr;
    150         value.assign(pos, pos + size);
    151         return pos + size;
    152     }
    153 
    154     /**
    155      *
    156      * @param pos Pointer to the current position in the byte array.
    157      * @param value A OneTimeKey object to serialize.
    158      * @return Pointer to the position in the byte array after the serialized data.
    159      */
    160     std::uint8_t *pickle(std::uint8_t *pos, const std::optional<OneTimeKey> &value)
    161     {
    162         pos = pickle(pos, value->id);
    163         pos = pickle(pos, value->published);
    164         return pickle(pos, value->key.raw_private_key_bits());
    165     }
    166 
    167     /**
    168      * Deserializes a OneTimeKey object from a byte array.
    169      *
    170      * @param pos Pointer to the current position in the byte array.
    171      * @param end Pointer to the end of the byte array.
    172      * @return A pair containing the pointer to the position in the byte array after the deserialized data and the
    173      * deserialized OneTimeKey object.
    174      */
    175     std::pair<std::uint8_t const *, std::optional<OneTimeKey>> unpickle_otk(std::uint8_t const *pos,
    176                                                                             std::uint8_t const *end)
    177     {
    178         std::uint32_t id; ///< The unique identifier for the one-time key.
    179         bool published; ///< Indicates whether the key has been published.
    180 
    181         pos = unpickle(pos, end, id);
    182         if (!pos || !id)
    183         {
    184             return {nullptr, std::nullopt};
    185         }
    186         pos = unpickle(pos, end, published);
    187         if (!pos)
    188             return {nullptr, std::nullopt};
    189 
    190         Botan::secure_vector<uint8_t> key_bits;
    191         pos = unpickle(pos, end, key_bits);
    192         if (!pos)
    193             return {nullptr, std::nullopt};
    194 
    195         auto otk = OneTimeKey{id, published, Botan::X25519_PrivateKey(key_bits)};
    196 
    197         return {pos, otk};
    198     }
    199 
    200     /**
    201      * Serializes a uint8_t value into a byte array.
    202      *
    203      * @param pos Pointer to the current position in the byte array.
    204      * @param value The uint8_t value to serialize.
    205      * @return Pointer to the position in the byte array after the serialized data.
    206      */
    207     std::uint8_t *pickle(std::uint8_t *pos, const std::uint8_t value)
    208     {
    209         *(pos++) = value;
    210         return pos;
    211     }
    212 
    213     /**
    214      * Deserializes a uint8_t value from a byte array.
    215      *
    216      * @param pos Pointer to the current position in the byte array.
    217      * @param end Pointer to the end of the byte array.
    218      * @param value Reference to the uint8_t value to store the deserialized value.
    219      * @return Pointer to the position in the byte array after the deserialized data, or nullptr on failure.
    220      */
    221     std::uint8_t const *unpickle(std::uint8_t const *pos, std::uint8_t const *end, std::uint8_t &value)
    222     {
    223         if (!pos || pos == end)
    224             return nullptr;
    225         value = *(pos++);
    226         return pos;
    227     }
    228 
    229     /**
    230      * Serializes an optional IdentityKeys object into a byte array.
    231      *
    232      * @param pos Pointer to the current position in the byte array.
    233      * @param value The optional IdentityKeys object to serialize.
    234      * @return Pointer to the position in the byte array after the serialized data.
    235      */
    236     std::uint8_t *pickle(std::uint8_t *pos, const std::optional<IdentityKeys> &value)
    237     {
    238         pos = pickle(pos, value->ed25519_key.public_key()->raw_public_key_bits());
    239         pos = pickle(pos, value->ed25519_key.raw_private_key_bits());
    240         pos = pickle(pos, value->curve25519_key.public_key()->raw_public_key_bits());
    241         return pickle(pos, value->curve25519_key.raw_private_key_bits());
    242     }
    243 
    244     /**
    245      * Deserializes an optional IdentityKeys object from a byte array.
    246      *
    247      * @param pos Pointer to the current position in the byte array.
    248      * @param end Pointer to the end of the byte array.
    249      * @param value Reference to the optional IdentityKeys object to store the deserialized value.
    250      * @return Pointer to the position in the byte array after the deserialized data, or nullptr on failure.
    251      */
    252     std::uint8_t const *unpickle(std::uint8_t const *pos, std::uint8_t const *end, std::optional<IdentityKeys> &value)
    253     {
    254         if (!pos || pos == end)
    255             return nullptr;
    256         Botan::secure_vector<uint8_t> ed25519_public_key_bits;
    257         Botan::secure_vector<uint8_t> curve25519_public_key_bits;
    258         Botan::secure_vector<uint8_t> ed25519_private_key_bits;
    259         Botan::secure_vector<uint8_t> curve25519_private_key_bits;
    260 
    261         pos = unpickle(pos, end, ed25519_public_key_bits);
    262         UNPICKLE_OK(pos);
    263         pos = unpickle(pos, end, ed25519_private_key_bits);
    264         UNPICKLE_OK(pos);
    265         pos = unpickle(pos, end, curve25519_public_key_bits);
    266         UNPICKLE_OK(pos);
    267         pos = unpickle(pos, end, curve25519_private_key_bits);
    268         UNPICKLE_OK(pos);
    269         value = IdentityKeys{Botan::Ed25519_PrivateKey::from_bytes(ed25519_private_key_bits),
    270                              Botan::X25519_PrivateKey(curve25519_private_key_bits)};
    271         return pos;
    272     }
    273 
    274     /**
    275      * Deserializes an optional OneTimeKey object from a byte array.
    276      *
    277      * @param pos Pointer to the current position in the byte array.
    278      * @param end Pointer to the end of the byte array.
    279      * @param value Reference to the optional OneTimeKey object to store the deserialized value.
    280      * @return Pointer to the position in the byte array after the deserialized data, or nullptr on failure.
    281      */
    282     std::uint8_t const *unpickle(std::uint8_t const *pos, std::uint8_t const *end, std::optional<OneTimeKey> &value)
    283     {
    284         if (!pos || pos == end)
    285             return nullptr;
    286         std::uint32_t id;
    287         bool published;
    288         Botan::secure_vector<uint8_t> key_bits;
    289         pos = unpickle(pos, end, id);
    290         UNPICKLE_OK(pos);
    291         pos = unpickle(pos, end, published);
    292         UNPICKLE_OK(pos);
    293         pos = unpickle(pos, end, key_bits);
    294         UNPICKLE_OK(pos);
    295         value = OneTimeKey{id, published, Botan::X25519_PrivateKey(key_bits)};
    296         return pos;
    297     }
    298 
    299     std::uint8_t *pickle_bytes(std::uint8_t *pos, const std::uint8_t *bytes, const std::size_t bytes_length)
    300     {
    301         std::memcpy(pos, bytes, bytes_length);
    302         return pos + bytes_length;
    303     }
    304 
    305     std::uint8_t const *unpickle_bytes(const std::uint8_t *pos, const std::uint8_t *end, std::uint8_t *bytes,
    306                                        const std::size_t bytes_length)
    307     {
    308         if (!pos || end < pos + bytes_length)
    309             return nullptr;
    310         std::memcpy(bytes, pos, bytes_length);
    311         return pos + bytes_length;
    312     }
    313 
    314 } // namespace spank_olm