Commit graph

1 commit

Author SHA1 Message Date
djmaze
7f1b1e6288 @ZaphodB fix(security): tokens could be forged by choosing the xxtea algorithm
Crypt::Decrypt() calls "{name}Decrypt" with the algorithm name taken from the
token itself, so a client could ask for xxtea on any server. XxteaDecrypt used
$salt . Passphrase() as the key, but XXTEA reads only the first 16 bytes of its
key and the salt is 16 bytes stored in the token: the server secret never took
part. Anyone could therefore make a token every Crypt::Decrypt* consumer would
accept as genuine (remember-me, secure cookies, DecodeKeyValuesQ raw keys, ...),
and any real xxtea token could be read. The consumers traced so far still
require a server-side record or a real IMAP login, so this is not a known
account takeover, but the integrity check they rely on was not there.

- Decrypt refuses xxtea whenever sodium or openssl is available, i.e. whenever
  Encrypt() would never have produced it, compares the name case-insensitively
  (PHP method names are), and dispatches only sodium, openssl and xxtea rather
  than any method name ending in Decrypt.
- The xxtea key is now the first 16 bytes of sha256(salt . passphrase), so on a
  host left with nothing but xxtea it depends on the secret. Tokens written under
  the old derivation stop decrypting there; they were never keyed by the server.

test/crypt-forgery.php forges a token with an attacker-chosen salt (accepted
before this change), checks it and an arbitrary method name are refused, and
that sodium, url-safe and xxtea round trips still work only with the right key.
2026-10-25 23:36:57 +01:00