int util_cmp(char *a, char *b) { if(!a || !b) return -1; if(a == b) return 0; if(strlen(a) != strlen(b)) return -1; return util_ct_memcmp(a,b,strlen(a)); }
lob_t ephemeral_decrypt(ephemeral_t ephem, lob_t outer) { uint8_t iv[16], hmac[32]; memset(iv,0,16); memcpy(iv,outer->body+16,4); memcpy(hmac,ephem->deckey,16); memcpy(hmac+16,iv,4); // mac just the ciphertext hmac_256(hmac,16+4,outer->body+16+4,outer->body_len-(4+16+4),hmac); fold3(hmac,hmac); if(util_ct_memcmp(hmac,outer->body+(outer->body_len-4),4) != 0) return LOG("hmac failed"); // decrypt in place aes_128_ctr(ephem->deckey,outer->body_len-(16+4+4),iv,outer->body+16+4,outer->body+16+4); // return parse attempt return lob_parse(outer->body+16+4, outer->body_len-(16+4+4)); }
uint8_t remote_verify(remote_t remote, local_t local, lob_t outer) { uint8_t shared[uECC_BYTES+4], hash[32]; if(!remote || !local || !outer) return 1; if(outer->head_len != 1 || outer->head[0] != 0x1a) return 2; // generate the key for the hmac, combining the shared secret and IV if(!uECC_shared_secret(remote->key, local->secret, shared)) return 3; memcpy(shared+uECC_BYTES,outer->body+21,4); // verify hmac_256(shared,uECC_BYTES+4,outer->body,outer->body_len-4,hash); fold3(hash,hash); if(util_ct_memcmp(hash,outer->body+(outer->body_len-4),4) != 0) { LOG("hmac failed"); return 4; } return 0; }
uint8_t remote_validate(remote_t remote, lob_t args, lob_t sig, uint8_t *data, size_t len) { uint8_t hash[32]; if(!args || !sig || !data || !len) return 1; if(lob_get_cmp(args,"alg","HS256") == 0) { if(sig->body_len != 32 || !args->body_len) return 2; hmac_256(args->body,args->body_len,data,len,hash); return (util_ct_memcmp(sig->body,hash,32) == 0) ? 0 : 3; } if(lob_get_cmp(args,"alg","ES160") == 0) { if(!remote || sig->body_len != KEY_BYTES) return 2; // hash data first e3x_hash(data,len,hash); return (uECC_verify(remote->key, hash, 32, sig->body, curve) == 1) ? 0 : 3; } return 3; }
// synchronize to incoming ephemeral key and set out at = in at, returns x if success, NULL if not e3x_exchange_t e3x_exchange_sync(e3x_exchange_t x, lob_t outer) { ephemeral_t ephem; if(!x || !outer) return LOG("bad args"); if(outer->body_len < 16) return LOG("outer too small"); if(x->in > x->out) x->out = x->in; // if the incoming ephemeral key is different, create a new ephemeral if(util_ct_memcmp(outer->body,x->eid,16) != 0) { ephem = x->cs->ephemeral_new(x->remote,outer); if(!ephem) return LOG("ephemeral creation failed %s",x->cs->err()); x->cs->ephemeral_free(x->ephem); x->ephem = ephem; memcpy(x->eid,outer->body,16); // reset incoming channel id validation x->last = 0; } return x; }