#!/usr/local/bin/php
<?php
/*
$Horde: horde/scripts/cipherTest.php,v 1.5 2003/02/22 05:11:37 mikec Exp $

This script tests the different cipher classes to check conformance.

*/
ini_set('display_errors', '1');
define('HORDE_BASE', dirname(__FILE__) . '/..');
@require_once HORDE_BASE . '/lib/base.php';
require_once HORDE_BASE . '/lib/Cipher.php';

/* RC4 Cipher */
echo "RC4:\n";
echo "----\n\n";

// 64 Bit key test
echo "64-bit Key\n";
$key = "\x01\x23\x45\x67\x89\xab\xcd\xef";;
$plaintext = "\x01\x23\x45\x67\x89\xab\xcd\xef";
$ciphertext = "\x75\xb7\x87\x80\x99\xe0\xc5\x96";
testCipher('rc4', $key, $plaintext, $ciphertext);

// 64 Bit key test
echo "64-bit Key\n";
$key = "\x01\x23\x45\x67\x89\xab\xcd\xef";;
$plaintext = "\x00\x00\x00\x00\x00\x00\x00\x00";
$ciphertext = "\x74\x94\xc2\xe7\x10\x4b\x08\x79";
testCipher('rc4', $key, $plaintext, $ciphertext);

// 64 Bit key test
echo "64-bit Key\n";
$key = "\x00\x00\x00\x00\x00\x00\x00\x00";
$plaintext = "\x00\x00\x00\x00\x00\x00\x00\x00";
$ciphertext = "\xde\x18\x89\x41\xa3\x37\x5d\x3a";
testCipher('rc4', $key, $plaintext, $ciphertext);

// 32 Bit key test
echo "32-bit Key\n";
$key = "\xef\x01\x23\x45";
$plaintext = "\x00\x00\x00\x00\x00\x00\x00\x00";
$ciphertext = "\xd6\xa1\x41\xa7\xec\x3c\x38\xdf";
testCipher('rc4', $key, $plaintext, $ciphertext);

/* DES Cipher */
echo "DES:\n";
echo "----\n\n";

// 64 Bit key test
$tests = array(
    "\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\x00", "\x8C\xA6\x4D\xE9\xC1\xB1\x23\xA7",
    "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", "\x73\x59\xB2\x16\x3E\x4E\xDC\x58",
    "\x30\x00\x00\x00\x00\x00\x00\x00", "\x10\x00\x00\x00\x00\x00\x00\x01", "\x95\x8E\x6E\x62\x7A\x05\x55\x7B",
    "\x01\x23\x45\x67\x89\xAB\xCD\xEF", "\x11\x11\x11\x11\x11\x11\x11\x11", "\x17\x66\x8D\xFC\x72\x92\x53\x2D",
    "\x11\x11\x11\x11\x11\x11\x11\x11", "\x01\x23\x45\x67\x89\xAB\xCD\xEF", "\x8A\x5A\xE1\xF8\x1A\xB8\xF2\xDD",

    // Initial Permutation and Expansion test
    "\x01\x01\x01\x01\x01\x01\x01\x01", "\x95\xF8\xA5\xE5\xDD\x31\xD9\x00", "\x80\x00\x00\x00\x00\x00\x00\x00",

    // Key Permutation test
    "\x80\x01\x01\x01\x01\x01\x01\x01", "\x00\x00\x00\x00\x00\x00\x00\x00", "\x95\xA8\xD7\x28\x13\xDA\xA9\x4D",

    // Data Permutation tests
    "\x10\x46\x91\x34\x89\x98\x01\x31", "\x00\x00\x00\x00\x00\x00\x00\x00", "\x88\xD5\x5E\x54\xF5\x4C\x97\xB4",

    // S-Box test
    "\x7C\xA1\x10\x45\x4A\x1A\x6E\x57", "\x01\xA1\xD6\xD0\x39\x77\x67\x42", "\x69\x0F\x5B\x0D\x9A\x26\x93\x9B",
    "\x01\x31\xD9\x61\x9D\xC1\x37\x6E", "\x5C\xD5\x4C\xA8\x3D\xEF\x57\xDA", "\x7A\x38\x9D\x10\x35\x4B\xD2\x71",
 );

for ($i = 0; $i < count($tests); $i+= 3) {
    echo "64-bit Key\n";
    $key = $tests[$i];
    $plaintext = $tests[$i + 1];
    $ciphertext = $tests[$i + 2];
    testCipher('des', $key, $plaintext, $ciphertext);
}

