in src/aesgcm.rs [230:264]
fn derive_key_and_nonce(
cryptographer: &dyn Cryptographer,
ece_mode: EceMode,
local_prv_key: &dyn LocalKeyPair,
remote_pub_key: &dyn RemotePublicKey,
auth_secret: &[u8],
salt: &[u8],
) -> Result<KeyAndNonce> {
if auth_secret.len() != ECE_WEBPUSH_AUTH_SECRET_LENGTH {
return Err(Error::InvalidAuthSecret);
}
if salt.len() != ECE_SALT_LENGTH {
return Err(Error::InvalidSalt);
}
let shared_secret = cryptographer.compute_ecdh_secret(remote_pub_key, local_prv_key)?;
let raw_remote_pub_key = remote_pub_key.as_raw()?;
let raw_local_pub_key = local_prv_key.pub_as_raw()?;
let keypair = match ece_mode {
EceMode::Encrypt => encode_keys(&raw_remote_pub_key, &raw_local_pub_key),
EceMode::Decrypt => encode_keys(&raw_local_pub_key, &raw_remote_pub_key),
}?;
let keyinfo = generate_info("aesgcm", &keypair)?;
let nonceinfo = generate_info("nonce", &keypair)?;
let ikm = cryptographer.hkdf_sha256(
auth_secret,
&shared_secret,
ECE_WEBPUSH_AESGCM_AUTHINFO.as_bytes(),
ECE_WEBPUSH_IKM_LENGTH,
)?;
let key = cryptographer.hkdf_sha256(salt, &ikm, &keyinfo, ECE_AES_KEY_LENGTH)?;
let nonce = cryptographer.hkdf_sha256(salt, &ikm, &nonceinfo, ECE_NONCE_LENGTH)?;
Ok((key, nonce))
}