ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
prepare.c
Go to the documentation of this file.
5#include <string.h>
6
7_Static_assert(ACIP_TRAFFIC_CONTROL == CRYPTO_RECORD_CONTROL_CHANNEL, "Control channel IDs must match");
8
9asciichat_error_t acip_packet_plan(crypto_context_t *crypto, const socket_buffer_t *buffers, size_t count,
10 acip_packet_plan_t *plan) {
11 if (!plan)
12 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing ACIP packet plan");
13 *plan = (acip_packet_plan_t){0};
14 if (!buffers || !count || count > SOCKET_IOV_MAX)
15 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid ACIP packet vectors");
16 size_t size = 0;
17 for (size_t i = 0; i < count; ++i) {
18 if ((buffers[i].len && !buffers[i].data) || buffers[i].len > SOCKET_SEND_BUFFER_MAX - size)
19 return SET_ERRNO(ERROR_NETWORK_SIZE, "Invalid ACIP packet vector size");
20 size += buffers[i].len;
21 }
22 bool encrypt = false;
23 acip_send_options_t options = {.delivery = ACIP_DELIVERY_RELIABLE};
24 buffer_domain_t *domain = NULL;
25 if (buffers[0].len >= sizeof(packet_header_t)) {
26 packet_header_t header;
27 memcpy(&header, buffers[0].data, sizeof(header));
28 packet_type_t type = NET_TO_HOST_U16(header.type);
29 if (packet_is_handshake_type(type) || type == PACKET_TYPE_ERROR_MESSAGE)
30 domain = buffer_control_domain();
32 ? (acip_traffic_class_t)NET_TO_HOST_U32(header.client_id)
34 encrypt = crypto && crypto->encrypt_data && crypto_is_ready(crypto) && type != PACKET_TYPE_ENCRYPTED &&
35 !packet_is_initial_handshake_type(type);
36 } else {
37 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing ACIP packet header");
38 }
39 size_t capacity = 0;
40 crypto_record_t *records = NULL;
41 if (encrypt) {
42 if (size > CRYPTO_MAX_PLAINTEXT_SIZE - 24 ||
43 size > SOCKET_SEND_BUFFER_MAX - sizeof(packet_header_t) - CRYPTO_NONCE_SIZE - CRYPTO_MAC_SIZE)
44 return SET_ERRNO(ERROR_NETWORK_SIZE, "Encrypted ACIP packet too large");
45 crypto_session_t *session = NULL;
46 asciichat_error_t result = crypto_session_lock(crypto, &session);
47 if (result != ASCIICHAT_OK)
48 return result;
49 records = &session->records;
50 crypto_session_unlock(session);
51 capacity = size + 32 + crypto->nonce_size + crypto->mac_size;
52 }
53 *plan = (acip_packet_plan_t){.buffers = buffers,
54 .count = count,
55 .plaintext_size = size,
56 .ciphertext_capacity = capacity,
57 .encrypt = encrypt,
58 .domain = domain,
59 .records = records,
60 .options = options};
61 return ASCIICHAT_OK;
62}
63
65 void *ciphertext, size_t capacity, packet_header_t *header, size_t *length) {
66 if (length)
67 *length = 0;
68 if (!crypto || !plan || !plan->encrypt || !plan->buffers || !plan->count || !ciphertext || !header || !length)
69 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid ACIP encryption arguments");
70 if (capacity < plan->ciphertext_capacity)
71 return SET_ERRNO(ERROR_NETWORK_SIZE, "ACIP ciphertext storage too small");
72 const uint8_t *plaintext = plan->buffers[0].data;
73 uint8_t *gathered = NULL;
74 if (plan->count > 1) {
75 gathered = buffer_alloc(domain, plan->plaintext_size);
76 if (!gathered)
77 return SET_ERRNO(ERROR_MEMORY, "Cannot gather ACIP encryption input");
78 size_t offset = 0;
79 for (size_t i = 0; i < plan->count; ++i) {
80 if (plan->buffers[i].len)
81 memcpy(gathered + offset, plan->buffers[i].data, plan->buffers[i].len);
82 offset += plan->buffers[i].len;
83 }
84 plaintext = gathered;
85 }
86 size_t encrypted_length = 0;
87 crypto_session_t *session = NULL;
88 bool shared = !plan->records_locked && crypto && crypto->session && plan->records == &crypto->session->records;
89 asciichat_error_t encrypted = shared ? crypto_session_lock(crypto, &session) : ASCIICHAT_OK;
90 if (encrypted == ASCIICHAT_OK)
92 plan->options.delivery, plaintext, plan->plaintext_size,
93 ciphertext, capacity, &encrypted_length, domain)
94 : SET_ERRNO(ERROR_INVALID_STATE, "Missing authenticated record context");
95 if (session)
96 crypto_session_unlock(session);
97 buffer_release(gathered);
98 if (encrypted != ASCIICHAT_OK)
99 return encrypted;
100 socket_buffer_t slice = {ciphertext, encrypted_length};
101 asciichat_error_t result = packet_header_build(header, PACKET_TYPE_ENCRYPTED, &slice, 1, 0);
102 if (result != ASCIICHAT_OK)
103 return result;
104 *length = encrypted_length;
105 return ASCIICHAT_OK;
106}
107
108static asciichat_error_t validate_record_packet(void *context, unsigned flow, unsigned delivery, const void *packet,
109 size_t length) {
110 (void)context;
111 packet_header_t header;
112 asciichat_error_t result = packet_validate(packet, length, 0, &header);
113 if (result != ASCIICHAT_OK)
114 return result;
115 uint16_t type = NET_TO_HOST_U16(header.type);
116 if (flow > ACIP_TRAFFIC_VISUAL || delivery > ACIP_DELIVERY_DATAGRAM ||
117 (delivery == ACIP_DELIVERY_DATAGRAM && flow == ACIP_TRAFFIC_CONTROL) || type == PACKET_TYPE_ENCRYPTED ||
118 packet_is_initial_handshake_type(type) ||
121 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid authenticated packet channel");
122 return ASCIICHAT_OK;
123}
124
126 const void *packet, size_t length, uint8_t **output, size_t *written) {
127 if (!output || !written || !records || !records->crypto)
128 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid packet encryption arguments");
129 *output = NULL;
130 *written = 0;
131 if ((unsigned)flow > ACIP_TRAFFIC_VISUAL || (unsigned)delivery > ACIP_DELIVERY_DATAGRAM ||
132 (flow == ACIP_TRAFFIC_CONTROL && delivery == ACIP_DELIVERY_DATAGRAM))
133 return SET_ERRNO(ERROR_INVALID_STATE, "Invalid packet output channel");
134 asciichat_error_t result = validate_record_packet(NULL, flow, delivery, packet, length);
135 if (result != ASCIICHAT_OK)
136 return result;
137 socket_buffer_t slice = {packet, length};
138 if (length > CRYPTO_MAX_PLAINTEXT_SIZE - 24)
139 return SET_ERRNO(ERROR_NETWORK_SIZE, "Packet exceeds record plaintext capacity");
140 acip_packet_plan_t plan = {.buffers = &slice,
141 .count = 1,
142 .plaintext_size = length,
143 .encrypt = true,
144 .records = records,
145 .records_locked = true,
146 .options = {.traffic_class = flow, .delivery = delivery},
147 .ciphertext_capacity =
148 length + 32 + records->crypto->nonce_size + records->crypto->mac_size};
149 uint8_t *wire = buffer_alloc(plan.domain, sizeof(packet_header_t) + plan.ciphertext_capacity);
150 if (!wire)
151 return SET_ERRNO(ERROR_MEMORY, "Cannot allocate encrypted packet");
152 packet_header_t header;
153 size_t encrypted_length = 0;
154 result = acip_packet_encrypt(records->crypto, &plan, plan.domain, wire + sizeof(header), plan.ciphertext_capacity,
155 &header, &encrypted_length);
156 if (result != ASCIICHAT_OK) {
157 buffer_release(wire);
158 return result;
159 }
160 memcpy(wire, &header, sizeof(header));
161 *output = wire;
162 *written = sizeof(header) + encrypted_length;
163 return ASCIICHAT_OK;
164}
165
167 acip_delivery_t delivery, const void *packet, size_t length,
168 uint8_t **output, size_t *written, uint64_t *sequence) {
169 if (!output || !written)
170 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing decrypted packet output");
171 *output = NULL;
172 *written = 0;
173 packet_header_t header;
174 asciichat_error_t result = packet_validate(packet, length, 0, &header);
175 if (result != ASCIICHAT_OK)
176 return result;
177 if (NET_TO_HOST_U16(header.type) != PACKET_TYPE_ENCRYPTED)
178 return SET_ERRNO(ERROR_CRYPTO, "Expected encrypted packet");
179 return acip_packet_decrypt_payload(records, flow, delivery, (const uint8_t *)packet + sizeof(header),
180 length - sizeof(header), output, written, sequence);
181}
182
184 const void *packet, size_t length, uint8_t **output, size_t *written) {
185 return acip_packet_open_sequence(records, flow, delivery, packet, length, output, written, NULL);
186}
187
188asciichat_error_t acip_packet_decrypt_payload(crypto_record_t *records, unsigned flow, unsigned delivery,
189 const void *payload, size_t length, uint8_t **output, size_t *written,
190 uint64_t *sequence) {
191 return crypto_record_open_sequence(records, flow, delivery, payload, length, output, written, sequence,
192 validate_record_packet, NULL);
193}
#define SET_ERRNO(code,...)
void * buffer_alloc(buffer_domain_t *domain, size_t size)
Definition buffer.c:274
buffer_domain_t * buffer_control_domain(void)
Definition buffer.c:436
struct buffer_domain buffer_domain_t
Definition buffer.h:24
#define buffer_release(data)
Definition buffer.h:91
Hardware-Accelerated CRC32 Checksum Computation.
🔄 Network byte order conversion helpers
#define NET_TO_HOST_U16(val)
Definition endian.h:111
#define NET_TO_HOST_U32(val)
Definition endian.h:81
unsigned short uint16_t
Definition common.h:61
unsigned long long uint64_t
Definition common.h:63
unsigned char uint8_t
Definition common.h:60
bool crypto_is_ready(const crypto_context_t *ctx)
Check if key exchange is complete and ready for encryption.
#define CRYPTO_MAX_PLAINTEXT_SIZE
Maximum plaintext size (1MB).
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ERROR_INVALID_STATE
@ ERROR_NETWORK_PROTOCOL
Definition error_codes.h:76
@ ERROR_MEMORY
Definition error_codes.h:51
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_NETWORK_SIZE
Definition error_codes.h:77
@ ERROR_CRYPTO
Definition error_codes.h:93
@ ERROR_INVALID_PARAM
asciichat_error_t packet_validate(const void *packet, size_t length, size_t limit, packet_header_t *output)
Definition packet.c:86
packet_type_t
Network protocol packet type enumeration.
Definition packet.h:301
asciichat_error_t packet_header_build(packet_header_t *header, packet_type_t type, const socket_buffer_t *payload, size_t count, uint32_t client_id)
Definition packet.c:47
@ PACKET_TYPE_CRYPTO_EPOCH_MARKER
Definition packet.h:345
@ PACKET_TYPE_ENCRYPTED
Encrypted packet (after handshake completion).
Definition packet.h:355
@ PACKET_TYPE_ERROR_MESSAGE
Error packet with asciichat_error_t code and human-readable message.
Definition packet.h:374
struct crypto_session crypto_session_t
For crypto session, this is the live record that ties owner, mutex, records, rotation together....
void crypto_session_unlock(crypto_session_t *session)
asciichat_error_t crypto_session_lock(crypto_context_t *crypto, crypto_session_t **output)
asciichat_error_t acip_packet_open(crypto_record_t *records, acip_traffic_class_t flow, acip_delivery_t delivery, const void *packet, size_t length, uint8_t **output, size_t *written)
Definition prepare.c:183
asciichat_error_t acip_packet_decrypt_payload(crypto_record_t *records, unsigned flow, unsigned delivery, const void *payload, size_t length, uint8_t **output, size_t *written, uint64_t *sequence)
Definition prepare.c:188
asciichat_error_t acip_packet_plan(crypto_context_t *crypto, const socket_buffer_t *buffers, size_t count, acip_packet_plan_t *plan)
Definition prepare.c:9
asciichat_error_t acip_packet_encrypt(crypto_context_t *crypto, const acip_packet_plan_t *plan, buffer_domain_t *domain, void *ciphertext, size_t capacity, packet_header_t *header, size_t *length)
The useful part of acip packet plan is in buffers, count, plaintext_size, ciphertext_capacity: togeth...
Definition prepare.c:64
asciichat_error_t acip_packet_seal(crypto_record_t *records, acip_traffic_class_t flow, acip_delivery_t delivery, const void *packet, size_t length, uint8_t **output, size_t *written)
Definition prepare.c:125
asciichat_error_t acip_packet_open_sequence(crypto_record_t *records, acip_traffic_class_t flow, acip_delivery_t delivery, const void *packet, size_t length, uint8_t **output, size_t *written, uint64_t *sequence)
Definition prepare.c:166
asciichat_error_t crypto_record_seal_into_domain(crypto_record_t *state, unsigned traffic_class, unsigned delivery, const void *packet, size_t length, uint8_t *wire, size_t capacity, size_t *out_length, buffer_domain_t *requested_domain)
Definition record.c:39
asciichat_error_t crypto_record_open_sequence(crypto_record_t *state, unsigned traffic_class, unsigned delivery, const void *packet, size_t length, uint8_t **out, size_t *out_length, uint64_t *sequence_out, crypto_record_validate_fn validate, void *context)
Definition record.c:88
struct crypto_record crypto_record_t
When code needs to work with crypto record, it keeps crypto, key_epoch, last_receive_epoch,...
#define CRYPTO_RECORD_CONTROL_CHANNEL
Definition record.h:8
#define CRYPTO_NONCE_SIZE
Nonce size (XSalsa20).
Definition sizes.h:79
#define CRYPTO_MAC_SIZE
MAC size (Poly1305).
Definition sizes.h:85
🔤 String Manipulation and Shell Escaping Utilities
size_t ciphertext_capacity
Definition prepare.h:20
crypto_record_t * records
Definition prepare.h:22
acip_send_options_t options
Definition prepare.h:24
const socket_buffer_t * buffers
Definition prepare.h:17
buffer_domain_t * domain
Borrowed control reserve for handshake/error traffic; NULL otherwise.
Definition prepare.h:25
size_t plaintext_size
Definition prepare.h:19
acip_delivery_t delivery
Definition traffic.h:18
acip_traffic_class_t traffic_class
Definition traffic.h:17
Endpoint cryptographic state for handshake, packet protection, authentication, and rekeying.
struct crypto_session * session
Endpoint cryptographic state for handshake, packet protection, authentication, and rekeying.
crypto_context_t * crypto
Definition record.h:18
Fixed prefix shared by every ACIP packet on the wire.
Definition packet.h:628
acip_traffic_class_t acip_packet_traffic_class(uint16_t type)
Definition traffic.c:4
acip_traffic_class_t
Definition traffic.h:5
@ ACIP_TRAFFIC_CONTROL
Definition traffic.h:6
@ ACIP_TRAFFIC_VISUAL
Definition traffic.h:8
acip_delivery_t
Definition traffic.h:11
@ ACIP_DELIVERY_RELIABLE
Definition traffic.h:12
@ ACIP_DELIVERY_DATAGRAM
Definition traffic.h:13