'victim@example.com', 'admin' => true]), $salt); foreach (['xxtea', 'XXTEA', 'Xxtea'] as $algo) { check(null === $Crypt::Decrypt([$algo, $salt, $forged], 'server-key'), "forged {$algo} token accepted"); } // Unknown algorithm names are refused rather than dispatched. check(null === $Crypt::Decrypt(['jsonDecode', $salt, $forged], 'server-key'), 'arbitrary method name dispatched'); // Normal tokens still round-trip, and only with the right key. $data = ['e' => 'user@example.com', 'n' => 42]; check($data === $Crypt::Decrypt($Crypt::Encrypt($data, 'server-key'), 'server-key'), 'sodium round trip broke'); check($data === $Crypt::DecryptUrlSafe($Crypt::EncryptUrlSafe($data, 'server-key'), 'server-key'), 'url-safe round trip broke'); check(null === $Crypt::Decrypt($Crypt::Encrypt($data, 'server-key'), 'other-key'), 'decrypted with the wrong key'); // The xxtea primitives themselves now depend on the server secret. $salt = random_bytes(16); $cipher = $Crypt::XxteaEncrypt('{"a":1}', $salt, 'server-key'); check('{"a":1}' === $Crypt::XxteaDecrypt($cipher, $salt, 'server-key'), 'xxtea round trip broke'); check('{"a":1}' !== $Crypt::XxteaDecrypt($cipher, $salt, 'other-key'), 'xxtea key does not depend on the secret'); check('{"a":1}' !== \MailSo\Base\Xxtea::decrypt($cipher, $salt), 'xxtea still keyed by the salt alone'); echo "crypt-forgery: ok\n"; }