/*
   CyberRax Programming (C) 2003
   TITLE:   CRYPTEST.H--
   DESCRIPTION:   Test module for encryption algorithms.
   LAST MODIFIED:  01 Oct 2003
   PROCEDURES DEFINED IN THIS FILE:
      word CRYPTEST(buf)
   DEFINITION AFFECTING THIS CODE:
      _TEST_ALL_CIPHERS_ - test all (currently BLOWFISH, ARCFOUR and TEA)
			   ciphers (sets also the following definitions)
      _TEST_ARCFOUR_	 - test (only) ARCFOUR cipher
      _TEST_BLOWFISH_	 - test (only) BLOWFISH cipher
      _TEST_TEA_	 - test (only) TEA cipher
			   These *must* be definied *before* including this
			     headerfile and if none is definied then
			     _TEST_ALL_CIPHERS_ is assumed
   NOTE:   both BlowFish and ARCFOUR (TEA perhaps too) have official (so
	     to speak) testvectors, but as this code was meant to be
	     incorporated into programs (rather than using just one time to
	     see if the implementations are correct) then it made no sence to
	     include different vectors for every cipher.
*/

? ifndef _CRYPTEST_
? define _CRYPTEST_			20031001

? ifndef _TEST_ARCFOUR_
  ? ifndef _TEST_BLOWFISH_
    ? ifndef _TEST_TEA_
      ? ifndef _TEST_ALL_CIPHERS_
	? define _TEST_ALL_CIPHERS_	TRUE
      ? endif
    ? endif
  ? endif
? endif

? ifdef _TEST_ALL_CIPHERS_
  ? ifndef _TEST_ARCFOUR_
    ? define _TEST_ARCFOUR_		TRUE
  ? endif
  ? ifndef _TEST_BLOWFISH_
    ? define _TEST_BLOWFISH_		TRUE
  ? endif
  ? ifndef _TEST_TEA_
    ? define _TEST_TEA_			TRUE
  ? endif
? endif

? ifdef _TEST_ARCFOUR_
  ? ifndef _ARCFOUR_
    ? include "ARCFOUR.H--"
  ? endif
? endif

? ifdef _TEST_BLOWFISH_
  ? ifndef _BLOWFISH_
    ? include "BLOWFISH.H--"
  ? endif
? endif

? ifdef _TEST_TEA_
  ? ifndef _TEA_
    ? include "TEA.H--"
  ? endif
? endif

? ifdef _TEST_BLOWFISH_
  ? define CipherBoxesLen		BFishBoxesLen
? else
  ? ifdef _TEST_ARCFOUR_
    ? define CipherBoxesLen		ArcFourBoxesLen
  ? else
    ? define CipherBoxesLen		TEABoxLen
  ? endif
? endif


? ifndef _NUMBERS_
  ? include "NUMBERS.H--"
? endif

? ifndef _BYTES_
  ? include "BYTES.H--"
? endif

? warning		TRUE


// Testvectors
: byte CrypTestPlain1[EIGHT] = { 0x00, 0x00, 0x00, 0x00,
				 0x00, 0x00, 0x00, 0x00 };
: byte CrypTestKey1[EIGHT] =   { 0x01, 0x23, 0x45, 0x67,
				 0x89, 0xAB, 0xCD, 0xEF };
: byte CrypTestPlain2[TWENTY+FOUR] = { 'C', 'r', 'y', 'p',
				       'T', 'e', 's', 't', ' ',
				       't', 'e', 's', 't', ' ',
				       's', 't', 'r', 'i', 'n', 'g',
				       NULL, NULL, NULL, NULL };
: byte CrypTestKey2[SIX] = { 'B', 'y', ' ', 'C', 'y', 'R' };
: byte CrypTestPlain3[SIXTEEN] = { '0', '1', '2', '3', '4', '5', '6', '7',
				   '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
: byte CrypTestKey3[TWENTY+SIX] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
				    'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
				    'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
				    'y', 'z' };

: byte CrypTestCiphered[TWENTY+FOUR];