/* RC2 Cipher */
echo "RC2:\n";
echo "----\n\n";

// 8 Bit key test
echo "8-bit Key\n";
$key = "\x88";
$plaintext = "\x00\x00\x00\x00\x00\x00\x00\x00";
$ciphertext = "\x61\xa8\xa2\x44\xad\xac\xcc\xf0";
testCipher('rc2', $key, $plaintext, $ciphertext);

// 64 Bit key test
echo "64-bit Key\n";
$key = "\x00\x00\x00\x00\x00\x00\x00\x00";
$plaintext = "\x00\x00\x00\x00\x00\x00\x00\x00";
$ciphertext = "\xeb\xb7\x73\xf9\x93\x27\x8e\xff";
testCipher('rc2', $key, $plaintext, $ciphertext);

// 128 Bit key test
echo "128-bit Key\n";
$key = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
$plaintext = "\x00\x00\x00\x00\x00\x00\x00\x00";
$ciphertext = "\x50\xDC\x01\x62\xBD\x75\x7F\x31";
testCipher('rc2', $key, $plaintext, $ciphertext);

// 64 Bit key test
echo "64-bit Key\n";
$key = "\xff\xff\xff\xff\xff\xff\xff\xff";
$plaintext = "\xff\xff\xff\xff\xff\xff\xff\xff";
$ciphertext = "\x27\x8b\x27\xe4\x2e\x2f\x0d\x49";
testCipher('rc2', $key, $plaintext, $ciphertext);


/* Cast 128 Cipher */
echo "Cast 128:\n";
echo "---------\n\n";

// 128 Bit key test
echo "128-bit Key\n";
$key = "\x01\x23\x45\x67\x12\x34\x56\x78\x23\x45\x67\x89\x34\x56\x78\x9A";
$plaintext = "\x01\x23\x45\x67\x89\xAB\xCD\xEF";
$ciphertext = "\x23\x8B\x4F\xE5\x84\x7E\x44\xB2";
testCipher('cast128', $key, $plaintext, $ciphertext);

// 80 Bit key text
echo "80-bit Key\n";
$key = "\x01\x23\x45\x67\x12\x34\x56\x78\x23\x45";
$plaintext = "\x01\x23\x45\x67\x89\xAB\xCD\xEF";
$ciphertext = "\xEB\x6A\x71\x1A\x2C\x02\x27\x1B";
testCipher('cast128', $key, $plaintext, $ciphertext);

// 40 Bit key text
echo "40-bit Key\n";
$key = "\x01\x23\x45\x67\x12";
$plaintext = "\x01\x23\x45\x67\x89\xAB\xCD\xEF";
$ciphertext = "\x7A\xC8\x16\xD1\x6E\x9B\x30\x2E";
testCipher('cast128', $key, $plaintext, $ciphertext);


/* Blowfish */
// selection of tests from: http://www.counterpane.com/vectors.txt
echo "Blowfish:\n";
echo "---------\n\n";

// 64 Bit key text
echo "64-bit Key\n";
$key = "\x49\xE9\x5D\x6D\x4C\xA2\x29\xBF";
$plaintext = "\x02\xFE\x55\x77\x81\x17\xF1\x2A";
$ciphertext = "\xCF\x9C\x5D\x7A\x49\x86\xAD\xB5";
testCipher('blowfish', $key, $plaintext, $ciphertext);

