#pragma once #include "stdint.h" /** * @brief The size of a message authentication code * * The MAC size is determined by the size of the output * of the hash function used. In this case, for SHA256, * the size is 32 bytes (= 256 bit) */ #define SHA256_MAC_SIZE 32 #pragma pack(push, 1) /** * @brief The content of an unlock message. * * The content is necessary to ensure freshness of the message * by requiring a recent time and a monotonously increasing counter. * This prevents messages from being delayed or being blocked and * replayed later. */ typedef struct { /** * The timestamp of message creation * * The timestamp is encoded as the epoch time, i.e. seconds since 1970 (GMT). * * The timestamp is used to ensure 'freshness' of the messages, * i.e. that they are not unreasonably delayed or captured and * later replayed by an attacker. */ uint32_t time; /** * The counter of unlock messages * * This counter must always increase with each message from the remote * in order for the messages to be deemed valid. Transfering the counters * back and forth also gives information about lost messages and potential * attacks. Both the remote and the device keep a record of at least the * last used counter. */ uint32_t id; } Message; /** * @brief An authenticated message by the mobile device to command unlocking. * * The message is protected by a message authentication code (MAC) based on * a symmetric key shared by the device and the remote. This code ensures * that the contents of the request were not altered. The message further * contains a timestamp to ensure that the message is recent, and not replayed * by an attacker. An additional counter is also included for this purpose, * which must continously increase for a message to be valid. This increases * security a bit, since the timestamp validation must be tolerant to some * inaccuracy due to mismatching clocks. */ typedef struct { /** * @brief The authentication code of the message * * The code is created by performing HMAC-SHA256 * over the bytes of the `Message`. */ uint8_t mac[SHA256_MAC_SIZE]; /** * @brief The message content. * * The content is necessary to ensure freshness of the message * by requiring a recent time and a monotonously increasing counter. * This prevents messages from being delayed or being blocked and * replayed later. */ Message message; } AuthenticatedMessage; #pragma pack(pop) #define MESSAGE_CONTENT_SIZE sizeof(Message) #define AUTHENTICATED_MESSAGE_SIZE sizeof(AuthenticatedMessage) /** * An event signaled from the device */ enum class SesameEvent { TextReceived = 1, UnexpectedSocketEvent = 2, InvalidMessageData = 3, MessageAuthenticationFailed = 4, MessageTimeMismatch = 5, MessageCounterInvalid = 6, MessageAccepted = 7, }; /** * @brief A callback for messages received over the socket * * The first parameter is the received message. * The second parameter is the response to the remote. * The return value is the type of event to respond with. */ typedef SesameEvent (*MessageCallback)(AuthenticatedMessage*, AuthenticatedMessage*);