So... Ich hab mich heute mal drangesetzt und das ein bisschen analysiert. Grundsätzlich habe ich keine großen Anmerkungen zu deiner Verschlüsselungsklasse, auch wenn ich persönlich einen komplett anderen Ansatz gewählt habe (hängt mit der Struktur meines Frameworks zusammen).
Ich würde allerdings in validate() das zweite IF durch ein ELSEIF ersetzen. Weiterhin solltest du nicht auf !($_COOKIE[self::$cookiename]) prüfen, sondern auf !isset($_COOKIE[self::$cookiename]), ist einfach genauer. Theoretisch könntest du auch die oder-Bedingung mit in die !isset-Bedingung einfassen in dem du !empty() nutzt.
Um auf dein Problem zurück zu kommen, es hat mich nen bisschen überlegen gekostet, woran es liegt. Ein paar mehr Echos in der validate-Funktion (Anzeige des Cookieinhalts) hat mich letztendlich darauf gebracht.
Sobald der verschlüsselte String ein \"
enthält, so scheint es Probleme mit der Übertragung vom/zum Browser zu geben. Das liegt daran, das der Output der Verschlüsselungsfunktionen nicht zwingend auch im anzeigbaren Zeichenbereich liegen müssen.
In diesem Fall wäre eine base64-Encodierung aus praktischen Gründen angebracht. Schau dir am besten base64_encode() / base64_decode() an.
Ansonsten mein (nicht ganz ins Klassenschema passender) Workaround:
public function set($challengekey)
{
setcookie(self::$cookiename,base64_encode($this->_encrypt($challengekey)));
}
private function _decrypt($crypttext)
{
$crypttext = base64_decode($crypttext);
...
Hoffe das hilft. In meinen anschliessenden Tests wurde der Cookie unter allen benutzten Browsern validiert, wenn er es sollte.