$plaintext = "\xFE\xDC\xBA\x98\x76\x54\x32\x10";
$c[ 1] = "\xF9\xAD\x59\x7C\x49\xDB\x00\x5E"; $k[ 1] = "\xF0";
$c[ 2] = "\xE9\x1D\x21\xC1\xD9\x61\xA6\xD6"; $k[ 2] = "\xF0\xE1";
$c[ 3] = "\xE9\xC2\xB7\x0A\x1B\xC6\x5C\xF3"; $k[ 3] = "\xF0\xE1\xD2";
$c[ 4] = "\xBE\x1E\x63\x94\x08\x64\x0F\x05"; $k[ 4] = "\xF0\xE1\xD2\xC3";
$c[ 5] = "\xB3\x9E\x44\x48\x1B\xDB\x1E\x6E"; $k[ 5] = "\xF0\xE1\xD2\xC3\xB4";
$c[ 6] = "\x94\x57\xAA\x83\xB1\x92\x8C\x0D"; $k[ 6] = "\xF0\xE1\xD2\xC3\xB4\xA5";
$c[ 7] = "\x8B\xB7\x70\x32\xF9\x60\x62\x9D"; $k[ 7] = "\xF0\xE1\xD2\xC3\xB4\xA5\x96";
$c[ 8] = "\xE8\x7A\x24\x4E\x2C\xC8\x5E\x82"; $k[ 8] = "\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87";
$c[ 9] = "\x15\x75\x0E\x7A\x4F\x4E\xC5\x77"; $k[ 9] = "\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87\x78";
$c[10] = "\x12\x2B\xA7\x0B\x3A\xB6\x4A\xE0"; $k[10] = "\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87\x78\x69";
$c[11] = "\x3A\x83\x3C\x9A\xFF\xC5\x37\xF6"; $k[11] = "\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87\x78\x69\x5A";
$c[12] = "\x94\x09\xDA\x87\xA9\x0F\x6B\xF2"; $k[12] = "\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87\x78\x69\x5A\x4B";
$c[13] = "\x88\x4F\x80\x62\x50\x60\xB8\xB4"; $k[13] = "\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87\x78\x69\x5A\x4B\x3C";
$c[14] = "\x1F\x85\x03\x1C\x19\xE1\x19\x68"; $k[14] = "\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87\x78\x69\x5A\x4B\x3C\x2D";
$c[15] = "\x79\xD9\x37\x3A\x71\x4C\xA3\x4F"; $k[15] = "\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87\x78\x69\x5A\x4B\x3C\x2D\x1E";
$c[16] = "\x93\x14\x28\x87\xEE\x3B\xE1\x5C"; $k[16] = "\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87\x78\x69\x5A\x4B\x3C\x2D\x1E\x0F";
$c[17] = "\x03\x42\x9E\x83\x8C\xE2\xD1\x4B"; $k[17] = "\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87\x78\x69\x5A\x4B\x3C\x2D\x1E\x0F\x00";
$c[18] = "\xA4\x29\x9E\x27\x46\x9F\xF6\x7B"; $k[18] = "\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87\x78\x69\x5A\x4B\x3C\x2D\x1E\x0F\x00\x11";
$c[19] = "\xAF\xD5\xAE\xD1\xC1\xBC\x96\xA8"; $k[19] = "\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87\x78\x69\x5A\x4B\x3C\x2D\x1E\x0F\x00\x11\x22";
$c[20] = "\x10\x85\x1C\x0E\x38\x58\xDA\x9F"; $k[20] = "\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87\x78\x69\x5A\x4B\x3C\x2D\x1E\x0F\x00\x11\x22\x33";
$c[21] = "\xE6\xF5\x1E\xD7\x9B\x9D\xB2\x1F"; $k[21] = "\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87\x78\x69\x5A\x4B\x3C\x2D\x1E\x0F\x00\x11\x22\x33\x44";
$c[22] = "\x64\xA6\xE1\x4A\xFD\x36\xB4\x6F"; $k[22] = "\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87\x78\x69\x5A\x4B\x3C\x2D\x1E\x0F\x00\x11\x22\x33\x44\x55";
$c[23] = "\x80\xC7\xD7\xD4\x5A\x54\x79\xAD"; $k[23] = "\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87\x78\x69\x5A\x4B\x3C\x2D\x1E\x0F\x00\x11\x22\x33\x44\x55\x66";
$c[24] = "\x05\x04\x4B\x62\xFA\x52\xD0\x80"; $k[24] = "\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87\x78\x69\x5A\x4B\x3C\x2D\x1E\x0F\x00\x11\x22\x33\x44\x55\x66\x77";
foreach ($k as $id => $key) {
    echo (strlen($key) * 8) . "-bit Key\n";
    testCipher('blowfish', $key, $plaintext, $c[$id]);
}

/* Block Mode Tests */
echo "Block Mode Tests:\n";
echo "-----------------\n";
echo "(using Blowfish test vectors)\n\n";

$key = "\x01\x23\x45\x67\x89\xAB\xCD\xEF\xF0\xE1\xD2\xC3\xB4\xA5\x96\x87";
$iv = "\xFE\xDC\xBA\x98\x76\x54\x32\x10";
$plaintext = "7654321 Now is the time for ";

