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