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; }
local_t local_new(lob_t keys, lob_t secrets) { local_t local = NULL; lob_t key, secret; if(!keys) keys = lob_linked(secrets); // for convenience key = lob_get_base32(keys,"1c"); if(!key) return LOG("invalid key"); secret = lob_get_base32(secrets,"1c"); if(!secret) return LOG("invalid secret"); if(key->body_len == COMP_BYTES && secret->body_len == SECRET_BYTES) { if((local = malloc(sizeof(struct local_struct)))) { memset(local,0,sizeof (struct local_struct)); // copy in key/secret data uECC_decompress(key->body,local->key, curve); memcpy(local->secret,secret->body,secret->body_len); }else{ LOG("OOM"); } }else{ LOG("invalid sizes key %d=%d secret %d=%d",key->body_len,COMP_BYTES,secret->body_len,SECRET_BYTES); } lob_free(key); lob_free(secret); return local; }
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; }
int joylink_encrypt_sub_dev_data( uint8_t* pBuf, int buflen, E_EncType enctype, uint8_t* key, const uint8_t* payload, int length) { char* psJson = (char*)payload; uint8_t* pOut = pBuf; int retlen; uint8_t peerPubKey[uECC_BYTES * 2] = {0}; uint8_t secret[uECC_BYTES] = {0}; switch (enctype) { case ET_NOTHING: break; case ET_PSKAES: break; case ET_ACCESSKEYAES: retlen = device_aes_encrypt( key, 16, key+16, (uint8_t*)psJson, length, pOut, length + 16); break; case ET_ECDH: memcpy(pOut, __g_ekey.devPubKeyC, uECC_BYTES + 1); pOut += (uECC_BYTES + 1); uECC_decompress(key, peerPubKey); uECC_shared_secret( peerPubKey, __g_ekey.priKey, secret); retlen = device_aes_encrypt( secret, 16, key + 4, (const uint8_t*)psJson, length, pOut, length + 16); break; default: break; } return retlen; }
local_t local_new(lob_t keys, lob_t secrets) { local_t local; lob_t key, secret; if(!keys) keys = lob_linked(secrets); // for convenience key = lob_get_base32(keys,"1a"); if(!key || key->body_len != uECC_BYTES+1) return LOG("invalid key %d != %d",(key)?key->body_len:0,uECC_BYTES+1); secret = lob_get_base32(secrets,"1a"); if(!secret || secret->body_len != uECC_BYTES) return LOG("invalid secret len %d",(secret)?secret->body_len:0); if(!(local = malloc(sizeof(struct local_struct)))) return NULL; memset(local,0,sizeof (struct local_struct)); // copy in key/secret data uECC_decompress(key->body,local->key); memcpy(local->secret,secret->body,secret->body_len); lob_free(key); lob_free(secret); return local; }
remote_t remote_new(lob_t key, uint8_t *token) { uint8_t hash[32]; remote_t remote; if(!key || key->body_len != uECC_BYTES+1) return LOG("invalid key %d != %d",(key)?key->body_len:0,uECC_BYTES+1); if(!(remote = malloc(sizeof(struct remote_struct)))) return NULL; memset(remote,0,sizeof (struct remote_struct)); // copy in key and make ephemeral ones uECC_decompress(key->body,remote->key); uECC_make_key(remote->ekey, remote->esecret); uECC_compress(remote->ekey, remote->ecomp); if(token) { cipher_hash(remote->ecomp,16,hash); memcpy(token,hash,16); } // generate a random seq starting point for message IV's e3x_rand((uint8_t*)&(remote->seq),4); return remote; }