echo "Cipher Block Chaining (CBC) Test\n";
$ciphertext = "\x6B\x77\xB4\xD6\x30\x06\xDE\xE6\x05\xB1\x56\xE2\x74\x03\x97\x93\x58\xDE\xB9\xE7\x15\x46\x16\xD9\x59\xF1\x65\x2B\xD5\xFF\x92\xCC";
$cipher = &Horde_Cipher::factory('blowfish');
$cipher->setBlockMode("cbc");
$cipher->setKey($key);
$cipher->setIV($iv);
testBlockCipher($cipher, $plaintext, $ciphertext);


echo "Electronic Code Book (ECB) Test\n";
$ciphertext = "\x2a\xfd\x7d\xaa\x60\x62\x6b\xa3\x86\x16\x46\x8c\xc2\x9c\xf6\xe1\x29\x1e\x81\x7c\xc7\x40\x98\x2d\x6f\x87\xac\x5f\x17\x1a\xab\xea";
$cipher = &Horde_Cipher::factory('blowfish');
$cipher->setBlockMode("ecb");
$cipher->setKey($key);
$cipher->setIV($iv);
testBlockCipher($cipher, $plaintext, $ciphertext);

echo "64 Bit Cipher Feedback (CFB64) Test\n";
$ciphertext = "\xE7\x32\x14\xA2\x82\x21\x39\xCA\xF2\x6E\xCF\x6D\x2E\xB9\xE7\x6E\x3D\xA3\xDE\x04\xD1\x51\x72\x00\x51\x9D\x57\xA6";
$cipher = &Horde_Cipher::factory('blowfish');
$cipher->setBlockMode("cfb64");
$cipher->setKey($key);
$cipher->setIV($iv);
testBlockCipher($cipher, $plaintext, $ciphertext);

echo "64 Bit Output Feedback (OFB64) Test\n";
$ciphertext = "\xE7\x32\x14\xA2\x82\x21\x39\xCA\x62\xB3\x43\xCC\x5B\x65\x58\x73\x10\xDD\x90\x8D\x0C\x24\x1B\x22\x63\xC2\xCF\x80";
$cipher = &Horde_Cipher::factory('blowfish');
$cipher->setBlockMode("ofb64");
$cipher->setKey($key);
$cipher->setIV($iv);
testBlockCipher($cipher, $plaintext, $ciphertext);


function testBlockCipher(&$cipher, $plaintext, $ciphertext)
{
    echo "Testing Encryption: ";
    if ($cipher->encrypt($plaintext) == $ciphertext) {
        echo "Pass\n";
    } else {
        echo "Fail\n";
    }
    echo "Testing Decryption: ";
    if ($cipher->decrypt($ciphertext) == $plaintext) {
        echo "Pass\n";
    } else {
        echo "Fail\n";
    }
    echo "\n";
    flush();
}

function testCipher($cipher, $key,  $plaintext, $ciphertext)
{
    $cipher = &Horde_Cipher::factory($cipher);
    $cipher->setKey($key);

    echo "Testing Encryption: ";
    $res = $cipher->encryptBlock($plaintext);
    if ($res == $ciphertext) {
        echo "Pass\n";
    } else {
        echo "Fail\n";
        echo "Returned: ";
        for ($i = 0; $i < strlen($res); $i++) {
            echo str_pad(dechex(ord(substr($res, $i, 1))), 2, '0', STR_PAD_LEFT) . " ";
        } echo "\n";
        echo "Expected: ";
        for ($i = 0; $i < strlen($ciphertext); $i++) {
            echo str_pad(dechex(ord(substr($ciphertext, $i, 1))), 2, '0', STR_PAD_LEFT)  . " ";
        } echo "\n";

    }
    echo "Testing Decryption: ";
    $res = $cipher->decryptBlock($ciphertext);
    if ($res == $plaintext) {
        echo "Pass\n";
    } else {
        echo "Fail\n";
        echo "Returned: ";
        for ($i = 0; $i < strlen($res); $i++) {
            echo str_pad(dechex(ord(substr($res, $i, 1))), 2, '0', STR_PAD_LEFT) . " ";
        } echo "\n";
        echo "Expected: ";
        for ($i = 0; $i < strlen($plaintext); $i++) {
            echo str_pad(dechex(ord(substr($plaintext, $i, 1))), 2, '0', STR_PAD_LEFT)  . " ";
        } echo "\n";
    }
    echo "\n";
    flush();
}
