After almost 4 days of work, I've finally gotten Libsodium crypto_aead_xchacha20poly1305_ietf_encrypt
to work and produce the same result in JavaScript and PHP.
But I'm confused.
The PHPDoc describes the parameters as:
* @param string $plaintext Message to be encrypted
* @param string $assocData Authenticated Associated Data (unencrypted)
* @param string $nonce Number to be used only Once
* @param string $key Encryption key
* @return string
While JSDoc asks for these parameters:
/**
* @param {string | Uint8Array} message
* @param {string | Uint8Array} additional_data
* @param {string | Uint8Array} secret_nonce
* @param {Uint8Array} public_nonce
* @param {Uint8Array} key
* @param {uint8array} outputFormat
* @returns {Uint8Array}
*/
My questions:
- It seems like a nonce is a type of salt of a specific size that can only be used once because otherwise replay attacks can happen. Can you help me understand this further? Wikipedia and other sites got too complicated.
- To a layman, how would you describe AEAD and how to use the "Authenticated Associated Data (unencrypted)" parameter?
- In the PHP function (which I copied from https://paragonie.com/b/kIqqEWlp3VUOpRD7), does using the nonce not just as a nonce but also as the "Authenticated Associated Data" reduce the security compared to some other approach where the sender would add some value here and communicate offline to the receiver what the receiver should expect this value to be?
- Why would the JavaScript version accept different parameters? JS asks for a secret_nonce separate from a public_nonce, and in order for the results to match PHP's function, I need to supply identical values for secret_nonce and public_nonce. So what's the point?
P.S. Here are the functions:
JavaScript:
/**
* @param {string} message
* @param {Uint8Array} key
* @returns {Uint8Array}
*/
function encryptAndPrependNonce(message, key) {
let nonce = sodium.randombytes_buf(nonceBytes);
var encrypted = sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(message, nonce, nonce, nonce, key);
var nonce_and_ciphertext = concatTypedArray(Uint8Array, nonce, encrypted);
return nonce_and_ciphertext;
}
PHP:
/**
* @link https://paragonie.com/b/kIqqEWlp3VUOpRD7 (from the `simpleEncrypt` function)
* @param string $message
* @param string $keyAsBinary
* @return string
*/
public static function encryptAndPrependNonce($message, $keyAsBinary) {
$nonce = random_bytes(self::NONCE_BYTES); // NONCE = Number to be used ONCE, for each message
$encrypted = ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_encrypt($message, $nonce, $nonce, $keyAsBinary);
return $nonce . $encrypted;
}