-- Copyright (C) 1983, 1984  by Xerox Corporation. All rights reserved. 
-- DESAux.mesa
-- JMaloney, 19-Jul-83 19:07:45.

-- Last modified: JMaloney, 23-Feb-84 21:06:04.

-- Software implementation of DES Face operations which would not
-- normally be implemented in uCode.

DIRECTORY
  DESFace USING [Block, DecryptBlock, EncryptBlock, IV, Key, parityTable],
  System USING [GetClockPulses];

DESAux: MONITOR
  IMPORTS System, DESFace
  EXPORTS DESFace =
  BEGIN


-- Random Block Generator --


randomSeed: DESFace.Block ← [0, 0, 0, 0];

MakeRandomBlock: ENTRY PROC
  RETURNS [rand: DESFace.Block] =
  -- Ideally, this should use a true random number generator
  BEGIN
    prevSeed: DESFace.Block ← randomSeed;
    zero: DESFace.Block ← [0, 0, 0, 0];
    seedKey: POINTER TO DESFace.Key = LOOPHOLE[@randomSeed];
    BEGIN
    -- randomSeed ← slightly different one
    -- This introduces a small number of bits of randomness
      pulse: POINTER TO LONG CARDINAL = LOOPHOLE[@randomSeed];
      pulse↑ ← pulse↑ + System.GetClockPulses[];
    END;
  -- randomSeed ← [0] encrypted with adjusted randomSeed
  -- This disperses the randomized bits
    CorrectParity[seedKey];
    DESFace.EncryptBlock[
      key: seedKey↑, from: LOOPHOLE[LONG[@zero]],
      to: LOOPHOLE[LONG[@randomSeed]]];
  -- rand ← prevSeed encrypted with randomSeed
  -- So that knowing rand doesn't make randomSeed vulnerable to plain-text attack
    CorrectParity[seedKey];
    DESFace.EncryptBlock[
      key: seedKey↑, from: LOOPHOLE[LONG[@prevSeed]],
      to: LOOPHOLE[LONG[@rand]]];
  END;


-- Public procedures --


GetRandomIV: PUBLIC PROC RETURNS [iVector: DESFace.IV] =
  BEGIN
    iVector ← MakeRandomBlock[];
  END;

GetRandomKey: PUBLIC PROC RETURNS [key: DESFace.Key] =
  BEGIN
    key ← LOOPHOLE[MakeRandomBlock[]];
    CorrectParity[@key];
  END;

CheckKeyParity: PUBLIC PROC [keyP: LONG POINTER TO DESFace.Key]
  RETURNS [ok: BOOLEAN ← TRUE] =
  BEGIN
    FOR i: CARDINAL IN [0..7] DO
      IF keyP[i].p # DESFace.parityTable[keyP[i].b] THEN RETURN[FALSE];
    ENDLOOP;
  END;

CorrectParity: PUBLIC PROC [keyP: LONG POINTER TO DESFace.Key] =
  BEGIN
    FOR i: CARDINAL IN [0..7] DO
      keyP[i].p ← DESFace.parityTable[keyP[i].b];
    ENDLOOP;
  END;

-- Data for NBS Acceptance Tests
  -- This data exercises every S-Box Entry.
  -- Source: Federal Register, XXX. (I got them from Andrew Birrell.)
  -- Values in Hex:
  --      (Key)		     (Data)		(Cipher)
  -- 7CA110454A1A6E57   01A1D6D039776742   690F5B0D9A26939B
  -- 0131D9619DC1376E   5CD54CA83DEF57DA   7A389D10354BD271
  -- 07A1133E4A0B2686   0248D43806F67172   868EBB51CAB4599A
  -- 3849674C2602319E   51454B582DDF440A   7178876E01F19B2A
  -- 04B915BA43FEB5B6   42FD443059577FA2   AF37FB421F8C4095
  -- 0113B970FD34F2CE   059B5E0851CF143A   86A560F10EC6D85B
  -- 0170F175468FB5E6   0756D8E0774761D2   0CD3DA020021DC09
  -- 43297FAD38E373FE   762514B829BF486A   EA676B2CB7DB2B7A
  -- 07A7137045DA2A16   3BDD119049372802   DFD64A815CAF1A0F
  -- 04689104C2FD3B2F   26955F6835AF609A   5C513C9C4886C088
  -- 37D06BB516CB7546   164D5E404F275232   0A2AEEAE3FF4AB77
  -- 1F08260D1AC2465E   6B056E18759F5CCA   EF1BF03E5DFA575A
  -- 584023641ABA6176   004BD6EF09176062   88BF0DB6D70DEE56
  -- 025816164629B007   480D39006EE762F2   A1F9915541020B56
  -- 49793EBC79B3258F   437540C8698F3CFA   6FBF1CAFCFFD0556
  -- 4FB05E1515AB73A7   072D43A077075292   2F22E49BAB7CA1AC
  -- 49E95D6D4CA229BF   02FE55778117F12A   5A6B612CC26CCE4A
  -- 018310DC409B26D6   1D9D5C5018F728C2   5F4C038ED12B2E41
  -- 1C587F1C13924FEF   305532286D6F295A   63FAC0D034D9F793
  -- 0101010101010101   AAAAAAAAAAAAAAAA   3AE716954DC04E25
  -- 0101010101010101   0000000000000000   8CA64DE9C1B123A7

