// encode packet static int packetEncode(unsigned char *pbuf, const int pbuf_size, const struct s_packet_data *data, struct s_crypto *ctx) { unsigned char dec_buf[packet_CRHDR_SIZE + data->pl_buf_size]; int32_t *scr_peerid = ((int32_t *)pbuf); int32_t ne_peerid; int len; // check if enough space is available for the operation if(data->pl_length > data->pl_buf_size) { return 0; } // prepare buffer utilWriteInt64(&dec_buf[packet_CRHDR_SEQ_START], data->seq); utilWriteInt16(&dec_buf[packet_CRHDR_PLLEN_START], data->pl_length); dec_buf[packet_CRHDR_PLTYPE_START] = data->pl_type; dec_buf[packet_CRHDR_PLOPT_START] = data->pl_options; memcpy(&dec_buf[packet_CRHDR_SIZE], data->pl_buf, data->pl_length); // encrypt buffer len = cryptoEnc(ctx, &pbuf[packet_PEERID_SIZE], (pbuf_size - packet_PEERID_SIZE), dec_buf, (packet_CRHDR_SIZE + data->pl_length), packet_HMAC_SIZE, packet_IV_SIZE); if(len < (packet_HMAC_SIZE + packet_IV_SIZE + packet_CRHDR_SIZE)) { return 0; } // write the scrambled peer ID utilWriteInt32((unsigned char *)&ne_peerid, data->peerid); scr_peerid[0] = (ne_peerid ^ (scr_peerid[1] ^ scr_peerid[2])); // return length of encoded packet return (packet_PEERID_SIZE + len); }
// Generate auth message S3 static void authGenS3(struct s_auth_state *authstate) { // generate msg(remote_authid, msgnum, enc(keygen_nonce, local_seq, local_peerid, local_flags)) unsigned char unencrypted_nextmsg[auth_MAXMSGSIZE_S3]; int unencrypted_nextmsg_size = (4 + 2 + auth_NONCESIZE + seq_SIZE + 4 + 8); int msgnum = authstate->state; int encsize; if(authstate->local_cneg_set) { memcpy(unencrypted_nextmsg, authstate->remote_authid, 4); utilWriteInt16(&unencrypted_nextmsg[4], msgnum); memcpy(authstate->nextmsg, unencrypted_nextmsg, 6); memcpy(&unencrypted_nextmsg[(4 + 2)], authstate->local_keygen_nonce, auth_NONCESIZE); memcpy(&unencrypted_nextmsg[(4 + 2 + auth_NONCESIZE)], authstate->local_seq, seq_SIZE); utilWriteInt32(&unencrypted_nextmsg[(4 + 2 + auth_NONCESIZE + seq_SIZE)], authstate->local_peerid); memcpy(&unencrypted_nextmsg[(4 + 2 + auth_NONCESIZE + seq_SIZE + 4)], authstate->local_flags, 8); encsize = cryptoEnc(&authstate->crypto_ctx[auth_CRYPTOCTX_CNEG], &authstate->nextmsg[(4 + 2)], (auth_MAXMSGSIZE - 2 - 4), &unencrypted_nextmsg[(4 + 2)], (unencrypted_nextmsg_size - 2 - 4), auth_CNEGHMACSIZE, auth_CNEGIVSIZE); if(encsize > 0) { authstate->nextmsg_size = (encsize + 4 + 2); } else { authstate->nextmsg_size = 0; } } else { authstate->nextmsg_size = 0; } }
// Generate auth message S2 static void authGenS2(struct s_auth_state *authstate) { // generate msg(remote_authid, msgnum, enc(pubkey_len, pubkey, sig_len, sig(authid, msgnum, local_nonce, remote_nonce, remote_dhkey, local_dhkey), hmac(pubkey))) unsigned char unencrypted_nextmsg[auth_MAXMSGSIZE_S2]; int unencrypted_nextmsg_size; int msgnum = authstate->state; unsigned char siginbuf[auth_SIGINBUFSIZE]; struct s_nodekey *local_nodekey; struct s_rsa *rsakey; int siginbuf_size; int nksize; int signsize; int encsize; memcpy(unencrypted_nextmsg, authstate->remote_authid, 4); utilWriteInt16(&unencrypted_nextmsg[4], msgnum); memcpy(authstate->nextmsg, unencrypted_nextmsg, 6); siginbuf_size = authGenSigIn(authstate, siginbuf, &unencrypted_nextmsg[4]); local_nodekey = authstate->local_nodekey; nksize = nodekeyGetDER(&unencrypted_nextmsg[(4 + 2 + 2)], nodekey_MAXSIZE, local_nodekey); if(nksize > nodekey_MINSIZE) { utilWriteInt16(&unencrypted_nextmsg[(4 + 2)], nksize); rsakey = &local_nodekey->key; signsize = rsaSign(rsakey, &unencrypted_nextmsg[(4 + 2 + 2 + nksize + 2)], nodekey_MAXSIZE, siginbuf, siginbuf_size); if(signsize > 0) { utilWriteInt16(&unencrypted_nextmsg[(4 + 2 + 2 + nksize)], signsize); if(cryptoHMAC(&authstate->crypto_ctx[auth_CRYPTOCTX_AUTH], &unencrypted_nextmsg[(4 + 2 + 2 + nksize + 2 + signsize)], auth_HMACSIZE, &unencrypted_nextmsg[(4 + 2 + 2)], nksize)) { unencrypted_nextmsg_size = (4 + 2 + 2 + nksize + 2 + signsize + auth_HMACSIZE); encsize = cryptoEnc(&authstate->crypto_ctx[auth_CRYPTOCTX_IDP], &authstate->nextmsg[(4 + 2)], (auth_MAXMSGSIZE - 2 - 4), &unencrypted_nextmsg[(2 + 4)], (unencrypted_nextmsg_size - 2 - 4), auth_IDPHMACSIZE, auth_IDPIVSIZE); if(encsize > 0) { authstate->nextmsg_size = (encsize + 4 + 2); } else { authstate->nextmsg_size = 0; } } else { authstate->nextmsg_size = 0; } } else { authstate->nextmsg_size = 0; } } else { authstate->nextmsg_size = 0; } }
// Generate auth message S4 static void authGenS4(struct s_auth_state *authstate) { // generate msg(remote_authid, msgnum, nonce, hmac_nonce) int msgnum = authstate->state; memcpy(authstate->nextmsg, authstate->remote_authid, 4); utilWriteInt16(&authstate->nextmsg[4], msgnum); memcpy(&authstate->nextmsg[6], authstate->s4msg_nonce, auth_NONCESIZE); if(cryptoHMAC(&authstate->crypto_ctx[auth_CRYPTOCTX_CNEG], &authstate->nextmsg[(6 + auth_NONCESIZE)], auth_CNEGHMACSIZE, authstate->s4msg_nonce, auth_NONCESIZE)) { authstate->nextmsg_size = (6 + auth_NONCESIZE + auth_CNEGHMACSIZE); } else { authstate->nextmsg_size = 0; } }
// Generate auth message S1 static void authGenS1(struct s_auth_state *authstate) { // generate msg(remote_authid, msgnum, checksum, sesstoken, nonce, dhkey_len, dhkey) int msgnum = authstate->state; int dhsize; memcpy(authstate->nextmsg, authstate->remote_authid, 4); utilWriteInt16(&authstate->nextmsg[4], msgnum); memcpy(&authstate->nextmsg[(4 + 2 + 8)], &authstate->remote_sesstoken, 4); memcpy(&authstate->nextmsg[(4 + 2 + 8 + 4)], authstate->local_nonce, auth_NONCESIZE); dhsize = dhGetPubkey(&authstate->nextmsg[(4 + 2 + 8 + 4 + auth_NONCESIZE + 2)], dh_MAXSIZE, authstate->dhstate); if(dhsize > dh_MINSIZE) { utilWriteInt16(&authstate->nextmsg[(4 + 2 + 8 + 4 + auth_NONCESIZE)], dhsize); if(cryptoCalculateSHA256(&authstate->nextmsg[(4 + 2)], 8, &authstate->nextmsg[(4 + 2 + 8)], (4 + auth_NONCESIZE + 2 + dhsize))) { authstate->nextmsg_size = (4 + 2 + 8 + 4 + auth_NONCESIZE + 2 + dhsize); } else { authstate->nextmsg_size = 0; } } else { authstate->nextmsg_size = 0; } }
// Generate auth message S0 static void authGenS0(struct s_auth_state *authstate) { // generate msg(remote_authid, msgnum, checksum, authid, sesstoken, netid) int msgnum = authstate->state; memcpy(authstate->nextmsg, authstate->remote_authid, 4); utilWriteInt16(&authstate->nextmsg[4], msgnum); memcpy(&authstate->nextmsg[(4 + 2 + 8)], &authstate->local_authid, 4); memcpy(&authstate->nextmsg[(4 + 2 + 8 + 4)], &authstate->local_sesstoken, 4); memcpy(&authstate->nextmsg[(4 + 2 + 8 + 4 + 4)], authstate->netid->id, netid_SIZE); if(cryptoCalculateSHA256(&authstate->nextmsg[(4 + 2)], 8, &authstate->nextmsg[(4 + 2 + 8)], (4 + 4 + netid_SIZE))) { authstate->nextmsg_size = (4 + 2 + 8 + 4 + 4 + netid_SIZE); } else { authstate->nextmsg_size = 0; } }
// Generate peer manager status report. static void peermgtStatus(struct s_peermgt *mgt, char *report, const int report_len) { int tnow = utilGetTime(); int pos = 0; int size = mapGetMapSize(&mgt->map); int maxpos = (((size + 2) * (160)) + 1); unsigned char infoid[packet_PEERID_SIZE]; unsigned char infostate[1]; unsigned char infoflags[2]; unsigned char inforq[1]; unsigned char timediff[4]; struct s_nodeid nodeid; int i = 0; if(maxpos > report_len) { maxpos = report_len; } memcpy(&report[pos], "PeerID NodeID Address Status LastPkt SessAge Flag RQ", 158); pos = pos + 158; report[pos++] = '\n'; while(i < size && pos < maxpos) { if(peermgtGetNodeID(mgt, &nodeid, i)) { utilWriteInt32(infoid, i); utilByteArrayToHexstring(&report[pos], ((packet_PEERID_SIZE * 2) + 2), infoid, packet_PEERID_SIZE); pos = pos + (packet_PEERID_SIZE * 2); report[pos++] = ' '; report[pos++] = ' '; utilByteArrayToHexstring(&report[pos], ((nodeid_SIZE * 2) + 2), nodeid.id, nodeid_SIZE); pos = pos + (nodeid_SIZE * 2); report[pos++] = ' '; report[pos++] = ' '; utilByteArrayToHexstring(&report[pos], ((peeraddr_SIZE * 2) + 2), mgt->data[i].remoteaddr.addr, peeraddr_SIZE); pos = pos + (peeraddr_SIZE * 2); report[pos++] = ' '; report[pos++] = ' '; infostate[0] = mgt->data[i].state; utilByteArrayToHexstring(&report[pos], 4, infostate, 1); pos = pos + 2; report[pos++] = ' '; report[pos++] = ' '; utilWriteInt32(timediff, (tnow - mgt->data[i].lastrecv)); utilByteArrayToHexstring(&report[pos], 10, timediff, 4); pos = pos + 8; report[pos++] = ' '; report[pos++] = ' '; utilWriteInt32(timediff, (tnow - mgt->data[i].conntime)); utilByteArrayToHexstring(&report[pos], 10, timediff, 4); pos = pos + 8; report[pos++] = ' '; report[pos++] = ' '; utilWriteInt16(infoflags, mgt->data[i].remoteflags); utilByteArrayToHexstring(&report[pos], 6, infoflags, 2); pos = pos + 4; report[pos++] = ' '; report[pos++] = ' '; inforq[0] = seqRQ(&mgt->data[i].seq); utilByteArrayToHexstring(&report[pos], 4, inforq, 1); pos = pos + 2; report[pos++] = '\n'; } i++; } report[pos++] = '\0'; }
// generate keys static int cryptoSetKeys(struct s_crypto *ctxs, const int count, const unsigned char *secret_buf, const int secret_len, const unsigned char *nonce_buf, const int nonce_len) { int cur_key_len; unsigned char cur_key[EVP_MAX_MD_SIZE]; int seed_key_len; unsigned char seed_key[EVP_MAX_MD_SIZE]; const EVP_MD *keygen_md = EVP_sha512(); const EVP_MD *out_md = EVP_sha256(); const EVP_CIPHER *out_cipher = EVP_aes_256_cbc(); const int key_size = EVP_CIPHER_key_length(out_cipher); HMAC_CTX hmac_ctx; int16_t i; unsigned char in[2]; int j,k; // setup hmac as the pseudorandom function HMAC_CTX_init(&hmac_ctx); // calculate seed key HMAC_Init_ex(&hmac_ctx, nonce_buf, nonce_len, keygen_md, NULL); HMAC_Update(&hmac_ctx, secret_buf, secret_len); HMAC_Final(&hmac_ctx, seed_key, (unsigned int *)&seed_key_len); // calculate derived keys HMAC_Init_ex(&hmac_ctx, seed_key, seed_key_len, keygen_md, NULL); HMAC_Update(&hmac_ctx, nonce_buf, nonce_len); HMAC_Final(&hmac_ctx, cur_key, (unsigned int *)&cur_key_len); i = 0; j = 0; k = 0; while(k < count) { // calculate next key utilWriteInt16(in, i); HMAC_Init_ex(&hmac_ctx, NULL, -1, NULL, NULL); HMAC_Update(&hmac_ctx, cur_key, cur_key_len); HMAC_Update(&hmac_ctx, nonce_buf, nonce_len); HMAC_Update(&hmac_ctx, in, 2); HMAC_Final(&hmac_ctx, cur_key, (unsigned int *)&cur_key_len); if(cur_key_len < key_size) return 0; // check if key is long enough switch(j) { case 1: // save this key as the decryption and encryption key if(!EVP_EncryptInit_ex(&ctxs[k].enc_ctx, out_cipher, NULL, cur_key, NULL)) return 0; if(!EVP_DecryptInit_ex(&ctxs[k].dec_ctx, out_cipher, NULL, cur_key, NULL)) return 0; break; case 2: // save this key as the hmac key HMAC_Init_ex(&ctxs[k].hmac_ctx, cur_key, cur_key_len, out_md, NULL); break; default: // throw this key away break; } if(j > 3) { j = 0; k++; } j++; i++; } // clean up HMAC_CTX_cleanup(&hmac_ctx); return 1; }