? ifdef _TEST_ARCFOUR_
  : byte CrypTestArcFourResult1 =  {  0x74, 0x94, 0xC2, 0xE7,
				      0x10, 0x4B, 0x08, 0x79  };
  : byte CrypTestArcFourResult2 =  {  0x5A, 0x22, 0x97, 0xA4,
				      0xBF, 0x59, 0xB0, 0x32,
				      0x82, 0x28, 0x85, 0x7A,
				      0xDD, 0xE5, 0x25, 0x7F,
				      0x77, 0xFD, 0xF9, 0xE5,
				      0x4F, 0x84, 0x6C, 0x14  };
  : byte CrypTestArcFourResult3 =  {  0x13, 0xA2, 0x85, 0xB6,
				      0xE7, 0xF6, 0x6B, 0x7F,
				      0x1C, 0xBC, 0xC9, 0x92,
				      0x83, 0x51, 0xD1, 0x65  };
? endif
? ifdef _TEST_BLOWFISH_
  : byte CrypTestBlowFishResult1 = {  0x24, 0x59, 0x46, 0x88,
				      0x57, 0x54, 0x36, 0x9A  };
  : byte CrypTestBlowFishResult2 = {  0x61, 0xD8, 0x41, 0x63,
				      0xBB, 0xA7, 0x44, 0x29,
				      0x83, 0x7A, 0x46, 0x00,
				      0x22, 0x52, 0xA8, 0x2E,
				      0xE1, 0xAC, 0xA7, 0x1E,
				      0xB2, 0xBA, 0xF4, 0x99  };
  : byte CrypTestBlowFishResult3 = {  0x9F, 0x8C, 0x0B, 0x9E,
				      0x8D, 0x79, 0x97, 0xB4,
				      0xB9, 0xFE, 0xDC, 0x9D,
				      0x71, 0x35, 0xB3, 0xC3  };
? endif
? ifdef _TEST_TEA_
  : byte CrypTestTeaResult1 =	   {  0xDC, 0x05, 0x57, 0xE5,
				      0xFE, 0xB6, 0x0D, 0xCA  };
  : byte CrypTestTeaResult2 =	   {  0x80, 0x4E, 0xFF, 0xEE,
				      0xD4, 0x8E, 0xE4, 0x5A,
				      0x33, 0xE3, 0x33, 0x13,
				      0x04, 0xEC, 0x78, 0x30,
				      0x04, 0x9B, 0xBE, 0xAC,
				      0xB3, 0x5B, 0xDB, 0x0C  };
  : byte CrypTestTeaResult3 =	   {  0x22, 0x11, 0x90, 0x17,
				      0xD8, 0xA9, 0x94, 0x85,
				      0x11, 0x62, 0x87, 0x3D,
				      0x63, 0x7C, 0xAA, 0xDC  };
? endif


: struct CRYPTESTDATA
{
   word KeyAddr;
   byte KeySize;
   word PlainAddr;
   byte PlainSize;
   ? ifdef _TEST_ARCFOUR_
     word ArcFourResult;
   ? endif
   ? ifdef _TEST_BLOWFISH_
     word BlowFishResult;
   ? endif
   ? ifdef _TEST_TEA_
     word TeaResult;
   ? endif
} CrypTestData[THREE] = { 
			  #CrypTestKey1, sizeof(CrypTestKey1),
			  #CrypTestPlain1, sizeof(CrypTestPlain1),
			  ? ifdef _TEST_ARCFOUR_
			    #CrypTestArcFourResult1,
			  ? endif
			  ? ifdef _TEST_BLOWFISH_
			    #CrypTestBlowFishResult1,
			  ? endif
			  ? ifdef _TEST_TEA_
			    #CrypTestTeaResult1,
			  ? endif
			  #CrypTestKey2, sizeof(CrypTestKey2),
			  #CrypTestPlain2, sizeof(CrypTestPlain2),
			  ? ifdef _TEST_ARCFOUR_
			    #CrypTestArcFourResult2,
			  ? endif
			  ? ifdef _TEST_BLOWFISH_
			    #CrypTestBlowFishResult2,
			  ? endif
			  ? ifdef _TEST_TEA_
			    #CrypTestTeaResult2,
			  ? endif
			  #CrypTestKey3, sizeof(CrypTestKey3),
			  #CrypTestPlain3, sizeof(CrypTestPlain3)
			  ? ifdef _TEST_ARCFOUR_
			    ,#CrypTestArcFourResult3
			  ? endif
			  ? ifdef _TEST_BLOWFISH_
			    ,#CrypTestBlowFishResult3
			  ? endif
			  ? ifdef _TEST_TEA_
			    ,#CrypTestTeaResult3
			  ? endif
			  };


