I am trying to implement ECIES properly with X25519/HKDFwithSHA256/AES-128-GCM with Node.js crypto library. It is not clear to me how to determine the input key material (IKM) to HKDF.
Initially, I thought it is okay to directly use the shared secret generated by X25519 as the IKM.
const {diffieHellman, hkdfSync} = require('crypto');
const sharedKey = diffieHellman({
privateKey,
publicKey,
});
const aesKey = hkdfSync('sha256', sharedKey, '', '', 16);
But apparently, if diffieHellman
does not contain publicKey
and the output only contains the x-coordinate of a point, then this is not CCA2-secure, as mentioned in https://eprint.iacr.org/2001/112.pdf:
There are a number of simple examples that illustrate why ECIES does not achieve this level of security. In particular, it is malleable. If the group is an elliptic curve, and the partial encoding function E′ encodes only the x-coordinate of a point, then the derived key K is the same if one takes a given ciphertext $C_0$ encoding a point $\tilde{g}$ and replaces it with an encoding of $−\tilde{g}$.
Some implementations of X25519 also suggests users to include the public values as inputs to the KDF.
Do not use the shared key directly, rather use a key derivation function and also include the two public values as inputs.
Is it sufficient to use the shared secret directly as IKM?
If not, what is the proper way to include the public key in the IKM?