ValidateEncryptionHardware: PUBLIC PROC RETURNS [ok: BOOLEAN ← TRUE] =
  BEGIN
    Block: TYPE = DESFace.Block;
    BlocksEqual: PROC [a, b: POINTER TO Block]
      RETURNS [equal: BOOLEAN] =
      BEGIN
	equal ←
	  a[0] = b[0] AND
	  a[1] = b[1] AND
	  a[2] = b[2] AND
	  a[3] = b[3];
      END;

  keySequence: ARRAY [1..21] OF Block ← [
    Block[76241B, 10105B, 45032B, 67127B],
    Block[461B, 154541B, 116701B, 33556B],
    Block[3641B, 11476B, 45013B, 23206B],
    Block[34111B, 63514B, 23002B, 30636B],
    Block[2271B, 12672B, 41776B, 132666B],
    Block[423B, 134560B, 176464B, 171316B],
    Block[560B, 170565B, 43217B, 132746B],
    Block[41451B, 77655B, 34343B, 71776B],
    Block[3647B, 11560B, 42732B, 25026B],
    Block[2150B, 110404B, 141375B, 35457B],
    Block[33720B, 65665B, 13313B, 72506B],
    Block[17410B, 23015B, 15302B, 43136B],
    Block[54100B, 21544B, 15272B, 60566B],
    Block[1130B, 13026B, 43051B, 130007B],
    Block[44571B, 37274B, 74663B, 22617B],
    Block[47660B, 57025B, 12653B, 71647B],
    Block[44751B, 56555B, 46242B, 24677B],
    Block[603B, 10334B, 40233B, 23326B],
    Block[16130B, 77434B, 11622B, 47757B],
    Block[401B, 401B, 401B, 401B],
    Block[401B, 401B, 401B, 401B]];
  dataSequence: ARRAY [1..21] OF Block ← [
    Block[641B, 153320B, 34567B, 63502B],
    Block[56325B, 46250B, 36757B, 53732B],
    Block[1110B, 152070B, 3366B, 70562B],
    Block[50505B, 45530B, 26737B, 42012B],
    Block[41375B, 42060B, 54527B, 77642B],
    Block[2633B, 57010B, 50717B, 12072B],
    Block[3526B, 154340B, 73507B, 60722B],
    Block[73045B, 12270B, 24677B, 44152B],
    Block[35735B, 10620B, 44467B, 24002B],
    Block[23225B, 57550B, 32657B, 60232B],
    Block[13115B, 57100B, 47447B, 51062B],
    Block[65405B, 67030B, 72637B, 56312B],
    Block[113B, 153357B, 4427B, 60142B],
    Block[44015B, 34400B, 67347B, 61362B],
    Block[41565B, 40310B, 64617B, 36372B],
    Block[3455B, 41640B, 73407B, 51222B],
    Block[1376B, 52567B, 100427B, 170452B],
    Block[16635B, 56120B, 14367B, 24302B],
    Block[30125B, 31050B, 66557B, 24532B],
    Block[125252B, 125252B, 125252B, 125252B],
    Block[0B, 0B, 0B, 0B]];
  cipherSequence: ARRAY [1..21] OF Block ← [
    Block[64417B, 55415B, 115046B, 111633B],
    Block[75070B, 116420B, 32513B, 151161B],
    Block[103216B, 135521B, 145264B, 54632B],
    Block[70570B, 103556B, 761B, 115452B],
    Block[127467B, 175502B, 17614B, 40225B],
    Block[103245B, 60361B, 7306B, 154133B],
    Block[6323B, 155002B, 41B, 156011B],
    Block[165147B, 65454B, 133733B, 25572B],
    Block[157726B, 45201B, 56257B, 15017B],
    Block[56121B, 36234B, 44206B, 140210B],
    Block[5052B, 167256B, 37764B, 125567B],
    Block[167433B, 170076B, 56772B, 53532B],
    Block[104277B, 6666B, 153415B, 167126B],
    Block[120771B, 110525B, 40402B, 5526B],
    Block[67677B, 16257B, 147775B, 2526B],
    Block[27442B, 162233B, 125574B, 120654B],
    Block[55153B, 60454B, 141154B, 147112B],
    Block[57514B, 1616B, 150453B, 27101B],
    Block[61772B, 140320B, 32331B, 173623B],
    Block[35347B, 13225B, 46700B, 47045B],
    Block[106246B, 46751B, 140661B, 21647B]];

    testBlock: Block;
    FOR i: CARDINAL IN [1..21] DO
      testBlock ← dataSequence[i];
      DESFace.EncryptBlock[
	key: LOOPHOLE[keySequence[i]],
	from: LOOPHOLE[LONG[@testBlock]], to: LOOPHOLE[LONG[@testBlock]]];
      IF ~BlocksEqual[@testBlock, @cipherSequence[i]]
	THEN RETURN[ok: FALSE];
      DESFace.DecryptBlock[
	key: LOOPHOLE[keySequence[i]],
	from: LOOPHOLE[LONG[@testBlock]], to: LOOPHOLE[LONG[@testBlock]]];
      IF ~BlocksEqual[@testBlock, @dataSequence[i]]
	THEN RETURN[ok: FALSE];
    ENDLOOP;
  END;


  END.


