-- Dummy implementation of DES

-- DESDummy.mesa

-- Andrew Birrell   

DIRECTORY
DESFace,
Inline		USING[ BITXOR ],
System		USING[ GetClockPulses ];



DESDummy: MONITOR 
    IMPORTS Inline, System
    EXPORTS DESFace
    SHARES DESFace

= BEGIN

OPEN DESFace;


Words4: TYPE = MACHINE DEPENDENT RECORD[w1, w2, w3, w4: WORD];

XOR64: PROCEDURE[a, b, out: LONG POINTER] = INLINE
  BEGIN
  OPEN
    aLP: LOOPHOLE[a, LONG POINTER TO Words4],
    bLP: LOOPHOLE[b, LONG POINTER TO Words4],
    outP: LOOPHOLE[out, LONG POINTER TO Words4];
  outP.w1 ← Inline.BITXOR[aLP.w1, bLP.w1];
  outP.w2 ← Inline.BITXOR[aLP.w2, bLP.w2];
  outP.w3 ← Inline.BITXOR[aLP.w3, bLP.w3];
  outP.w4 ← Inline.BITXOR[aLP.w4, bLP.w4];
  END;

Words2: TYPE = MACHINE DEPENDENT RECORD[w1, w2: WORD];

XOR32: PROCEDURE[a, b: LONG UNSPECIFIED, out: POINTER]  = INLINE
  BEGIN
  OPEN
    aP: LOOPHOLE[a, Words2],
    bP: LOOPHOLE[b, Words2],
    outP: LOOPHOLE[out, POINTER TO Words2];
  outP.w1 ← Inline.BITXOR[aP.w1, bP.w1];
  outP.w2 ← Inline.BITXOR[aP.w2, bP.w2];
  END;




cachedKey: Key;
noKeyCached: BOOLEAN ← TRUE;

BadParity: ERROR = CODE;

InternalizeKey: ENTRY PROC [keyP: POINTER TO Key] =
  BEGIN
  IF noKeyCached OR cachedKey # keyP↑ THEN
    BEGIN
    FOR i: CARDINAL IN [0..7] DO
      IF keyP[i].p # parityTable[keyP[i].b]
        THEN RETURN WITH ERROR BadParity;
      ENDLOOP;
    cachedKey ← keyP↑;
    noKeyCached ← FALSE;
    END;
  END; --InternalizeKey--

NotImplemented: ERROR = CODE;

CryptData: PUBLIC PROCEDURE [keyP: POINTER TO Key, nBlks: CARDINAL,
        from, to: Blocks, direction: Direction, mode: Mode,
        seedP: LONG POINTER TO IV ← NIL] =
  BEGIN

  newSeed: IV;

  IF mode = checksum THEN ERROR NotImplemented;

  IF mode = cbcCheck AND direction = encrypt AND nBlks > 0
  THEN BEGIN
       FOR blk: CARDINAL IN [0..nBlks-1)
       DO XOR64[@from[nBlks-1], @from[blk], @from[nBlks-1]] ENDLOOP;
       END;

  InternalizeKey[keyP];
  FOR blk: CARDINAL IN [0 .. nBlks) DO
    IF mode#ecb THEN
      IF direction=encrypt
        THEN XOR64[@from[blk], seedP, @from[blk]]
        ELSE newSeed ← from[blk];
    XOR64[keyP, @from[blk], @to[blk]];
    IF mode#ecb THEN
      IF direction=encrypt
        THEN seedP ← @to[blk]
        ELSE {XOR64[@to[blk], seedP, @to[blk]]; seedP↑ ← newSeed};
    ENDLOOP;

  IF mode = cbcCheck AND direction = decrypt AND nBlks > 0
  THEN BEGIN
       FOR blk: CARDINAL IN [0..nBlks-1)
       DO XOR64[@to[nBlks-1], @to[blk], @to[nBlks-1]] ENDLOOP;
       END

  END; --CryptData--


randomSeed: Block ← [1,2,3,4];

GetRandomIV: PUBLIC PROCEDURE RETURNS [iv: IV] =
  BEGIN
  -- Ideally, this should use a true random number generator --
  prevSeed: Block ← randomSeed;
  pulse1: POINTER TO LONG CARDINAL = LOOPHOLE[@randomSeed[0]];
  pulse2: POINTER TO LONG CARDINAL = LOOPHOLE[@randomSeed[2]];
  seedKey: POINTER TO Key = LOOPHOLE[@randomSeed];
  pulse1↑ ← pulse1↑ + System.GetClockPulses[];
  XOR32[pulse2↑, System.GetClockPulses[], pulse2];
  CorrectParity[seedKey];
  CryptData[keyP: seedKey, nBlks: 1,
            from: LOOPHOLE[LONG[@prevSeed], Blocks],
	    to:   LOOPHOLE[LONG[@iv], Blocks],
            direction: encrypt, mode: ecb, seedP: NIL];
  END; --GetRandomIV--

GetRandomKey: PUBLIC PROCEDURE RETURNS [k: Key] =
  BEGIN
  k ← LOOPHOLE[GetRandomIV[]];
  CorrectParity[@k];
  END; --GetRandomKey--


MakeKey: PUBLIC PROCEDURE [source: LONG STRING]
    RETURNS [key: Key] =
  BEGIN

  -- User interface routine to construct a 64 bit key from an ASCII string.
  -- "key" is an array that holds the 64 bit key.
  -- Note: every eighth bit of "key" is an odd parity bit for the preceeding seven bits.

  key ← nullKey;

  FOR i: CARDINAL IN [0..source.length) DO
    j: CARDINAL = i MOD 8;
    c: CHARACTER = IF source[i] IN ['A..'Z] THEN 'a + (source[i]-'A) ELSE source[i];
    key[j].b ← Inline.BITXOR[LOOPHOLE[c, [0 .. 127]], key[j].b];
  ENDLOOP;

  CorrectParity[@key];

  END; -- MakeKey

parityTable: PACKED ARRAY [0..127] OF [0..1] ← [
  1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
  0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
  0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
  1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
  0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
  1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
  1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
  0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
  ];


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

[] ← GetRandomKey[];


END. --DES--