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 main(int argc, char **argv) { char *eout = malloc(base64_encode_length(7)); uint8_t *dout = malloc(base64_decode_length(8)); size_t len; len = base64_encoder((const uint8_t *)"foobar", 6, eout); fail_unless(len == 8); fail_unless(strcmp(eout,"Zm9vYmFy") == 0); len = base64_decoder(eout,0,dout); fail_unless(len == 6); fail_unless(strncmp((char*)dout,"foobar",6) == 0); char bfix[] = "eyJzdWIiOjEyMzQ1Njc4OTAsIm5hbWUiOiJKb2huIERvZSIsImFkbWluIjp0cnVlfQ"; char jfix[] = "{\"sub\":1234567890,\"name\":\"John Doe\",\"admin\":true}"; char *jtest = malloc(base64_decode_length(strlen(bfix))); len = base64_decoder(bfix,0,(uint8_t*)jtest); fail_unless(len == strlen(jfix)); fail_unless(strcmp(jtest,jfix) == 0); char *btest = malloc(base64_encode_length(strlen(jfix))); len = base64_encoder((uint8_t*)jfix,strlen(jfix),btest); // printf("len %d %d %s",len,strlen(bfix),btest); fail_unless(len == strlen(bfix)); fail_unless(strncmp(btest,bfix,len) == 0); e3x_init(NULL); // random seed uint8_t *rand = malloc(32); char *rtest = malloc(base64_encode_length(32)); uint8_t *rand2 = malloc(32); char *rtest2 = malloc(base64_encode_length(32)); int i; for(i = 1;i<=32;i++) { e3x_rand(rand, i); e3x_rand(rand2, i); base64_encoder(rand,i,rtest); base64_decoder(rtest,0,rand2); base64_encoder(rand2,i,rtest2); // printf("%s\n%s\n",rtest,rtest2); fail_unless(memcmp(rand,rand2,i) == 0); } return 0; }
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; }
static int RNG(uint8_t *p_dest, unsigned p_size) { e3x_rand(p_dest,p_size); return 1; }
int main(int argc, char **argv) { lob_t id; mesh_t mesh; lob_t opts = lob_new(); fail_unless(e3x_init(opts) == 0); fail_unless(!e3x_err()); // need cs1a support to continue testing e3x_cipher_t cs = e3x_cipher_set(0x1a,NULL); if(!cs) return 0; cs = e3x_cipher_set(0,"1a"); fail_unless(cs); fail_unless(cs->id == CS_1a); uint8_t buf[32]; fail_unless(e3x_rand(buf,32)); char hex[65]; util_hex(e3x_hash((uint8_t*)"foo",3,buf),32,hex); fail_unless(strcmp(hex,"2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae") == 0); id = util_fjson("/Users/chrigel/.id.json"); if(!id) return -1; lob_t secrets = lob_get_json(id,"secrets"); fail_unless(secrets); fail_unless(lob_get(secrets,"1a")); lob_t keys = lob_get_json(id,"keys"); fail_unless(keys); fail_unless(lob_get(keys,"1a")); LOG("generated key %s secret %s",lob_get(keys,"1a"),lob_get(secrets,"1a")); local_t localA = cs->local_new(keys,secrets); fail_unless(localA); remote_t remoteA = cs->remote_new(lob_get_base32(keys,"1a"), NULL); fail_unless(remoteA); // create another to start testing real packets lob_t secretsB = e3x_generate(); fail_unless(lob_linked(secretsB)); printf("XX %s\n",lob_json(lob_linked(secretsB))); local_t localB = cs->local_new(lob_linked(secretsB),secretsB); fail_unless(localB); remote_t remoteB = cs->remote_new(lob_get_base32(lob_linked(secretsB),"1a"), NULL); fail_unless(remoteB); // generate a message lob_t messageAB = lob_new(); lob_set_int(messageAB,"a",42); lob_t outerAB = cs->remote_encrypt(remoteB,localA,messageAB); fail_unless(outerAB); fail_unless(lob_len(outerAB) == 42); // decrypt and verify it lob_t innerAB = cs->local_decrypt(localB,outerAB); fail_unless(innerAB); fail_unless(lob_get_int(innerAB,"a") == 42); fail_unless(cs->remote_verify(remoteA,localB,outerAB) == 0); ephemeral_t ephemBA = cs->ephemeral_new(remoteA,outerAB); fail_unless(ephemBA); lob_t channelBA = lob_new(); lob_set(channelBA,"type","foo"); lob_t couterBA = cs->ephemeral_encrypt(ephemBA,channelBA); fail_unless(couterBA); fail_unless(lob_len(couterBA) == 42); lob_t outerBA = cs->remote_encrypt(remoteA,localB,messageAB); fail_unless(outerBA); ephemeral_t ephemAB = cs->ephemeral_new(remoteB,outerBA); fail_unless(ephemAB); lob_t cinnerAB = cs->ephemeral_decrypt(ephemAB,couterBA); fail_unless(cinnerAB); fail_unless(util_cmp(lob_get(cinnerAB,"type"),"foo") == 0); return 0; }