LOG

May 12, 1983 -- JMaloney -- Created from old CryptImpl.
May 16, 1983 -- JMaloney -- Fixed CorrectParity.
May 31, 1983 -- JMaloney -- Use Andrew's random block generator.
July 19, 1983 -- JMaloney -- Use DESFace.parityTable.
October 31, 1983 -- JMaloney -- Flush references to DESFaceExtras.
January 20, 1984 -- JMaloney -- Added BadDESHardware, ValidateEncryptionHardware.
January 23, 1984 -- JMaloney -- Removed BadDESHardware.
January 30, 1984 -- JMaloney -- Removed MakeKey.
February 23, 1984 -- JMaloney -- Moved CheckKeyParity here from DESSoft.


OldMakeKey: PUBLIC PROC [source: LONG STRING] RETURNS [key: DESFace.Key] =
  -- Constructs a 64 bit key from an ASCII string.
  -- Note: high bit of each character is ignored by the encryption algorithm;
  -- it is an odd parity bit for the other seven bits of the character.
  -- NOTE: This implementation is INTERIM!!!
  BEGIN
    fourWords: ARRAY [1..4] OF UNSPECIFIED;
    keyIndex: [1..4];

    fourWords ← [0,0,0,0];
    FOR charIndex: CARDINAL IN [0..source.length) DO
      bitShift: [0..15];
      circle, r: UNSPECIFIED;

      circle ← LOOPHOLE[(source[charIndex] - Ascii.NUL) MOD 128, UNSPECIFIED];
      bitShift ← (9*(charIndex + 1)) MOD 16;
      circle ← Inline.BITROTATE[circle, bitShift];
      keyIndex ← ((charIndex)*7)/16 MOD 4 + 1;
      IF bitShift IN [2..9] THEN
	fourWords[keyIndex] ← Inline.BITXOR[fourWords[keyIndex], circle]
      ELSE
	BEGIN
	  fourWords[keyIndex] ← Inline.BITXOR[
	    fourWords[keyIndex], Inline.LowByte[circle]];
	  r ← Inline.HighByte[circle] * 256;
	  IF keyIndex = 4 THEN fourWords[1] ← Inline.BITXOR[fourWords[1], r]
	  ELSE fourWords[keyIndex + 1] ←
	    Inline.BITXOR[fourWords[keyIndex + 1], r];
	END;
    ENDLOOP;

    key ← LOOPHOLE[fourWords];
    CorrectParity[@key];
  END;