/** * proto_crypt_mkkeys(K, nonce_l, nonce_r, yh_r, x, nofps, decr, eh_c, eh_s): * Using the protocol secret ${K}, the local and remote nonces ${nonce_l} and * ${nonce_r}, the remote MACed diffie-hellman handshake parameter ${yh_r}, * and the local diffie-hellman secret ${x}, generate the keys ${eh_c} and * ${eh_s}. If ${nofps} is non-zero, we are performing weak handshaking and * y_SC is set to 1 rather than being computed. If ${decr} is non-zero, * "local" == "S" and "remote" == "C"; otherwise the assignments are opposite. */ int proto_crypt_mkkeys(const struct proto_secret * K, const uint8_t nonce_l[PCRYPT_NONCE_LEN], const uint8_t nonce_r[PCRYPT_NONCE_LEN], const uint8_t yh_r[PCRYPT_YH_LEN], const uint8_t x[PCRYPT_X_LEN], int nofps, int decr, struct proto_keys ** eh_c, struct proto_keys ** eh_s) { uint8_t nonce_y[PCRYPT_NONCE_LEN * 2 + CRYPTO_DH_KEYLEN]; uint8_t dk_2[128]; const uint8_t * nonce_c, * nonce_s; /* Copy in nonces (in the right order). */ nonce_c = decr ? nonce_r : nonce_l; nonce_s = decr ? nonce_l : nonce_r; memcpy(&nonce_y[0], nonce_c, PCRYPT_NONCE_LEN); memcpy(&nonce_y[PCRYPT_NONCE_LEN], nonce_s, PCRYPT_NONCE_LEN); /* Are we bypassing the diffie-hellman computation? */ if (nofps) { /* We sent y_l = 1, so y_SC is also 1. */ memset(&nonce_y[PCRYPT_NONCE_LEN * 2], 0, CRYPTO_DH_KEYLEN - 1); nonce_y[PCRYPT_NONCE_LEN * 2 + CRYPTO_DH_KEYLEN - 1] = 1; } else { /* Perform the diffie-hellman computation. */ if (crypto_dh_compute(yh_r, x, &nonce_y[PCRYPT_NONCE_LEN * 2])) goto err0; } /* Compute dk_2. */ PBKDF2_SHA256(K->K, 32, nonce_y, PCRYPT_NONCE_LEN * 2 + CRYPTO_DH_KEYLEN, 1, dk_2, 128); /* Create key structures. */ if ((*eh_c = mkkeypair(&dk_2[0])) == NULL) goto err0; if ((*eh_s = mkkeypair(&dk_2[64])) == NULL) goto err1; /* Success! */ return (0); err1: proto_crypt_free(*eh_c); err0: /* Failure! */ return (-1); }
static int callback_register_challenge(void * cookie, NETPACKET_CONNECTION * NPC, int status, uint8_t packettype, const uint8_t * packetbuf, size_t packetlen) { struct register_internal * C = cookie; uint8_t pub[CRYPTO_DH_PUBLEN]; uint8_t priv[CRYPTO_DH_PRIVLEN]; uint8_t K[CRYPTO_DH_KEYLEN]; uint8_t keys[96]; /* Handle errors. */ if (status != NETWORK_STATUS_OK) { netproto_printerr(status); goto err0; } /* * Make sure we received the right type of packet. It is legal for * the server to send back a NETPACKET_REGISTER_RESPONSE at this * point; call callback_register_response to handle those. */ if (packettype == NETPACKET_REGISTER_RESPONSE) return (callback_register_response(cookie, NPC, status, packettype, packetbuf, packetlen)); else if (packettype != NETPACKET_REGISTER_CHALLENGE) { netproto_printerr(NETPROTO_STATUS_PROTERR); goto err0; } /* Generate DH parameters from the password and salt. */ if (crypto_passwd_to_dh(C->passwd, packetbuf, pub, priv)) { warnp("Could not generate DH parameter from password"); goto err0; } /* Compute shared key. */ if (crypto_dh_compute(&packetbuf[32], priv, K)) goto err0; if (crypto_hash_data(CRYPTO_KEY_HMAC_SHA256, K, CRYPTO_DH_KEYLEN, C->register_key)) { warn0("Programmer error: " "SHA256 should never fail"); goto err0; } /* Export access keys. */ if (crypto_keys_raw_export_auth(keys)) goto err0; /* Send challenge response packet. */ if (netpacket_register_cha_response(NPC, keys, C->name, C->register_key, callback_register_response)) goto err0; /* We've responded to a challenge. */ C->donechallenge = 1; /* Success! */ return (0); err0: /* Failure! */ return (-1); }
/** * crypto_session_init(pub, priv, nonce, mkey, encr_write, auth_write, * encr_read, auth_read): * Compute K = ${pub}^(2^258 + ${priv}), mkey = MGF1(nonce || K, 48), and * return a CRYPTO_SESSION with encryption and authentication write and read * keys constructed from HMAC(mkey, (encr|auth)_(write|read)). */ CRYPTO_SESSION * crypto_session_init(uint8_t pub[CRYPTO_DH_PUBLEN], uint8_t priv[CRYPTO_DH_PRIVLEN], uint8_t nonce[32], uint8_t mkey[48], const char * encr_write, const char * auth_write, const char * encr_read, const char * auth_read) { struct crypto_session_internal * CS; uint8_t K[CRYPTO_DH_PUBLEN]; uint8_t MGFbuf[32 + CRYPTO_DH_PUBLEN]; uint8_t aes_write[32]; uint8_t aes_read[32]; /* Compute K = 2^(xy) mod p. */ if (crypto_dh_compute(pub, priv, K)) goto err0; /* Shared key is MGF1(nonce || K, 48). */ memcpy(MGFbuf, nonce, 32); memcpy(MGFbuf + 32, K, CRYPTO_DH_PUBLEN); crypto_MGF1(MGFbuf, 32 + CRYPTO_DH_PUBLEN, mkey, 48); /* Allocate space for session key structure. */ if ((CS = malloc(sizeof(struct crypto_session_internal))) == NULL) goto err0; /* Generate raw keys. */ crypto_hash_data_key(mkey, 48, (const uint8_t *)encr_write, strlen(encr_write), aes_write); crypto_hash_data_key(mkey, 48, (const uint8_t *)auth_write, strlen(auth_write), CS->auth_write); crypto_hash_data_key(mkey, 48, (const uint8_t *)encr_read, strlen(encr_read), aes_read); crypto_hash_data_key(mkey, 48, (const uint8_t *)auth_read, strlen(auth_read), CS->auth_read); /* Expand AES keys and set up streams. */ if (AES_set_encrypt_key(aes_write, 256, &CS->encr_write)) { warn0("error in AES_set_encrypt_key"); goto err1; } if (AES_set_encrypt_key(aes_read, 256, &CS->encr_read)) { warn0("error in AES_set_encrypt_key"); goto err1; } if ((CS->encr_write_stream = crypto_aesctr_init(&CS->encr_write, 0)) == NULL) goto err1; if ((CS->encr_read_stream = crypto_aesctr_init(&CS->encr_read, 0)) == NULL) goto err2; /* Initialize parameters. */ CS->auth_write_nonce = CS->auth_read_nonce = 0; /* Success! */ return (CS); err2: crypto_aesctr_free(CS->encr_write_stream); err1: free(CS); err0: /* Failure! */ return (NULL); }