in src/aes128gcm.rs [521:565]
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()?;
// The "aes128gcm" scheme includes the sender and receiver public keys in
// the info string when deriving the Web Push IKM.
let ikm_info = match ece_mode {
EceMode::Encrypt => generate_info(&raw_remote_pub_key, &raw_local_pub_key),
EceMode::Decrypt => generate_info(&raw_local_pub_key, &raw_remote_pub_key),
}?;
let ikm = cryptographer.hkdf_sha256(
auth_secret,
&shared_secret,
&ikm_info,
ECE_WEBPUSH_IKM_LENGTH,
)?;
let key = cryptographer.hkdf_sha256(
salt,
&ikm,
ECE_AES128GCM_KEY_INFO.as_bytes(),
ECE_AES_KEY_LENGTH,
)?;
let nonce = cryptographer.hkdf_sha256(
salt,
&ikm,
ECE_AES128GCM_NONCE_INFO.as_bytes(),
ECE_NONCE_LENGTH,
)?;
Ok((key, nonce))
}