: word CrypTestBuffer, CrypTestIndex;
: byte CrypTestCrypt, CrypTestCipherID;

inline word CRYPTEST (AX)
/* Tests encryption algorithm implementation against known(?) testvectors
   Input:  DS:AX = CipherBoxesLen (256 or 4160) bytes long buffer for ciphers
   Output: AX = 0 if all tests passed successfully
	   AX <> if some test failed
	     AH = number of test which failed (0 - 2)
	     AL = action * 10h + cipher ==> action = 0 by encryption
						   = 1 by decryption
					    cipher = 0 for ARCFOUR
						   = 1 for BLOWFISH
						   = 2 for TEA
	     So AX = 0x111 means BLOWFISH failed on decrypting the 2nd vector
	   BX, CX, DX, SI, DI destroyed
	   ES = DS
   Uses: COMP() from BYTES.H--
	 ARCFOUR_INIT()/ARCFOUR_CRYPT() from ARCFOUR.H-- and / or
	   BLOWFISH_INIT()/BLOWFISH_CRYPT() from BLOWFISH.H-- and / or
	   TEA_INIT()/TEA_CRYPT() from TEA.H--
	 ca. 16 - 20 bytes of stack
   Size: min. 490 bytes
*/
{
CrypTestBuffer = AX;
CrypTestIndex = CrypTestCrypt = NULL;
ES = DS;

CX = THREE;

CX_LOOP_1:
$PUSH CX

/***/
/*** For some unknown reason the following line *always* generates 386+ code
       if more than one cipher and 'optimize for speed' are used (atleast with
       C-- 0.239b8), so I'm including also 286- code.
***/
? ifdef cpu >= 3
  BX = #CrypTestData[CrypTestIndex].KeyAddr;
? else
  AX = sizeof(CrypTestData) / THREE;
  $IMUL CrypTestIndex
  BX = AX + #CrypTestData;
? endif

? ifdef _TEST_ARCFOUR_
  CrypTestCipherID = NULL;
  CX = TWO;
 CX_LOOP_2:
  $PUSH CX
  $PUSH BX
  SI = BX.CRYPTESTDATA.KeyAddr;
  BL = BX.CRYPTESTDATA.KeySize;
  DI = CrypTestBuffer;
  ? ifdef _MAXIMUM_SECURITY_
    CX = ONE;
  ? endif
  ARCFOUR_INIT();
  $POP BX
  $PUSH BX
  CX = BX.CRYPTESTDATA.PlainSize;
  SI = BX.CRYPTESTDATA.PlainAddr;
  DI = #CrypTestCiphered;
  IF (CrypTestCrypt)
     SI = DI;
  ARCFOUR_CRYPT(SI,CX,DI);
  $POP BX
  CX = BX.CRYPTESTDATA.PlainSize;
  SI = BX.CRYPTESTDATA.ArcFourResult;
  DI = #CrypTestCiphered;
  IF (CrypTestCrypt)
     SI = BX.CRYPTESTDATA.PlainAddr;
  IF (COMP(SI,DI,CX))
     {
     $POP CX,CX
     AL = CrypTestCrypt * SIXTEEN + CrypTestCipherID;
     AH = DSBYTE[#CrypTestIndex];
     return(AX);
     }
  CrypTestCrypt ^= ONE;

  $POP CX
  ? ifdef codesize
    $LOOP CX_LOOP_2;
  ? else
    /*** This method seems to be faster only on 386+, but when optimizing for
	 speed then (even the 286) code gets too large for the smaller '$LOOP'
	 so we use that instead.
    ***/
    CX--;
    IF (NOTZEROFLAG)
       GOTO CX_LOOP_2;
  ? endif
? endif

? ifdef _TEST_BLOWFISH_
  CrypTestCipherID = ONE;
  CX = TWO;
 CX_LOOP_3:
  $PUSH CX

  $PUSH BX
  DX = BX.CRYPTESTDATA.KeyAddr;
  BL = BX.CRYPTESTDATA.KeySize;
  DI = CrypTestBuffer;
  BLOWFISH_INIT();
  $POP BX
  $PUSH BX
  ? ifdef cpu >= 3
    CX = BX.CRYPTESTDATA.PlainSize / EIGHT;
  ? else
    AX = BX.CRYPTESTDATA.PlainSize / EIGHT;
    ? ifdef codesize
      CX >< AX;
    ? else
      CX = AX;
    ? endif
  ? endif
  AL = BFishEncrypt;
  SI = BX.CRYPTESTDATA.PlainAddr;
  DI = #CrypTestCiphered;
  IF (CrypTestCrypt)
     {
     AX++;
     SI = DI;
     }
  BLOWFISH_CRYPT();
  $POP BX
  CX = BX.CRYPTESTDATA.PlainSize;
  SI = BX.CRYPTESTDATA.BlowFishResult;
  DI = #CrypTestCiphered;
  IF (CrypTestCrypt)
     SI = BX.CRYPTESTDATA.PlainAddr;
  IF (COMP(SI,DI,CX))
     {
     $POP CX,CX
     AL = CrypTestCrypt * SIXTEEN + CrypTestCipherID;
     AH = DSBYTE[#CrypTestIndex];
     return(AX);
     }
  CrypTestCrypt ^= ONE;
  $POP CX
  ? ifdef codesize
    $LOOP CX_LOOP_3;
  ? else
    CX--;
    IF (NOTZEROFLAG)
       GOTO CX_LOOP_3;
  ? endif
? endif

? ifdef _TEST_TEA_
  CrypTestCipherID = TWO;
  CX = TWO;
 CX_LOOP_4:
  $PUSH CX

  $PUSH BX
  SI = BX.CRYPTESTDATA.KeyAddr;
  BL = BX.CRYPTESTDATA.KeySize;
  DI = CrypTestBuffer;
  TEA_INIT();
  $POP BX
  $PUSH BX
  ? ifdef cpu >= 3
    CX = BX.CRYPTESTDATA.PlainSize / EIGHT;
  ? else
    AX = BX.CRYPTESTDATA.PlainSize / EIGHT;
    ? ifdef codesize
      CX >< AX;
    ? else
      CX = AX;
    ? endif
  ? endif
  AL = TeaEncrypt;
  SI = BX.CRYPTESTDATA.PlainAddr;
  DI = #CrypTestCiphered;
  IF (CrypTestCrypt)
     {
     AX++;
     SI = DI;
     }
  TEA_CRYPT();
  $POP BX
  CX = BX.CRYPTESTDATA.PlainSize;
  SI = BX.CRYPTESTDATA.TeaResult;
  DI = #CrypTestCiphered;
  IF (CrypTestCrypt)
     SI = BX.CRYPTESTDATA.PlainAddr;
  IF (COMP(SI,DI,CX))
     {
     $POP CX,CX
     AL = CrypTestCrypt * SIXTEEN + CrypTestCipherID;
     AH = DSBYTE[#CrypTestIndex];
     return(AX);
     }
  CrypTestCrypt ^= ONE;
  $POP CX
  ? ifdef codesize
    $LOOP CX_LOOP_4;
  ? else
    CX--;
    IF (NOTZEROFLAG)
       GOTO CX_LOOP_4;
  ? endif
? endif


CrypTestIndex++;
$POP CX
/*** Because '$LOOP' generates compiler errors in some situations then we
     won't use it at all.
***/
CX--;
IF (NOTZEROFLAG)
   GOTO CX_LOOP_1;

return(OK);
}


? endif


/* end of CRYPTEST.H-- */

