示例#1
0
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;
}
示例#2
0
lob_t ephemeral_encrypt(ephemeral_t ephem, lob_t inner)
{
  lob_t outer;
  uint8_t iv[16], hmac[32];
  size_t inner_len;

  outer = lob_new();
  inner_len = lob_len(inner);
  if(!lob_body(outer,NULL,16+4+inner_len+4)) return lob_free(outer);

  // copy in token and create/copy iv
  memcpy(outer->body,ephem->token,16);
  memset(iv,0,16);
  memcpy(iv,&(ephem->seq),4);
  ephem->seq++;
  memcpy(outer->body+16,iv,4);

  // encrypt full inner into the outer
  aes_128_ctr(ephem->enckey,inner_len,iv,lob_raw(inner),outer->body+16+4);

  // generate mac key and mac the ciphertext
  memcpy(hmac,ephem->enckey,16);
  memcpy(hmac+16,iv,4);
  hmac_256(hmac,16+4,outer->body+16+4,inner_len,hmac);
  fold3(hmac,outer->body+16+4+inner_len);

  return outer;
}
示例#3
0
lob_t remote_encrypt(remote_t remote, local_t local, lob_t inner)
{
  uint8_t secret[crypto_box_BEFORENMBYTES], nonce[24], shared[24+crypto_box_BEFORENMBYTES], hash[32], csid = 0x3a;
  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,32+24+inner_len+crypto_secretbox_MACBYTES+16)) return lob_free(outer);

  // copy in the ephemeral public key/nonce
  memcpy(outer->body, remote->ekey, 32);
  randombytes(nonce,24);
  memcpy(outer->body+32, nonce, 24);

  // get the shared secret to create the nonce+key for the open aes
  crypto_box_beforenm(secret, remote->key, remote->esecret);

  // encrypt the inner
  if(crypto_secretbox_easy(outer->body+32+24,
    lob_raw(inner),
    inner_len,
    nonce,
    secret) != 0) return lob_free(outer);

  // generate secret for hmac
  crypto_box_beforenm(secret, remote->key, local->secret);
  memcpy(shared,nonce,24);
  memcpy(shared+24,secret,crypto_box_BEFORENMBYTES);
  e3x_hash(shared,24+crypto_box_BEFORENMBYTES,hash);
  crypto_onetimeauth(outer->body+32+24+inner_len+crypto_secretbox_MACBYTES, outer->body, outer->body_len-16, hash);

  return outer;
}
示例#4
0
lob_t link_handshakes(link_t link)
{
  uint32_t i;
  uint8_t csid;
  char *key;
  lob_t tmp, hs = NULL, handshakes = NULL;
  if(!link) return NULL;
  
  // no keys means we have to generate a handshake for each key
  if(!link->x)
  {
    for(i=0;(key = lob_get_index(link->mesh->keys,i));i+=2)
    {
      util_unhex(key,2,&csid);
      hs = lob_new();
      tmp = hashname_im(link->mesh->keys, csid);
      lob_body(hs, lob_raw(tmp), lob_len(tmp));
      lob_free(tmp);
      handshakes = lob_link(hs, handshakes);
    }
  }else{ // generate one just for this csid
    handshakes = lob_new();
    tmp = hashname_im(link->mesh->keys, link->csid);
    lob_body(handshakes, lob_raw(tmp), lob_len(tmp));
    lob_free(tmp);
  }

  // add any custom per-link
  for(hs = link->handshakes; hs; hs = lob_linked(hs)) handshakes = lob_link(lob_copy(hs), handshakes);

  // add any mesh-wide handshakes
  for(hs = link->mesh->handshakes; hs; hs = lob_linked(hs)) handshakes = lob_link(lob_copy(hs), handshakes);
  
  // encrypt them if we can
  if(link->x)
  {
    tmp = handshakes;
    handshakes = NULL;
    for(hs = tmp; hs; hs = lob_linked(hs)) handshakes = lob_link(e3x_exchange_handshake(link->x, hs), handshakes);
    lob_free(tmp);
  }

  return handshakes;
}
示例#5
0
util_frames_t util_frames_outbox(util_frames_t frames, uint8_t *data, uint8_t *meta)
{
  if(!frames) return LOG("bad args");
  if(frames->err) return LOG("frame state error");
  if(!data) return util_frames_ready(frames); // just a ready check
  uint8_t size = PAYLOAD(frames);
  uint8_t *out = lob_raw(frames->outbox);
  uint32_t len = lob_len(frames->outbox); 
  
  // clear/init
  uint32_t hash = frames->outbase;
  
  // first get the last sent hash
  if(len)
  {
    // safely only hash the packet size correctly
    uint32_t at, i;
    for(i = at = 0;at < len && i < frames->out;i++,at += size)
    {
      hash ^= murmur4((out+at), ((at - len) < size) ? (at - len) : size);
      hash += i;
    }
  }

  // if flushing, or nothing to send, just send meta frame w/ hashes
  if(frames->flush || !len || (frames->out * size) > len)
  {
    memset(data,0,size+4);
    memcpy(data,&(frames->inlast),4);
    memcpy(data+4,&(hash),4);
    if(meta) memcpy(data+10,meta,size-10);
    murmur(data,size,data+size);
//    LOG("sending meta frame inlast %lu cur %lu",frames->inlast,hash);
    return frames;
  }
  
  // send next frame
  memset(data,0,size+4);
  uint32_t at = frames->out * size;
  if((at + size) > len)
  {
    size = len - at;
    data[PAYLOAD(frames)-1] = size;
  }
  memcpy(data,out+at,size);
  hash ^= murmur4(data,size);
  hash += frames->out;
  memcpy(data+PAYLOAD(frames),&(hash),4);
  LOG("sending data frame %u %lu",frames->out,hash);

  return frames;
}
示例#6
0
lob_t link_handshake(link_t link)
{
  if(!link) return NULL;
  if(!link->x) return LOG_DEBUG("no exchange");

  LOG_DEBUG("generating a new handshake in %lu out %lu",link->x->in,link->x->out);
  lob_t handshake = lob_copy(link->mesh->handshake);
  lob_t tmp = hashname_im(link->mesh->keys, link->csid);
  lob_body(handshake, lob_raw(tmp), lob_len(tmp));
  lob_free(tmp);

  // encrypt it
  tmp = handshake;
  handshake = e3x_exchange_handshake(link->x, tmp);
  lob_free(tmp);

  return handshake;
}
示例#7
0
lob_t ephemeral_encrypt(ephemeral_t ephem, lob_t inner)
{
  lob_t outer;
  size_t inner_len;

  outer = lob_new();
  inner_len = lob_len(inner);
  if(!lob_body(outer,NULL,16+24+inner_len+crypto_secretbox_MACBYTES)) return lob_free(outer);

  // copy in token and create nonce
  memcpy(outer->body,ephem->token,16);
  randombytes(outer->body+16,24);

  crypto_secretbox_easy(outer->body+16+24,
    lob_raw(inner),
    lob_len(inner),
    outer->body+16,
    ephem->enckey);

  return outer;

}
示例#8
0
// chunk the packet out
void thtp_send(chan_t c, lob_t req)
{
  lob_t chunk;
  unsigned char *raw;
  unsigned short len, space;
  if(!c || !req) return;
  DEBUG_PRINTF("THTP sending %.*s %.*s",req->json_len,req->json,req->body_len,req->body);
  raw = lob_raw(req);
  len = lob_len(req);
  while(len)
  {
    chunk = chan_packet(c);
    if(!chunk) return; // TODO backpressure
    space = lob_space(chunk);
    if(space > len) space = len;
    lob_body(chunk,raw,space);
    if(len==space) lob_set(chunk,"end","true",4);
    chan_send(c,chunk);
    raw+=space;
    len-=space;
  }
}
示例#9
0
// turn this packet into chunks
util_chunks_t util_chunks_send(util_chunks_t chunks, lob_t out)
{
  uint32_t start, at;
  size_t len;
  uint8_t *raw, size, rounds = 1; // TODO random rounds?
  
  // validate and gc first
  if(!_util_chunks_gc(chunks) || !(len = lob_len(out))) return chunks;
  if(chunks->cloak) len += (8*rounds);

  start = chunks->writelen;
  chunks->writelen += len;
  chunks->writelen += CEIL(len,chunks->space); // include space for per-chunk start byte
  chunks->writelen++; // space for terminating 0
  if(!(chunks->writing = util_reallocf(chunks->writing, chunks->writelen)))
  {
    chunks->writelen = chunks->writeat = 0;
    return LOG("OOM");
  }
  
  raw = lob_raw(out);
  if(chunks->cloak) raw = lob_cloak(out, rounds);
  
  for(at = 0; at < len;)
  {
    size = ((len-at) < chunks->space) ? (uint8_t)(len-at) : chunks->space;
    chunks->writing[start] = size;
    start++;
    memcpy(chunks->writing+start,raw+at,size);
    at += size;
    start += size;
  }
  chunks->writing[start] = 0; // end of chunks, full packet
  
  if(chunks->cloak) free(raw);
  
  return chunks;
}
示例#10
0
// the next frame of data in/out, if data NULL bool is just ready check
util_frames_t util_frames_inbox(util_frames_t frames, uint8_t *data, uint8_t *meta)
{
  if(!frames) return LOG("bad args");
  if(frames->err) return LOG("frame state error");
  if(!data) return util_frames_await(frames);
  
  // conveniences for code readability
  uint8_t size = PAYLOAD(frames);
  uint32_t hash1;
  memcpy(&(hash1),data+size,4);
  uint32_t hash2 = murmur4(data,size);
  
//  LOG("frame sz %u hash rx %lu check %lu",size,hash1,hash2);
  
  // meta frames are self contained
  if(hash1 == hash2)
  {
//    LOG("meta frame %s",util_hex(data,size+4,NULL));

    // if requested, copy in metadata block
    if(meta) memcpy(meta,data+10,size-10);

    // verify sender's last rx'd hash
    uint32_t rxd;
    memcpy(&rxd,data,4);
    uint8_t *bin = lob_raw(frames->outbox);
    uint32_t len = lob_len(frames->outbox);
    uint32_t rxs = frames->outbase;
    uint8_t i;
    for(i = 0;i <= frames->out;i++)
    {
      // verify/reset to last rx'd frame
      if(rxd == rxs)
      {
        frames->out = i;
        break;
      }

      // handle tail hash correctly like sender
      uint32_t at = i * size;
      rxs ^= murmur4((bin+at), ((at+size) > len) ? (len - at) : size);
      rxs += i;
    }
    if(rxd != rxs)
    {
      LOG("invalid received frame hash %lu check %lu",rxd,rxs);
      frames->err = 1;
      return NULL;
    }
    
    // advance full packet once confirmed
    if((frames->out * size) > len)
    {
      frames->out = 0;
      frames->outbase = rxd;
      lob_t done = lob_shift(frames->outbox);
      frames->outbox = done->next;
      done->next = NULL;
      lob_free(done);
    }

    // sender's last tx'd hash changes flush state
    if(memcmp(data+4,&(frames->inlast),4) == 0)
    {
      frames->flush = 0;
    }else{
      frames->flush = 1;
      LOG("flushing mismatch, last %lu",frames->inlast);
    }
    
    return frames;
  }
  
  // dedup, if identical to last received one
  if(hash1 == frames->inlast) return frames;

  // full data frames must match combined w/ previous
  hash2 ^= frames->inlast;
  hash2 += frames->in;
  if(hash1 == hash2)
  {
    if(!util_frame_new(frames)) return LOG("OOM");
    // append, update inlast, continue
    memcpy(frames->cache->data,data,size);
    frames->flush = 0;
    frames->inlast = hash1;
//    LOG("got data frame %lu",hash1);
    return frames;
  }
  
  // check if it's a tail data frame
  uint8_t tail = data[size-1];
  if(tail >= size)
  {
    frames->flush = 1;
    return LOG("invalid frame data length: %u %s",tail,util_hex(data+(size-4),8,NULL));
  }
  
  // hash must match
  hash2 = murmur4(data,tail);
  hash2 ^= frames->inlast;
  hash2 += frames->in;
  if(hash1 != hash2)
  {
    frames->flush = 1;
    return LOG("invalid frame %u tail (%u) hash %lu != %lu last %lu",frames->in,tail,hash1,hash2,frames->inlast);
  }
  
  // process full packet w/ tail, update inlast, set flush
//  LOG("got frame tail of %u",tail);
  frames->flush = 1;
  frames->inlast = hash1;
  
  size_t tlen = (frames->in * size) + tail;

  // TODO make a lob_new that creates space to prevent double-copy here
  uint8_t *buf = malloc(tlen);
  if(!buf) return LOG("OOM");
  
  // copy in tail
  memcpy(buf+(frames->in * size), data, tail);
  
  // eat cached frames copying in reverse
  util_frame_t frame = frames->cache;
  while(frames->in && frame)
  {
    frames->in--;
    memcpy(buf+(frames->in*size),frame->data,size);
    frame = frame->prev;
  }
  frames->cache = util_frame_free(frames->cache);
  
  lob_t packet = lob_parse(buf,tlen);
  if(!packet) LOG("packet parsing failed: %s",util_hex(buf,tlen,NULL));
  free(buf);
  frames->inbox = lob_push(frames->inbox,packet);
  return frames;
}