Use ChiakiKeyState to 32bit fix key state overflow (Fix #172) (#359)

This commit is contained in:
Sven Scharmentke 2020-11-04 11:45:05 +01:00 committed by GitHub
commit 59e6603256
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 272 additions and 108 deletions

View file

@ -20,15 +20,20 @@ extern "C" {
#define CHIAKI_GKCRYPT_GMAC_KEY_REFRESH_KEY_POS 45000
#define CHIAKI_GKCRYPT_GMAC_KEY_REFRESH_IV_OFFSET 44910
typedef struct chiaki_key_state_t
{
uint64_t prev;
} ChiakiKeyState;
typedef struct chiaki_gkcrypt_t {
uint8_t index;
uint8_t *key_buf; // circular buffer of the ctr mode key stream
size_t key_buf_size;
size_t key_buf_populated; // size of key_buf that is already populated (on startup)
size_t key_buf_key_pos_min; // minimal key pos currently in key_buf
uint64_t key_buf_key_pos_min; // minimal key pos currently in key_buf
size_t key_buf_start_offset; // offset in key_buf of the minimal key pos
size_t last_key_pos; // last key pos that has been requested
uint64_t last_key_pos; // last key pos that has been requested
bool key_buf_thread_stop;
ChiakiMutex key_buf_mutex;
ChiakiCond key_buf_cond;
@ -50,14 +55,14 @@ struct chiaki_session_t;
CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_init(ChiakiGKCrypt *gkcrypt, ChiakiLog *log, size_t key_buf_chunks, uint8_t index, const uint8_t *handshake_key, const uint8_t *ecdh_secret);
CHIAKI_EXPORT void chiaki_gkcrypt_fini(ChiakiGKCrypt *gkcrypt);
CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_gen_key_stream(ChiakiGKCrypt *gkcrypt, size_t key_pos, uint8_t *buf, size_t buf_size);
CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_get_key_stream(ChiakiGKCrypt *gkcrypt, size_t key_pos, uint8_t *buf, size_t buf_size);
CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_decrypt(ChiakiGKCrypt *gkcrypt, size_t key_pos, uint8_t *buf, size_t buf_size);
static inline ChiakiErrorCode chiaki_gkcrypt_encrypt(ChiakiGKCrypt *gkcrypt, size_t key_pos, uint8_t *buf, size_t buf_size) { return chiaki_gkcrypt_decrypt(gkcrypt, key_pos, buf, buf_size); }
CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_gen_key_stream(ChiakiGKCrypt *gkcrypt, uint64_t key_pos, uint8_t *buf, size_t buf_size);
CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_get_key_stream(ChiakiGKCrypt *gkcrypt, uint64_t key_pos, uint8_t *buf, size_t buf_size);
CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_decrypt(ChiakiGKCrypt *gkcrypt, uint64_t key_pos, uint8_t *buf, size_t buf_size);
static inline ChiakiErrorCode chiaki_gkcrypt_encrypt(ChiakiGKCrypt *gkcrypt, uint64_t key_pos, uint8_t *buf, size_t buf_size) { return chiaki_gkcrypt_decrypt(gkcrypt, key_pos, buf, buf_size); }
CHIAKI_EXPORT void chiaki_gkcrypt_gen_gmac_key(uint64_t index, const uint8_t *key_base, const uint8_t *iv, uint8_t *key_out);
CHIAKI_EXPORT void chiaki_gkcrypt_gen_new_gmac_key(ChiakiGKCrypt *gkcrypt, uint64_t index);
CHIAKI_EXPORT void chiaki_gkcrypt_gen_tmp_gmac_key(ChiakiGKCrypt *gkcrypt, uint64_t index, uint8_t *key_out);
CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_gmac(ChiakiGKCrypt *gkcrypt, size_t key_pos, const uint8_t *buf, size_t buf_size, uint8_t *gmac_out);
CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_gmac(ChiakiGKCrypt *gkcrypt, uint64_t key_pos, const uint8_t *buf, size_t buf_size, uint8_t *gmac_out);
static inline ChiakiGKCrypt *chiaki_gkcrypt_new(ChiakiLog *log, size_t key_buf_chunks, uint8_t index, const uint8_t *handshake_key, const uint8_t *ecdh_secret)
{
@ -81,12 +86,17 @@ static inline void chiaki_gkcrypt_free(ChiakiGKCrypt *gkcrypt)
free(gkcrypt);
}
typedef struct chiaki_key_state_t {
uint64_t prev;
} ChiakiKeyState;
CHIAKI_EXPORT void chiaki_key_state_init(ChiakiKeyState *state);
CHIAKI_EXPORT uint64_t chiaki_key_state_request_pos(ChiakiKeyState *state, uint32_t low);
/**
* @param commit whether to remember this key_pos to update the state. Should only be true after authentication to avoid DoS.
*/
CHIAKI_EXPORT uint64_t chiaki_key_state_request_pos(ChiakiKeyState *state, uint32_t low, bool commit);
/**
* Update the internal state after knowing that this key_pos is authentic.
*/
CHIAKI_EXPORT void chiaki_key_state_commit(ChiakiKeyState *state, uint64_t prev);
#ifdef __cplusplus
}

View file

@ -24,8 +24,6 @@
extern "C" {
#endif
typedef uint32_t ChiakiTakionPacketKeyPos;
typedef enum chiaki_takion_message_data_type_t {
CHIAKI_TAKION_MESSAGE_DATA_TYPE_PROTOBUF = 0,
CHIAKI_TAKION_MESSAGE_DATA_TYPE_9 = 9
@ -45,7 +43,7 @@ typedef struct chiaki_takion_av_packet_t
uint8_t adaptive_stream_index;
uint8_t byte_at_0x2c;
uint32_t key_pos;
uint64_t key_pos;
uint8_t *data; // not owned
size_t data_size;
@ -55,7 +53,7 @@ static inline uint8_t chiaki_takion_av_packet_audio_unit_size(ChiakiTakionAVPack
static inline uint8_t chiaki_takion_av_packet_audio_source_units_count(ChiakiTakionAVPacket *packet) { return packet->units_in_frame_fec & 0xf; }
static inline uint8_t chiaki_takion_av_packet_audio_fec_units_count(ChiakiTakionAVPacket *packet) { return (packet->units_in_frame_fec >> 4) & 0xf; }
typedef ChiakiErrorCode (*ChiakiTakionAVPacketParse)(ChiakiTakionAVPacket *packet, uint8_t *buf, size_t buf_size);
typedef ChiakiErrorCode (*ChiakiTakionAVPacketParse)(ChiakiTakionAVPacket *packet, ChiakiKeyState *key_state, uint8_t *buf, size_t buf_size);
typedef struct chiaki_takion_congestion_packet_t
{
@ -133,7 +131,7 @@ typedef struct chiaki_takion_t
size_t postponed_packets_count;
ChiakiGKCrypt *gkcrypt_local; // if NULL (default), no gmac is calculated and nothing is encrypted
size_t key_pos_local;
uint64_t key_pos_local;
ChiakiMutex gkcrypt_local_mutex;
ChiakiGKCrypt *gkcrypt_remote; // if NULL (default), remote gmacs are IGNORED (!) and everything is expected to be unencrypted
@ -158,6 +156,8 @@ typedef struct chiaki_takion_t
uint32_t a_rwnd;
ChiakiTakionAVPacketParse av_packet_parse;
ChiakiKeyState key_state;
} ChiakiTakion;
@ -178,7 +178,7 @@ static inline void chiaki_takion_set_crypt(ChiakiTakion *takion, ChiakiGKCrypt *
* Thread-safe while Takion is running.
* @param key_pos pointer to write the new key pos to. will be 0 if encryption is disabled. Contents undefined on failure.
*/
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_crypt_advance_key_pos(ChiakiTakion *takion, size_t data_size, size_t *key_pos);
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_crypt_advance_key_pos(ChiakiTakion *takion, size_t data_size, uint64_t *key_pos);
/**
* Send a datagram directly on the socket.
@ -193,7 +193,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_raw(ChiakiTakion *takion, const
*
* If encryption is disabled, the MAC will be set to 0.
*/
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send(ChiakiTakion *takion, uint8_t *buf, size_t buf_size);
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send(ChiakiTakion *takion, uint8_t *buf, size_t buf_size, uint64_t key_pos);
/**
* Thread-safe while Takion is running.
@ -220,7 +220,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_feedback_history(ChiakiTakion *
#define CHIAKI_TAKION_V9_AV_HEADER_SIZE_VIDEO 0x17
#define CHIAKI_TAKION_V9_AV_HEADER_SIZE_AUDIO 0x12
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_v9_av_packet_parse(ChiakiTakionAVPacket *packet, uint8_t *buf, size_t buf_size);
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_v9_av_packet_parse(ChiakiTakionAVPacket *packet, ChiakiKeyState *key_state, uint8_t *buf, size_t buf_size);
#define CHIAKI_TAKION_V7_AV_HEADER_SIZE_BASE 0x12
#define CHIAKI_TAKION_V7_AV_HEADER_SIZE_VIDEO_ADD 0x3
@ -228,7 +228,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_v9_av_packet_parse(ChiakiTakionAVPac
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_v7_av_packet_format_header(uint8_t *buf, size_t buf_size, size_t *header_size_out, ChiakiTakionAVPacket *packet);
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_v7_av_packet_parse(ChiakiTakionAVPacket *packet, uint8_t *buf, size_t buf_size);
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_v7_av_packet_parse(ChiakiTakionAVPacket *packet, ChiakiKeyState *key_state, uint8_t *buf, size_t buf_size);
#ifdef __cplusplus
}

View file

@ -79,7 +79,6 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_ctrl_init(ChiakiCtrl *ctrl, ChiakiSession *
goto error_notif_pipe;
return err;
error_notif_mutex:
chiaki_mutex_fini(&ctrl->notif_mutex);
error_notif_pipe:
chiaki_stop_pipe_fini(&ctrl->notif_pipe);

View file

@ -210,7 +210,7 @@ CHIAKI_EXPORT void chiaki_gkcrypt_gen_tmp_gmac_key(ChiakiGKCrypt *gkcrypt, uint6
memcpy(key_out, gkcrypt->key_gmac_base, sizeof(gkcrypt->key_gmac_base));
}
CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_gen_key_stream(ChiakiGKCrypt *gkcrypt, size_t key_pos, uint8_t *buf, size_t buf_size)
CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_gen_key_stream(ChiakiGKCrypt *gkcrypt, uint64_t key_pos, uint8_t *buf, size_t buf_size)
{
assert(key_pos % CHIAKI_GKCRYPT_BLOCK_SIZE == 0);
assert(buf_size % CHIAKI_GKCRYPT_BLOCK_SIZE == 0);
@ -276,7 +276,7 @@ static bool gkcrypt_key_buf_should_generate(ChiakiGKCrypt *gkcrypt)
return gkcrypt->last_key_pos > gkcrypt->key_buf_key_pos_min + gkcrypt->key_buf_populated / 2;
}
CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_get_key_stream(ChiakiGKCrypt *gkcrypt, size_t key_pos, uint8_t *buf, size_t buf_size)
CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_get_key_stream(ChiakiGKCrypt *gkcrypt, uint64_t key_pos, uint8_t *buf, size_t buf_size)
{
if(!gkcrypt->key_buf)
return chiaki_gkcrypt_gen_key_stream(gkcrypt, key_pos, buf, buf_size);
@ -291,7 +291,15 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_get_key_stream(ChiakiGKCrypt *gkcry
if(key_pos < gkcrypt->key_buf_key_pos_min
|| key_pos + buf_size >= gkcrypt->key_buf_key_pos_min + gkcrypt->key_buf_populated)
{
CHIAKI_LOGW(gkcrypt->log, "Requested key stream for key pos %#llx on GKCrypt %d, but it's not in the buffer", (int)key_pos, gkcrypt->index);
CHIAKI_LOGW(gkcrypt->log, "Requested key stream for key pos %#llx on GKCrypt %d, but it's not in the buffer:"
" key buf size %#llx, start offset: %#llx, populated: %#llx, min key pos: %#llx, last key pos: %#llx",
(unsigned long long)key_pos,
gkcrypt->index,
(unsigned long long)gkcrypt->key_buf_size,
(unsigned long long)gkcrypt->key_buf_start_offset,
(unsigned long long)gkcrypt->key_buf_populated,
(unsigned long long)gkcrypt->key_buf_key_pos_min,
(unsigned long long)gkcrypt->last_key_pos);
chiaki_mutex_unlock(&gkcrypt->key_buf_mutex);
err = chiaki_gkcrypt_gen_key_stream(gkcrypt, key_pos, buf, buf_size);
}
@ -318,9 +326,9 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_get_key_stream(ChiakiGKCrypt *gkcry
return err;
}
CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_decrypt(ChiakiGKCrypt *gkcrypt, size_t key_pos, uint8_t *buf, size_t buf_size)
CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_decrypt(ChiakiGKCrypt *gkcrypt, uint64_t key_pos, uint8_t *buf, size_t buf_size)
{
size_t padding_pre = key_pos % CHIAKI_GKCRYPT_BLOCK_SIZE;
uint64_t padding_pre = key_pos % CHIAKI_GKCRYPT_BLOCK_SIZE;
size_t full_size = ((padding_pre + buf_size + CHIAKI_GKCRYPT_BLOCK_SIZE - 1) / CHIAKI_GKCRYPT_BLOCK_SIZE) * CHIAKI_GKCRYPT_BLOCK_SIZE;
uint8_t *key_stream = malloc(full_size);
@ -340,7 +348,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_decrypt(ChiakiGKCrypt *gkcrypt, siz
return CHIAKI_ERR_SUCCESS;
}
CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_gmac(ChiakiGKCrypt *gkcrypt, size_t key_pos, const uint8_t *buf, size_t buf_size, uint8_t *gmac_out)
CHIAKI_EXPORT ChiakiErrorCode chiaki_gkcrypt_gmac(ChiakiGKCrypt *gkcrypt, uint64_t key_pos, const uint8_t *buf, size_t buf_size, uint8_t *gmac_out)
{
uint8_t iv[CHIAKI_GKCRYPT_BLOCK_SIZE];
counter_add(iv, gkcrypt->iv, key_pos / 0x10);
@ -463,7 +471,7 @@ static ChiakiErrorCode gkcrypt_generate_next_chunk(ChiakiGKCrypt *gkcrypt)
{
assert(gkcrypt->key_buf_populated + KEY_BUF_CHUNK_SIZE <= gkcrypt->key_buf_size);
size_t buf_offset = (gkcrypt->key_buf_start_offset + gkcrypt->key_buf_populated) % gkcrypt->key_buf_size;
size_t key_pos = gkcrypt->key_buf_key_pos_min + gkcrypt->key_buf_populated;
uint64_t key_pos = gkcrypt->key_buf_key_pos_min + gkcrypt->key_buf_populated;
uint8_t *buf_start = gkcrypt->key_buf + buf_offset;
chiaki_mutex_unlock(&gkcrypt->key_buf_mutex);
@ -505,7 +513,7 @@ static void *gkcrypt_thread_func(void *user)
if(gkcrypt->last_key_pos > gkcrypt->key_buf_key_pos_min + gkcrypt->key_buf_populated)
{
// skip ahead if the last key pos is already beyond our buffer
size_t key_pos = (gkcrypt->last_key_pos / KEY_BUF_CHUNK_SIZE) * KEY_BUF_CHUNK_SIZE;
uint64_t key_pos = (gkcrypt->last_key_pos / KEY_BUF_CHUNK_SIZE) * KEY_BUF_CHUNK_SIZE;
CHIAKI_LOGW(gkcrypt->log, "Already requested a higher key pos than in the buffer, skipping ahead from min %#llx to %#llx",
(unsigned long long)gkcrypt->key_buf_key_pos_min,
(unsigned long long)key_pos);
@ -533,7 +541,7 @@ CHIAKI_EXPORT void chiaki_key_state_init(ChiakiKeyState *state)
state->prev = 0;
}
CHIAKI_EXPORT uint64_t chiaki_key_state_request_pos(ChiakiKeyState *state, uint32_t low)
CHIAKI_EXPORT uint64_t chiaki_key_state_request_pos(ChiakiKeyState *state, uint32_t low, bool commit)
{
uint32_t prev_low = (uint32_t)state->prev;
uint32_t high = (uint32_t)(state->prev >> 32);
@ -541,5 +549,13 @@ CHIAKI_EXPORT uint64_t chiaki_key_state_request_pos(ChiakiKeyState *state, uint3
high++;
else if(chiaki_seq_num_32_lt(low, prev_low) && low > prev_low && high)
high--;
return state->prev = (((uint64_t)high) << 32) | ((uint64_t)low);
uint64_t res = (((uint64_t)high) << 32) | ((uint64_t)low);
if(commit)
state->prev = res;
return res;
}
CHIAKI_EXPORT void chiaki_key_state_commit(ChiakiKeyState *state, uint64_t prev)
{
state->prev = prev;
}

View file

@ -16,6 +16,7 @@
#include <pb_decode.h>
#include <pb.h>
#include <chiaki/takion.h>
#include <chiaki/gkcrypt.h>
#ifndef _WIN32
#include <sys/types.h>
@ -85,6 +86,8 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_senkusha_init(ChiakiSenkusha *senkusha, Chi
senkusha->ping_tag = 0;
senkusha->pong_time_us = 0;
chiaki_key_state_init(&senkusha->takion.key_state);
return CHIAKI_ERR_SUCCESS;
error_state_mutex:

View file

@ -3,6 +3,7 @@
#include <chiaki/takion.h>
#include <chiaki/congestioncontrol.h>
#include <chiaki/random.h>
#include <chiaki/gkcrypt.h>
#include <fcntl.h>
#include <stdbool.h>
@ -71,6 +72,8 @@ int takion_packet_type_mac_offset(TakionPacketType type)
case TAKION_PACKET_TYPE_VIDEO:
case TAKION_PACKET_TYPE_AUDIO:
return 0xa;
case TAKION_PACKET_TYPE_CONGESTION:
return 7;
default:
return -1;
}
@ -88,6 +91,8 @@ int takion_packet_type_key_pos_offset(TakionPacketType type)
case TAKION_PACKET_TYPE_VIDEO:
case TAKION_PACKET_TYPE_AUDIO:
return 0xe;
case TAKION_PACKET_TYPE_CONGESTION:
return 0xb;
default:
return -1;
}
@ -107,7 +112,7 @@ typedef struct takion_message_t
{
uint32_t tag;
//uint8_t zero[4];
uint32_t key_pos;
uint64_t key_pos;
uint8_t chunk_type;
uint8_t chunk_flags;
@ -162,7 +167,7 @@ static void takion_handle_packet_message(ChiakiTakion *takion, uint8_t *buf, siz
static void takion_handle_packet_message_data(ChiakiTakion *takion, uint8_t *packet_buf, size_t packet_buf_size, uint8_t type_b, uint8_t *payload, size_t payload_size);
static void takion_handle_packet_message_data_ack(ChiakiTakion *takion, uint8_t flags, uint8_t *buf, size_t buf_size);
static ChiakiErrorCode takion_parse_message(ChiakiTakion *takion, uint8_t *buf, size_t buf_size, TakionMessage *msg);
static void takion_write_message_header(uint8_t *buf, uint32_t tag, uint32_t key_pos, uint8_t chunk_type, uint8_t chunk_flags, size_t payload_data_size);
static void takion_write_message_header(uint8_t *buf, uint32_t tag, uint64_t key_pos, uint8_t chunk_type, uint8_t chunk_flags, size_t payload_data_size);
static ChiakiErrorCode takion_send_message_init(ChiakiTakion *takion, TakionMessagePayloadInit *payload);
static ChiakiErrorCode takion_send_message_cookie(ChiakiTakion *takion, uint8_t *cookie);
static ChiakiErrorCode takion_recv(ChiakiTakion *takion, uint8_t *buf, size_t *buf_size, uint64_t timeout_ms);
@ -304,7 +309,7 @@ CHIAKI_EXPORT void chiaki_takion_close(ChiakiTakion *takion)
chiaki_mutex_fini(&takion->gkcrypt_local_mutex);
}
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_crypt_advance_key_pos(ChiakiTakion *takion, size_t data_size, size_t *key_pos)
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_crypt_advance_key_pos(ChiakiTakion *takion, size_t data_size, uint64_t *key_pos)
{
ChiakiErrorCode err = chiaki_mutex_lock(&takion->gkcrypt_local_mutex);
if(err != CHIAKI_ERR_SUCCESS)
@ -312,7 +317,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_crypt_advance_key_pos(ChiakiTakion *
if(takion->gkcrypt_local)
{
size_t cur = takion->key_pos_local;
uint64_t cur = takion->key_pos_local;
if(SIZE_MAX - cur < data_size)
{
chiaki_mutex_unlock(&takion->gkcrypt_local_mutex);
@ -337,8 +342,26 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_raw(ChiakiTakion *takion, const
return CHIAKI_ERR_SUCCESS;
}
static ChiakiErrorCode chiaki_takion_packet_read_key_pos(ChiakiTakion *takion, uint8_t *buf, size_t buf_size, uint64_t *key_pos_out)
{
if(buf_size < 1)
return CHIAKI_ERR_BUF_TOO_SMALL;
static ChiakiErrorCode chiaki_takion_packet_mac(ChiakiGKCrypt *crypt, uint8_t *buf, size_t buf_size, uint8_t *mac_out, uint8_t *mac_old_out, ChiakiTakionPacketKeyPos *key_pos_out)
TakionPacketType base_type = buf[0] & TAKION_PACKET_BASE_TYPE_MASK;
int key_pos_offset = takion_packet_type_key_pos_offset(base_type);
if(key_pos_offset < 0)
return CHIAKI_ERR_INVALID_DATA;
if(buf_size < key_pos_offset + sizeof(uint32_t))
return CHIAKI_ERR_BUF_TOO_SMALL;
uint32_t key_pos_low = ntohl(*((chiaki_unaligned_uint32_t *)(buf + key_pos_offset)));
*key_pos_out = chiaki_key_state_request_pos(&takion->key_state, key_pos_low, false);
return CHIAKI_ERR_SUCCESS;
}
static ChiakiErrorCode chiaki_takion_packet_mac(ChiakiGKCrypt *crypt, uint8_t *buf, size_t buf_size, uint64_t key_pos, uint8_t *mac_out, uint8_t *mac_old_out)
{
if(buf_size < 1)
return CHIAKI_ERR_BUF_TOO_SMALL;
@ -349,7 +372,7 @@ static ChiakiErrorCode chiaki_takion_packet_mac(ChiakiGKCrypt *crypt, uint8_t *b
if(mac_offset < 0 || key_pos_offset < 0)
return CHIAKI_ERR_INVALID_DATA;
if(buf_size < mac_offset + CHIAKI_GKCRYPT_GMAC_SIZE || buf_size < key_pos_offset + sizeof(ChiakiTakionPacketKeyPos))
if(buf_size < mac_offset + CHIAKI_GKCRYPT_GMAC_SIZE || buf_size < key_pos_offset + sizeof(uint32_t))
return CHIAKI_ERR_BUF_TOO_SMALL;
if(mac_old_out)
@ -357,31 +380,31 @@ static ChiakiErrorCode chiaki_takion_packet_mac(ChiakiGKCrypt *crypt, uint8_t *b
memset(buf + mac_offset, 0, CHIAKI_GKCRYPT_GMAC_SIZE);
ChiakiTakionPacketKeyPos key_pos = ntohl(*((ChiakiTakionPacketKeyPos *)(buf + key_pos_offset)));
if(crypt)
{
uint8_t key_pos_tmp[sizeof(uint32_t)];
if(base_type == TAKION_PACKET_TYPE_CONTROL)
memset(buf + key_pos_offset, 0, sizeof(ChiakiTakionPacketKeyPos));
{
memcpy(key_pos_tmp, buf + key_pos_offset, sizeof(uint32_t));
memset(buf + key_pos_offset, 0, sizeof(uint32_t));
}
chiaki_gkcrypt_gmac(crypt, key_pos, buf, buf_size, buf + mac_offset);
*((ChiakiTakionPacketKeyPos *)(buf + key_pos_offset)) = htonl(key_pos);
if(base_type == TAKION_PACKET_TYPE_CONTROL)
memcpy(buf + key_pos_offset, key_pos_tmp, sizeof(uint32_t));
}
if(key_pos_out)
*key_pos_out = key_pos;
memcpy(mac_out, buf + mac_offset, CHIAKI_GKCRYPT_GMAC_SIZE);
return CHIAKI_ERR_SUCCESS;
}
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send(ChiakiTakion *takion, uint8_t *buf, size_t buf_size)
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send(ChiakiTakion *takion, uint8_t *buf, size_t buf_size, uint64_t key_pos)
{
ChiakiErrorCode err = chiaki_mutex_lock(&takion->gkcrypt_local_mutex);
if(err != CHIAKI_ERR_SUCCESS)
return err;
uint8_t mac[CHIAKI_GKCRYPT_GMAC_SIZE];
err = chiaki_takion_packet_mac(takion->gkcrypt_local, buf, buf_size, mac, NULL, NULL);
err = chiaki_takion_packet_mac(takion->gkcrypt_local, buf, buf_size, key_pos, mac, NULL);
chiaki_mutex_unlock(&takion->gkcrypt_local_mutex);
if(err != CHIAKI_ERR_SUCCESS)
return err;
@ -397,7 +420,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_message_data(ChiakiTakion *taki
// TODO: can we make this more memory-efficient?
// TODO: split packet if necessary?
size_t key_pos;
uint64_t key_pos;
ChiakiErrorCode err = chiaki_takion_crypt_advance_key_pos(takion, buf_size, &key_pos);
if(err != CHIAKI_ERR_SUCCESS)
return err;
@ -424,7 +447,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_message_data(ChiakiTakion *taki
*(msg_payload + 8) = 0;
memcpy(msg_payload + 9, buf, buf_size);
err = chiaki_takion_send(takion, packet_buf, packet_size); // will alter packet_buf with gmac
err = chiaki_takion_send(takion, packet_buf, packet_size, key_pos); // will alter packet_buf with gmac
if(err != CHIAKI_ERR_SUCCESS)
{
CHIAKI_LOGE(takion->log, "Takion failed to send data packet: %s", chiaki_error_string(err));
@ -445,7 +468,7 @@ static ChiakiErrorCode chiaki_takion_send_message_data_ack(ChiakiTakion *takion,
uint8_t buf[1 + TAKION_MESSAGE_HEADER_SIZE + 0xc];
buf[0] = TAKION_PACKET_TYPE_CONTROL;
size_t key_pos;
uint64_t key_pos;
ChiakiErrorCode err = chiaki_takion_crypt_advance_key_pos(takion, sizeof(buf), &key_pos);
if(err != CHIAKI_ERR_SUCCESS)
return err;
@ -458,7 +481,7 @@ static ChiakiErrorCode chiaki_takion_send_message_data_ack(ChiakiTakion *takion,
*((chiaki_unaligned_uint16_t *)(data_ack + 8)) = 0;
*((chiaki_unaligned_uint16_t *)(data_ack + 0xa)) = 0;
return chiaki_takion_send(takion, buf, sizeof(buf));
return chiaki_takion_send(takion, buf, sizeof(buf), key_pos);
}
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_congestion(ChiakiTakion *takion, ChiakiTakionCongestionPacket *packet)
@ -470,19 +493,15 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_congestion(ChiakiTakion *takion
*((chiaki_unaligned_uint16_t *)(buf + 3)) = htons(packet->word_1);
*((chiaki_unaligned_uint16_t *)(buf + 5)) = htons(packet->word_2);
ChiakiErrorCode err = chiaki_mutex_lock(&takion->gkcrypt_local_mutex);
if(err != CHIAKI_ERR_SUCCESS)
return err;
*((chiaki_unaligned_uint32_t *)(buf + 0xb)) = htonl((uint32_t)takion->key_pos_local); // TODO: is this correct? shouldn't key_pos be 0 for mac calculation?
err = chiaki_gkcrypt_gmac(takion->gkcrypt_local, takion->key_pos_local, buf, sizeof(buf), buf + 7);
takion->key_pos_local += sizeof(buf);
chiaki_mutex_unlock(&takion->gkcrypt_local_mutex);
uint64_t key_pos;
ChiakiErrorCode err = chiaki_takion_crypt_advance_key_pos(takion, sizeof(buf), &key_pos);
if(err != CHIAKI_ERR_SUCCESS)
return err;
*((chiaki_unaligned_uint32_t *)(buf + 0xb)) = htonl((uint32_t)key_pos); // TODO: is this correct? shouldn't key_pos be 0 for mac calculation?
//chiaki_log_hexdump(takion->log, CHIAKI_LOG_DEBUG, buf, sizeof(buf));
return chiaki_takion_send_raw(takion, buf, sizeof(buf));
return chiaki_takion_send(takion, buf, sizeof(buf), key_pos);
}
static ChiakiErrorCode takion_send_feedback_packet(ChiakiTakion *takion, uint8_t *buf, size_t buf_size)
@ -495,7 +514,7 @@ static ChiakiErrorCode takion_send_feedback_packet(ChiakiTakion *takion, uint8_t
if(err != CHIAKI_ERR_SUCCESS)
return err;
size_t key_pos;
uint64_t key_pos;
err = chiaki_takion_crypt_advance_key_pos(takion, payload_size + CHIAKI_GKCRYPT_BLOCK_SIZE, &key_pos);
if(err != CHIAKI_ERR_SUCCESS)
goto beach;
@ -780,8 +799,14 @@ static ChiakiErrorCode takion_handle_packet_mac(ChiakiTakion *takion, uint8_t ba
uint8_t mac[CHIAKI_GKCRYPT_GMAC_SIZE];
uint8_t mac_expected[CHIAKI_GKCRYPT_GMAC_SIZE];
ChiakiTakionPacketKeyPos key_pos;
ChiakiErrorCode err = chiaki_takion_packet_mac(takion->gkcrypt_remote, buf, buf_size, mac_expected, mac, &key_pos);
uint64_t key_pos;
ChiakiErrorCode err = chiaki_takion_packet_read_key_pos(takion, buf, buf_size, &key_pos);
if(err != CHIAKI_ERR_SUCCESS)
{
CHIAKI_LOGE(takion->log, "Takion failed to pull key_pos out of received packet");
return err;
}
err = chiaki_takion_packet_mac(takion->gkcrypt_remote, buf, buf_size, key_pos, mac_expected, mac);
if(err != CHIAKI_ERR_SUCCESS)
{
CHIAKI_LOGE(takion->log, "Takion failed to calculate mac for received packet");
@ -799,6 +824,8 @@ static ChiakiErrorCode takion_handle_packet_mac(ChiakiTakion *takion, uint8_t ba
return CHIAKI_ERR_INVALID_MAC;
}
chiaki_key_state_commit(&takion->key_state, key_pos);
return CHIAKI_ERR_SUCCESS;
}
@ -1014,7 +1041,7 @@ static void takion_handle_packet_message_data_ack(ChiakiTakion *takion, uint8_t
*
* @param raw_payload_size size of the actual data of the payload excluding type_a, type_b and payload_size
*/
static void takion_write_message_header(uint8_t *buf, uint32_t tag, uint32_t key_pos, uint8_t chunk_type, uint8_t chunk_flags, size_t payload_data_size)
static void takion_write_message_header(uint8_t *buf, uint32_t tag, uint64_t key_pos, uint8_t chunk_type, uint8_t chunk_flags, size_t payload_data_size)
{
*((chiaki_unaligned_uint32_t *)(buf + 0)) = htonl(tag);
memset(buf + 4, 0, CHIAKI_GKCRYPT_GMAC_SIZE);
@ -1033,7 +1060,8 @@ static ChiakiErrorCode takion_parse_message(ChiakiTakion *takion, uint8_t *buf,
}
msg->tag = ntohl(*((chiaki_unaligned_uint32_t *)buf));
msg->key_pos = ntohl(*((chiaki_unaligned_uint32_t *)(buf + 0x8)));
uint32_t key_pos_low = ntohl(*((chiaki_unaligned_uint32_t *)(buf + 0x8)));
msg->key_pos = chiaki_key_state_request_pos(&takion->key_state, key_pos_low, true);
msg->chunk_type = buf[0xc];
msg->chunk_flags = buf[0xd];
msg->payload_size = ntohs(*((chiaki_unaligned_uint16_t *)(buf + 0xe)));
@ -1185,7 +1213,7 @@ static void takion_handle_packet_av(ChiakiTakion *takion, uint8_t base_type, uin
assert(base_type == TAKION_PACKET_TYPE_VIDEO || base_type == TAKION_PACKET_TYPE_AUDIO);
ChiakiTakionAVPacket packet;
ChiakiErrorCode err = takion->av_packet_parse(&packet, buf, buf_size);
ChiakiErrorCode err = takion->av_packet_parse(&packet, &takion->key_state, buf, buf_size);
if(err != CHIAKI_ERR_SUCCESS)
{
if(err == CHIAKI_ERR_BUF_TOO_SMALL)
@ -1202,7 +1230,7 @@ static void takion_handle_packet_av(ChiakiTakion *takion, uint8_t base_type, uin
}
}
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_v9_av_packet_parse(ChiakiTakionAVPacket *packet, uint8_t *buf, size_t buf_size)
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_v9_av_packet_parse(ChiakiTakionAVPacket *packet, ChiakiKeyState *key_state, uint8_t *buf, size_t buf_size)
{
memset(packet, 0, sizeof(ChiakiTakionAVPacket));
@ -1242,8 +1270,8 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_v9_av_packet_parse(ChiakiTakionAVPac
}
packet->codec = av[8];
packet->key_pos = ntohl(*((chiaki_unaligned_uint32_t *)(av + 0xd)));
uint32_t key_pos_low = ntohl(*((chiaki_unaligned_uint32_t *)(av + 0xd)));
packet->key_pos = chiaki_key_state_request_pos(key_state, key_pos_low, true);
uint8_t unknown_1 = av[0x11];
@ -1313,7 +1341,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_v7_av_packet_format_header(uint8_t *
*(chiaki_unaligned_uint32_t *)(buf + 0xa) = 0; // unknown
*(chiaki_unaligned_uint32_t *)(buf + 0xe) = packet->key_pos;
*(chiaki_unaligned_uint32_t *)(buf + 0xe) = (uint32_t)packet->key_pos;
uint8_t *cur = buf + 0x12;
if(packet->is_video)
@ -1332,7 +1360,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_v7_av_packet_format_header(uint8_t *
return CHIAKI_ERR_SUCCESS;
}
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_v7_av_packet_parse(ChiakiTakionAVPacket *packet, uint8_t *buf, size_t buf_size)
CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_v7_av_packet_parse(ChiakiTakionAVPacket *packet, ChiakiKeyState *key_state, uint8_t *buf, size_t buf_size)
{
memset(packet, 0, sizeof(ChiakiTakionAVPacket));