// makes sure all the crypto line state is set up, and creates line keys if exist int crypt_line_1a(crypt_t c, packet_t inner) { unsigned char line_public[uECC_BYTES*2], secret[uECC_BYTES], input[uECC_BYTES+16+16], hash[32]; char *hecc; crypt_1a_t cs; cs = (crypt_1a_t)c->cs; hecc = packet_get_str(inner,"ecc"); // it's where we stashed it if(!hecc || strlen(hecc) != uECC_BYTES*4) return 1; crypt_rand((unsigned char*)&(cs->seq),4); // init seq to random start // do the diffie hellman util_unhex((unsigned char*)hecc,uECC_BYTES*4,line_public); if(!uECC_shared_secret(line_public, cs->line_private, secret)) return 1; // make line keys! memcpy(input,secret,uECC_BYTES); memcpy(input+uECC_BYTES,c->lineOut,16); memcpy(input+uECC_BYTES+16,c->lineIn,16); crypt_hash(input,uECC_BYTES+16+16,hash); fold1(hash,cs->keyOut); memcpy(input+uECC_BYTES,c->lineIn,16); memcpy(input+uECC_BYTES+16,c->lineOut,16); crypt_hash(input,uECC_BYTES+16+16,hash); fold1(hash,cs->keyIn); return 0; }
ephemeral_t ephemeral_new(remote_t remote, lob_t outer) { uint8_t ekey[uECC_BYTES*2], shared[uECC_BYTES+((uECC_BYTES+1)*2)], hash[32]; ephemeral_t ephem; if(!remote) return NULL; if(!outer || outer->body_len < (uECC_BYTES+1)) return LOG("invalid outer"); if(!(ephem = malloc(sizeof(struct ephemeral_struct)))) return NULL; memset(ephem,0,sizeof (struct ephemeral_struct)); // create and copy in the exchange routing token e3x_hash(outer->body,16,hash); memcpy(ephem->token,hash,16); // generate a random seq starting point for channel IV's e3x_rand((uint8_t*)&(ephem->seq),4); // decompress the exchange key and get the shared secret uECC_decompress(outer->body,ekey); if(!uECC_shared_secret(ekey, remote->esecret, shared)) return LOG("ECDH failed"); // combine inputs to create the digest memcpy(shared+uECC_BYTES,remote->ecomp,uECC_BYTES+1); memcpy(shared+uECC_BYTES+uECC_BYTES+1,outer->body,uECC_BYTES+1); e3x_hash(shared,uECC_BYTES+((uECC_BYTES+1)*2),hash); fold1(hash,ephem->enckey); memcpy(shared+uECC_BYTES,outer->body,uECC_BYTES+1); memcpy(shared+uECC_BYTES+uECC_BYTES+1,remote->ecomp,uECC_BYTES+1); e3x_hash(shared,uECC_BYTES+((uECC_BYTES+1)*2),hash); fold1(hash,ephem->deckey); return ephem; }
// create a new open packet packet_t crypt_openize_1a(crypt_t self, crypt_t c, packet_t inner) { unsigned char secret[uECC_BYTES], iv[16], hash[32]; packet_t open; int inner_len; crypt_1a_t cs = (crypt_1a_t)c->cs, scs = (crypt_1a_t)self->cs; open = packet_chain(inner); packet_json(open,&(self->csid),1); inner_len = packet_len(inner); if(!packet_body(open,NULL,4+40+inner_len)) return NULL; // copy in the line public key memcpy(open->body+4, cs->line_public, 40); // get the shared secret to create the iv+key for the open aes if(!uECC_shared_secret(cs->id_public, cs->line_private, secret)) return packet_free(open); crypt_hash(secret,uECC_BYTES,hash); fold1(hash,hash); memset(iv,0,16); iv[15] = 1; // encrypt the inner aes_128_ctr(hash,inner_len,iv,packet_raw(inner),open->body+4+40); // generate secret for hmac if(!uECC_shared_secret(cs->id_public, scs->id_private, secret)) return packet_free(open); hmac_256(secret,uECC_BYTES,open->body+4,40+inner_len,hash); fold3(hash,open->body); return open; }
lob_t remote_encrypt(remote_t remote, local_t local, lob_t inner) { uint8_t shared[uECC_BYTES+4], iv[16], hash[32], csid = 0x1a; lob_t outer; size_t inner_len; outer = lob_new(); lob_head(outer,&csid,1); inner_len = lob_len(inner); if(!lob_body(outer,NULL,21+4+inner_len+4)) return lob_free(outer); // copy in the ephemeral public key memcpy(outer->body, remote->ecomp, uECC_BYTES+1); // get the shared secret to create the iv+key for the open aes if(!uECC_shared_secret(remote->key, remote->esecret, shared)) return lob_free(outer); e3x_hash(shared,uECC_BYTES,hash); fold1(hash,hash); memset(iv,0,16); memcpy(iv,&(remote->seq),4); remote->seq++; // increment seq after every use memcpy(outer->body+21,iv,4); // send along the used IV // encrypt the inner into the outer aes_128_ctr(hash,inner_len,iv,lob_raw(inner),outer->body+21+4); // generate secret for hmac if(!uECC_shared_secret(remote->key, local->secret, shared)) return lob_free(outer); memcpy(shared+uECC_BYTES,outer->body+21,4); // use the IV too hmac_256(shared,uECC_BYTES+4,outer->body,21+4+inner_len,hash); fold3(hash,outer->body+21+4+inner_len); // write into last 4 bytes return outer; }
lob_t local_decrypt(local_t local, lob_t outer) { uint8_t key[uECC_BYTES*2], shared[uECC_BYTES], iv[16], hash[32]; lob_t inner, tmp; // * `KEY` - 21 bytes, the sender's ephemeral exchange public key in compressed format // * `IV` - 4 bytes, a random but unique value determined by the sender // * `INNER` - (minimum 21+2 bytes) the AES-128-CTR encrypted inner packet ciphertext // * `HMAC` - 4 bytes, the calculated HMAC of all of the previous KEY+INNER bytes if(outer->body_len <= (21+4+0+4)) return NULL; tmp = lob_new(); if(!lob_body(tmp,NULL,outer->body_len-(4+21+4))) return lob_free(tmp); // get the shared secret to create the iv+key for the open aes uECC_decompress(outer->body,key); if(!uECC_shared_secret(key, local->secret, shared)) return lob_free(tmp); e3x_hash(shared,uECC_BYTES,hash); fold1(hash,hash); memset(iv,0,16); memcpy(iv,outer->body+21,4); // decrypt the inner aes_128_ctr(hash,tmp->body_len,iv,outer->body+4+21,tmp->body); // load inner packet inner = lob_parse(tmp->body,tmp->body_len); lob_free(tmp); return inner; }
packet_t crypt_deopenize_1a(crypt_t self, packet_t open) { unsigned char secret[uECC_BYTES], iv[16], b64[uECC_BYTES*2*2], hash[32]; packet_t inner, tmp; crypt_1a_t cs = (crypt_1a_t)self->cs; if(open->body_len <= (4+40)) return NULL; inner = packet_new(); if(!packet_body(inner,NULL,open->body_len-(4+40))) return packet_free(inner); // get the shared secret to create the iv+key for the open aes if(!uECC_shared_secret(open->body+4, cs->id_private, secret)) return packet_free(inner); crypt_hash(secret,uECC_BYTES,hash); fold1(hash,hash); memset(iv,0,16); iv[15] = 1; // decrypt the inner aes_128_ctr(hash,inner->body_len,iv,open->body+4+40,inner->body); // load inner packet if((tmp = packet_parse(inner->body,inner->body_len)) == NULL) return packet_free(inner); packet_free(inner); inner = tmp; // generate secret for hmac if(inner->body_len != uECC_BYTES*2) return packet_free(inner); if(!uECC_shared_secret(inner->body, cs->id_private, secret)) return packet_free(inner); // verify hmac_256(secret,uECC_BYTES,open->body+4,open->body_len-4,hash); fold3(hash,hash); if(memcmp(hash,open->body,4) != 0) return packet_free(inner); // stash the hex line key w/ the inner util_hex(open->body+4,40,b64); packet_set_str(inner,"ecc",(char*)b64); return inner; }