/** Encrypts a packet and adds the common method header */ static bool method_encrypt(UNUSED fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in) { size_t tail_len = alignto(in.len, sizeof(fastd_block128_t))-in.len; *out = fastd_buffer_alloc(in.len, alignto(COMMON_HEADBYTES, 16), sizeof(fastd_block128_t)+tail_len); if (tail_len) memset(in.data+in.len, 0, tail_len); uint8_t nonce[session->method->cipher_info->iv_length ?: 1] __attribute__((aligned(8))); fastd_method_expand_nonce(nonce, session->common.send_nonce, sizeof(nonce)); int n_blocks = block_count(in.len, sizeof(fastd_block128_t)); fastd_block128_t *inblocks = in.data; fastd_block128_t *outblocks = out->data; bool ok = session->cipher->crypt(session->cipher_state, outblocks, inblocks, n_blocks*sizeof(fastd_block128_t), nonce); if (!ok) { fastd_buffer_free(*out); return false; } fastd_buffer_free(in); fastd_method_put_common_header(out, session->common.send_nonce, 0); fastd_method_increment_nonce(&session->common); return true; }
/** Verifies and decrypts a packet */ static bool method_decrypt(fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in, bool *reordered) { if (in.len < COMMON_HEADBYTES+sizeof(fastd_block128_t)) return false; if (!method_session_is_valid(session)) return false; uint8_t in_nonce[COMMON_NONCEBYTES]; uint8_t flags; int64_t age; if (!fastd_method_handle_common_header(&session->common, &in, in_nonce, &flags, &age)) return false; if (flags) return false; uint8_t nonce[session->method->cipher_info->iv_length] __attribute__((aligned(8))); fastd_method_expand_nonce(nonce, in_nonce, sizeof(nonce)); size_t tail_len = alignto(in.len, sizeof(fastd_block128_t))-in.len; *out = fastd_buffer_alloc(in.len, 0, tail_len); int n_blocks = block_count(in.len, sizeof(fastd_block128_t)); fastd_block128_t *inblocks = in.data; fastd_block128_t *outblocks = out->data; fastd_block128_t tag; bool ok = session->cipher->crypt(session->cipher_state, outblocks, inblocks, n_blocks*sizeof(fastd_block128_t), nonce); if (ok) { if (tail_len) memset(in.data+in.len, 0, tail_len); put_size(&inblocks[n_blocks], in.len-sizeof(fastd_block128_t)); ok = session->ghash->digest(session->ghash_state, &tag, inblocks+1, n_blocks*sizeof(fastd_block128_t)); } if (!ok || !block_equal(&tag, &outblocks[0])) { fastd_buffer_free(*out); return false; } fastd_buffer_free(in); fastd_buffer_push_head(out, sizeof(fastd_block128_t)); fastd_tristate_t reorder_check = fastd_method_reorder_check(peer, &session->common, in_nonce, age); if (reorder_check.set) { *reordered = reorder_check.state; } else { fastd_buffer_free(*out); *out = fastd_buffer_alloc(0, 0, 0); } return true; }
static int bin_listend(Generator* generator, Symbol* tsym, void* liststate, ListClass lc, int uid, size_t count, Bytebuffer* buf, ...) { if(lc == LISTCOMPOUND) { int offsetbase = *((int*)liststate); /* Pad out the whole instance */ alignto(tsym->typ.cmpdalign,buf,offsetbase); } return 1; }
static int bin_list(Generator* generator, Symbol* tsym, void* liststate, ListClass lc, int uid, size_t count, Bytebuffer* buf, ...) { if(lc == LISTCOMPOUND) { int offsetbase = *((int*)liststate); /* Pad for the alignment */ alignto(tsym->typ.alignment,buf,offsetbase); } return 1; }
/** Encrypts and authenticates a packet */ static bool method_encrypt(UNUSED fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in) { size_t tail_len = in.len ? alignto(in.len, 2 * sizeof(fastd_block128_t))-in.len : (2 * sizeof(fastd_block128_t)); fastd_buffer_pull_head_zero(&in, sizeof(fastd_block128_t)); *out = fastd_buffer_alloc(in.len, alignto(COMMON_HEADBYTES, 16), tail_len); uint8_t nonce[session->method->cipher_info->iv_length] __attribute__((aligned(8))); fastd_method_expand_nonce(nonce, session->common.send_nonce, sizeof(nonce)); int n_blocks = block_count(in.len, sizeof(fastd_block128_t)); fastd_block128_t *inblocks = in.data; fastd_block128_t *outblocks = out->data; fastd_block128_t tag; bool ok = session->cipher->crypt(session->cipher_state, outblocks, inblocks, n_blocks*sizeof(fastd_block128_t), nonce); if (ok) { if (tail_len) memset(out->data+out->len, 0, tail_len); ok = session->uhash->digest(session->uhash_state, &tag, outblocks+1, out->len - sizeof(fastd_block128_t)); } if (!ok) { fastd_buffer_free(*out); return false; } xor_a(&outblocks[0], &tag); fastd_buffer_free(in); fastd_method_put_common_header(out, session->common.send_nonce, 0); fastd_method_increment_nonce(&session->common); return true; }
extern void *nalloc(size_t n) { size_t base; Block *ulp; n = alignto(n, sizeof (ALIGN_T)); ulp = ul; if (ulp != NULL && n + (base = ulp->used) < ulp->size) { ulp->used = base + n; return &ulp->mem[base]; } else { getblock(n); /* assert(ul->used) == 0 */ (ulp = ul)->used = n; return &ulp->mem[0]; } }
static void getblock(size_t n) { Block *r, *p; for (r = fl, p = NULL; r != NULL; p = r, r = r->n) if (n <= r->size) break; /* look for a block which fits the request */ if (r != NULL) { /* if one is found, take it off the free list */ if (p != NULL) p->n = r->n; else fl = r->n; } else { /* else allocate a new block */ r = enew(Block); r->mem = ealloc(r->size = alignto(n, BLOCKSIZE)); } r->used = 0; r->n = ul; ul = r; }
/* Used for compound instances */ static void genbin_compound(Symbol* tsym, Datasrc* datasrc, Datalist* fillsrc, Bytebuffer* memory) { int i; int base = bblength(memory); if(!issublist(datasrc)) { semerror(srcline(datasrc),"Compound data must be enclosed in {..}"); } /* Use this datasrc list to get values for compound fields */ srcpush(datasrc); for(i=0;i<listlength(tsym->subnodes);i++) { Symbol* field = (Symbol*)listget(tsym->subnodes,i); if(!srcmore(datasrc)) { /* generate a fill value*/ Datalist* fillsrc = getfiller(tsym); genbin_data(field,datasrc,fillsrc,memory); } else genbin_data(field,datasrc,NULL,memory); } srcpop(datasrc); /* Re: github issue 323: we may need to pad the end of the structure to make its size be a multiple of the largest alignment. */ alignto(tsym->cmpdalignment,buf,base); }