// Receive a SIGnature record, verify it, if it passed, compute the shared secret and calculate the session keys. static bool receive_sig(sptps_t *s, const char *data, uint16_t len) { size_t keylen = ECDH_SIZE; size_t siglen = ecdsa_size(s->hiskey); // Verify length of KEX record. if(len != siglen) return error(s, EIO, "Invalid KEX record length"); // Concatenate both KEX messages, plus tag indicating if it is from the connection originator char msg[(1 + 32 + keylen) * 2 + 1 + s->labellen]; msg[0] = !s->initiator; memcpy(msg + 1, s->hiskex, 1 + 32 + keylen); memcpy(msg + 1 + 33 + keylen, s->mykex, 1 + 32 + keylen); memcpy(msg + 1 + 2 * (33 + keylen), s->label, s->labellen); // Verify signature. if(!ecdsa_verify(s->hiskey, msg, sizeof msg, data)) return error(s, EIO, "Failed to verify SIG record"); // Compute shared secret. char shared[ECDH_SHARED_SIZE]; if(!ecdh_compute_shared(s->ecdh, s->hiskex + 1 + 32, shared)) return error(s, EINVAL, "Failed to compute ECDH shared secret"); s->ecdh = NULL; // Generate key material from shared secret. if(!generate_key_material(s, shared, sizeof shared)) return false; free(s->mykex); free(s->hiskex); s->mykex = NULL; s->hiskex = NULL; // Send cipher change record if(s->outstate && !send_ack(s)) return false; // TODO: only set new keys after ACK has been set/received if(s->initiator) { if(!chacha_poly1305_set_key(s->outcipher, s->key + CHACHA_POLY1305_KEYLEN)) return error(s, EINVAL, "Failed to set key"); } else { if(!chacha_poly1305_set_key(s->outcipher, s->key)) return error(s, EINVAL, "Failed to set key"); } return true; }
// Receive an ACKnowledgement record. static bool receive_ack(sptps_t *s, const char *data, uint16_t len) { if(len) return error(s, EIO, "Invalid ACK record length"); if(s->initiator) { if(!chacha_poly1305_set_key(s->incipher, s->key)) return error(s, EINVAL, "Failed to set counter"); } else { if(!chacha_poly1305_set_key(s->incipher, s->key + CHACHA_POLY1305_KEYLEN)) return error(s, EINVAL, "Failed to set counter"); } free(s->key); s->key = NULL; s->instate = true; return true; }
// Encrypts plaintext ptxt, stores as ciphertext ctxt void encrypt_phrase(dheluks_ctx_t *ctx, dheluks_pkg_t *pkg, dheluks_kys_t *skr, dheluks_txt_t *txt) { chacha_poly1305_set_key(&ctx->ciph, skr->sharekey); //set key gen_random(&ctx->rand, NONCE_SIZE, pkg->nonce); //generate nonce chacha_poly1305_set_nonce(&ctx->ciph, pkg->nonce); //set nonce chacha_poly1305_encrypt(&ctx->ciph, pkg->csize, pkg->cphtxt, txt->plntxt); //encrypt chacha_poly1305_digest(&ctx->ciph, DIGEST_SIZE, pkg->digest); }
// Decrypts ctxt, stores as an encoded uint8 int decrypt_phrase(dheluks_ctx_t *ctx, dheluks_pkg_t *pkg, dheluks_kys_t *skr, dheluks_txt_t *txt) { uint8_t dig[DIGEST_SIZE]; chacha_poly1305_set_key(&ctx->ciph, skr->sharekey); //set key chacha_poly1305_set_nonce(&ctx->ciph, pkg->nonce); //set nonce chacha_poly1305_decrypt(&ctx->ciph, pkg->csize, txt->plntxt, pkg->cphtxt); //decrypt chacha_poly1305_digest(&ctx->ciph, DIGEST_SIZE, dig); if (not_equal(dig, pkg->digest, DIGEST_SIZE, "Message authentication failed.")) //if the digests aren't equal, return -1; //return an error return 0; }
// Initialize chacha-poly1305 cipher void init_cipher(dheluks_ctx_t *ctx, uint8_t *sk) { chacha_poly1305_set_key(&ctx->ciph, sk); //initialize symm cipher with key sk }