127 lines
3.6 KiB
C++
127 lines
3.6 KiB
C++
#pragma once
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.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;
|
|
|
|
/**
|
|
* @brief The id of the device sending the message
|
|
*/
|
|
uint8_t device;
|
|
|
|
} Message;
|
|
|
|
constexpr size_t messageCounterSize = sizeof(uint32_t);
|
|
|
|
/**
|
|
* @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)
|
|
|
|
constexpr int MESSAGE_CONTENT_SIZE = sizeof(Message);
|
|
|
|
constexpr int AUTHENTICATED_MESSAGE_SIZE = sizeof(AuthenticatedMessage);
|
|
|
|
/**
|
|
* An event signaled from the device
|
|
*/
|
|
enum class SesameEvent {
|
|
TextReceived = 1,
|
|
UnexpectedSocketEvent = 2,
|
|
InvalidMessageSize = 3,
|
|
MessageAuthenticationFailed = 4,
|
|
MessageTimeMismatch = 5,
|
|
MessageCounterInvalid = 6,
|
|
MessageAccepted = 7,
|
|
MessageDeviceInvalid = 8,
|
|
InvalidUrlParameter = 9,
|
|
InvalidResponseAuthentication = 10,
|
|
DeviceSetupIncomplete = 11,
|
|
};
|
|
|
|
/**
|
|
* @brief A callback for messages received over the socket
|
|
*
|
|
* The first parameter is a pointer to the byte buffer.
|
|
* The second parameter indicates the number of received bytes.
|
|
*/
|
|
typedef void (*MessageCallback)(uint8_t* payload, size_t length);
|
|
|
|
/**
|
|
* @brief A callback for socket errors
|
|
*/
|
|
typedef void (*ErrorCallback)(SesameEvent event);
|
|
|