-- Software implementation of DES

-- DESSoft.mesa

-- Andrew Birrell  16-Mar-82  8:43:23
-- Michael D. Schroeder, November 3, 1981  10:14 AM;

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



DESSoft: MONITOR 
    IMPORTS Inline, System
    EXPORTS DESFace
    SHARES DESFace

= BEGIN

OPEN DESFace;



-- Types --

IKey: TYPE = ARRAY [1..16] OF Bits48;

LeftShift28In: TYPE = MACHINE DEPENDENT RECORD
    [f1: [0..1], f2: [0..77777B], f3: [0..1], f4: [0..3777B], f5: [0..15]];

LeftShift28Out: TYPE = MACHINE DEPENDENT RECORD
    [f1: [0..77777B], f2: [0..1], f3: [0..3777B], f4: [0..1], f5: [0..15]];

Bits32: TYPE = MACHINE DEPENDENT RECORD
    [b1, b2, b3, b4, b5, b6, b7, b8,
     b9, b10, b11, b12, b13, b14, b15, b16,
     b17, b18, b19, b20, b21, b22, b23, b24,
     b25, b26, b27, b28, b29, b30, b31, b32: [0..1]];
PBits32: TYPE = POINTER TO Bits32;

Bits48: TYPE = MACHINE DEPENDENT RECORD
    [b1, b2, b3, b4, b5, b6, b7, b8,
     b9, b10, b11, b12, b13, b14, b15, b16,
     b17, b18, b19, b20, b21, b22, b23, b24,
     b25, b26, b27, b28, b29, b30, b31, b32,
     b33, b34, b35, b36, b37, b38, b39, b40,
     b41, b42, b43, b44, b45, b46, b47, b48: [0..1]];
PBits48: TYPE = POINTER TO Bits48;

Bits64: TYPE = MACHINE DEPENDENT RECORD
    [b1, b2, b3, b4, b5, b6, b7, b8,
     b9, b10, b11, b12, b13, b14, b15, b16,
     b17, b18, b19, b20, b21, b22, b23, b24,
     b25, b26, b27, b28, b29, b30, b31, b32,
     b33, b34, b35, b36, b37, b38, b39, b40,
     b41, b42, b43, b44, b45, b46, b47, b48,
     b49, b50, b51, b52, b53, b54, b55, b56,
     b57, b58, b59, b60, b61, b62, b63, b64: [0..1]];
PBits64: TYPE = POINTER TO Bits64;
LPBits64: TYPE = LONG POINTER TO Bits64;

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

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

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

Sixes: TYPE = MACHINE DEPENDENT RECORD
    [s1, s2: [0..63], s31: [0..15], s32: [0..3],
     s4, s5: [0..63], s61: [0..3], s62: [0..15], s7, s8: [0..63]];

Fours: TYPE = MACHINE DEPENDENT RECORD
    [f1, f2, f3, f4, f5, f6, f7, f8: [0..15]];

Sbox: TYPE = MACHINE DEPENDENT RECORD
    [f1, f2, f3, f4, f5, f6, f7, f8,
     f9, f10, f11, f12, f13, f14, f15, f16,
     f17, f18, f19, f20, f21, f22, f23, f24,
     f25, f26, f27, f28, f29, f30, f31, f32,
     f33, f34, f35, f36, f37, f38, f39, f40,
     f41, f42, f43, f44, f45, f46, f47, f48,
     f49, f50, f51, f52, f53, f54, f55, f56,
     f57, f58, f59, f60, f61, f62, f63, f64: [0..15]];



-- Constants --

shifts: ARRAY[1..16] OF CARDINAL =
    [1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1];

sbox1: Sbox = [
    14,0,4,15,13,7,1,4,2,14,15,2,11,13,8,1,
    3,10,10,6,6,12,12,11,5,9,9,5,0,3,7,8,
    4,15,1,12,14,8,8,2,13,4,6,9,2,1,11,7,
    15,5,12,11,9,3,7,14,3,10,10,0,5,6,0,13];
sbox2: Sbox = [
    15,3,1,13,8,4,14,7,6,15,11,2,3,8,4,14,
    9,12,7,0,2,1,13,10,12,6,0,9,5,11,10,5,
    0,13,14,8,7,10,11,1,10,3,4,15,13,4,1,2,
    5,11,8,6,12,7,6,12,9,0,3,5,2,14,15,9];
sbox3: Sbox = [
    10,13,0,7,9,0,14,9,6,3,3,4,15,6,5,10,
    1,2,13,8,12,5,7,14,11,12,4,11,2,15,8,1,
    13,1,6,10,4,13,9,0,8,6,15,9,3,8,0,7,
    11,4,1,15,2,14,12,3,5,11,10,5,14,2,7,12];
sbox4: Sbox = [
    7,13,13,8,14,11,3,5,0,6,6,15,9,0,10,3,
    1,4,2,7,8,2,5,12,11,1,12,10,4,14,15,9,
    10,3,6,15,9,0,0,6,12,10,11,1,7,13,13,8,
    15,9,1,4,3,5,14,11,5,12,2,7,8,2,4,14];
sbox5: Sbox = [
    2,14,12,11,4,2,1,12,7,4,10,7,11,13,6,1,
    8,5,5,0,3,15,15,10,13,3,0,9,14,8,9,6,
    4,11,2,8,1,12,11,7,10,1,13,14,7,2,8,13,
    15,6,9,15,12,0,5,9,6,10,3,4,0,5,14,3];
sbox6: Sbox = [
    12,10,1,15,10,4,15,2,9,7,2,12,6,9,8,5,
    0,6,13,1,3,13,4,14,14,0,7,11,5,3,11,8,
    9,4,14,3,15,2,5,12,2,9,8,5,12,15,3,10,
    7,11,0,14,4,1,10,7,1,6,13,0,11,8,6,13];
sbox7: Sbox = [
    4,13,11,0,2,11,14,7,15,4,0,9,8,1,13,10,
    3,14,12,3,9,5,7,12,5,2,10,15,6,8,1,6,
    1,6,4,11,11,13,13,8,12,1,3,4,7,10,14,7,
    10,9,15,5,6,0,8,15,0,14,5,2,9,3,2,12];
sbox8: Sbox = [
    13,1,2,15,8,13,4,8,6,10,15,3,11,7,1,4,
    10,12,9,5,3,6,14,11,5,0,0,14,12,9,7,2,
    7,2,11,1,4,14,1,7,9,4,12,10,14,8,2,13,
    0,15,6,12,10,9,13,0,15,3,3,5,5,6,8,11];



-- Procedures --

PermInitial: PROCEDURE[inP: LONG POINTER,
        outLeft, outRight: PBits32] = INLINE
BEGIN

OPEN in:LOOPHOLE[inP, LPBits64];

outLeft.b1 ← in.b58; outLeft.b2 ← in.b50; outLeft.b3 ← in.b42; outLeft.b4 ← in.b34;
outLeft.b5 ← in.b26; outLeft.b6 ← in.b18; outLeft.b7 ← in.b10; outLeft.b8 ← in.b2;
outLeft.b9 ← in.b60; outLeft.b10 ← in.b52; outLeft.b11 ← in.b44; outLeft.b12 ← in.b36;
outLeft.b13 ← in.b28; outLeft.b14 ← in.b20; outLeft.b15 ← in.b12; outLeft.b16 ← in.b4;
outLeft.b17 ← in.b62; outLeft.b18 ← in.b54; outLeft.b19 ← in.b46; outLeft.b20 ← in.b38;
outLeft.b21 ← in.b30; outLeft.b22 ← in.b22; outLeft.b23 ← in.b14; outLeft.b24 ← in.b6;
outLeft.b25 ← in.b64; outLeft.b26 ← in.b56; outLeft.b27 ← in.b48; outLeft.b28 ← in.b40;
outLeft.b29 ← in.b32; outLeft.b30 ← in.b24; outLeft.b31 ← in.b16; outLeft.b32 ← in.b8;

outRight.b1 ← in.b57; outRight.b2 ← in.b49; outRight.b3 ← in.b41; outRight.b4 ← in.b33;
outRight.b5 ← in.b25; outRight.b6 ← in.b17; outRight.b7 ← in.b9; outRight.b8 ← in.b1;
outRight.b9 ← in.b59; outRight.b10 ← in.b51; outRight.b11 ← in.b43; outRight.b12 ← in.b35;
outRight.b13 ← in.b27; outRight.b14 ← in.b19; outRight.b15 ← in.b11; outRight.b16 ← in.b3;
outRight.b17 ← in.b61; outRight.b18 ← in.b53; outRight.b19 ← in.b45; outRight.b20 ← in.b37;
outRight.b21 ← in.b29; outRight.b22 ← in.b21; outRight.b23 ← in.b13; outRight.b24 ← in.b5;
outRight.b25 ← in.b63; outRight.b26 ← in.b55; outRight.b27 ← in.b47; outRight.b28 ← in.b39;
outRight.b29 ← in.b31; outRight.b30 ← in.b23; outRight.b31 ← in.b15; outRight.b32 ← in.b7;

END;



PermInverseInitial: PROCEDURE[inLeft, inRight: PBits32,
        outLP: LONG POINTER] = INLINE
BEGIN

OPEN out:LOOPHOLE[outLP, LPBits64];

out.b1 ← inRight.b8; out.b2 ← inLeft.b8; out.b3 ← inRight.b16; out.b4 ← inLeft.b16;
out.b5 ← inRight.b24; out.b6 ← inLeft.b24; out.b7 ← inRight.b32; out.b8 ← inLeft.b32;
out.b9 ← inRight.b7; out.b10 ← inLeft.b7; out.b11 ← inRight.b15; out.b12 ← inLeft.b15;
out.b13 ← inRight.b23; out.b14 ← inLeft.b23; out.b15 ← inRight.b31; out.b16 ← inLeft.b31;
out.b17 ← inRight.b6; out.b18 ← inLeft.b6; out.b19 ← inRight.b14; out.b20 ← inLeft.b14;
out.b21 ← inRight.b22; out.b22 ← inLeft.b22; out.b23 ← inRight.b30; out.b24 ← inLeft.b30;
out.b25 ← inRight.b5; out.b26 ← inLeft.b5; out.b27 ← inRight.b13; out.b28 ← inLeft.b13;
out.b29 ← inRight.b21; out.b30 ← inLeft.b21; out.b31 ← inRight.b29; out.b32 ← inLeft.b29;
out.b33 ← inRight.b4; out.b34 ← inLeft.b4; out.b35 ← inRight.b12; out.b36 ← inLeft.b12;
out.b37 ← inRight.b20; out.b38 ← inLeft.b20; out.b39 ← inRight.b28; out.b40 ← inLeft.b28;
out.b41 ← inRight.b3; out.b42 ← inLeft.b3; out.b43 ← inRight.b11; out.b44 ← inLeft.b11;
out.b45 ← inRight.b19; out.b46 ← inLeft.b19; out.b47 ← inRight.b27; out.b48 ← inLeft.b27;
out.b49 ← inRight.b2; out.b50 ← inLeft.b2; out.b51 ← inRight.b10; out.b52 ← inLeft.b10;
out.b53 ← inRight.b18; out.b54 ← inLeft.b18; out.b55 ← inRight.b26; out.b56 ← inLeft.b26;
out.b57 ← inRight.b1; out.b58 ← inLeft.b1; out.b59 ← inRight.b9; out.b60 ← inLeft.b9;
out.b61 ← inRight.b17; out.b62 ← inLeft.b17; out.b63 ← inRight.b25; out.b64 ← inLeft.b25;

END;



PermP: PROCEDURE[in, out: PBits32] = INLINE
BEGIN

out.b1 ← in.b16; out.b2 ← in.b7; out.b3 ← in.b20; out.b4 ← in.b21;
out.b5 ← in.b29; out.b6 ← in.b12; out.b7 ← in.b28; out.b8 ← in.b17;
out.b9 ← in.b1; out.b10 ← in.b15; out.b11 ← in.b23; out.b12 ← in.b26;
out.b13 ← in.b5; out.b14 ← in.b18; out.b15 ← in.b31; out.b16 ← in.b10;
out.b17 ← in.b2; out.b18 ← in.b8; out.b19 ← in.b24; out.b20 ← in.b14;
out.b21 ← in.b32; out.b22 ← in.b27; out.b23 ← in.b3; out.b24 ← in.b9;
out.b25 ← in.b19; out.b26 ← in.b13; out.b27 ← in.b30; out.b28 ← in.b6;
out.b29 ← in.b22; out.b30 ← in.b11; out.b31 ← in.b4; out.b32 ← in.b25;

END;



PermE: PROCEDURE[in: PBits32, out: PBits48] = INLINE
BEGIN

out.b1 ← out.b47 ← in.b32;
out.b2 ← out.b48 ← in.b1;
out.b3 ← in.b2;
out.b4 ← in.b3;
out.b5 ← out.b7 ← in.b4;
out.b6 ← out.b8 ← in.b5;
out.b9 ← in.b6;
out.b10 ← in.b7;
out.b11 ← out.b13 ← in.b8;
out.b12 ← out.b14 ← in.b9;
out.b15 ← in.b10;
out.b16 ← in.b11;
out.b17 ← out.b19 ← in.b12;
out.b18 ← out.b20 ← in.b13;
out.b21 ← in.b14;
out.b22 ← in.b15;
out.b23 ← out.b25 ← in.b16;
out.b24 ← out.b26 ← in.b17;
out.b27 ← in.b18;
out.b28 ← in.b19;
out.b29 ← out.b31 ← in.b20;
out.b30 ← out.b32 ← in.b21;
out.b33 ← in.b22;
out.b34 ← in.b23;
out.b35 ← out.b37 ← in.b24;
out.b36 ← out.b38 ← in.b25;
out.b39 ← in.b26;
out.b40 ← in.b27;
out.b41 ← out.b43 ← in.b28;
out.b42 ← out.b44 ← in.b29;
out.b45 ← in.b30;
out.b46 ← in.b31;


END;



PermPC1: PROCEDURE[inP: POINTER, outC, outD: PBits32] = INLINE
BEGIN

OPEN in:LOOPHOLE[inP, PBits64];

-- converts 64 bit key into two 28 bit key parts.  (Only first 28 bits of outputs are set)

outC.b1 ← in.b57; outC.b2 ← in.b49; outC.b3 ← in.b41; outC.b4 ← in.b33;
outC.b5 ← in.b25; outC.b6 ← in.b17; outC.b7 ← in.b9; outC.b8 ← in.b1;
outC.b9 ← in.b58; outC.b10 ← in.b50; outC.b11 ← in.b42; outC.b12 ← in.b34;
outC.b13 ← in.b26; outC.b14 ← in.b18; outC.b15 ← in.b10; outC.b16 ← in.b2;
outC.b17 ← in.b59; outC.b18 ← in.b51; outC.b19 ← in.b43; outC.b20 ← in.b35;
outC.b21 ← in.b27; outC.b22 ← in.b19; outC.b23 ← in.b11; outC.b24 ← in.b3;
outC.b25 ← in.b60; outC.b26 ← in.b52; outC.b27 ← in.b44; outC.b28 ← in.b36;

outD.b1 ← in.b63; outD.b2 ← in.b55; outD.b3 ← in.b47; outD.b4 ← in.b39;
outD.b5 ← in.b31; outD.b6 ← in.b23; outD.b7 ← in.b15; outD.b8 ← in.b7;
outD.b9 ← in.b62; outD.b10 ← in.b54; outD.b11 ← in.b46; outD.b12 ← in.b38;
outD.b13 ← in.b30; outD.b14 ← in.b22; outD.b15 ← in.b14; outD.b16 ← in.b6;
outD.b17 ← in.b61; outD.b18 ← in.b53; outD.b19 ← in.b45; outD.b20 ← in.b37;
outD.b21 ← in.b29; outD.b22 ← in.b21; outD.b23 ← in.b13; outD.b24 ← in.b5;
outD.b25 ← in.b28; outD.b26 ← in.b20; outD.b27 ← in.b12; outD.b28 ← in.b4;

END;



PermPC2: PROCEDURE[inC, inD: PBits32, out: PBits48] = INLINE
BEGIN

out.b1 ← inC.b14; out.b2 ← inC.b17; out.b3 ← inC.b11; out.b4 ← inC.b24;
out.b5 ← inC.b1; out.b6 ← inC.b5; out.b7 ← inC.b3; out.b8 ← inC.b28;
out.b9 ← inC.b15; out.b10 ← inC.b6; out.b11 ← inC.b21; out.b12 ← inC.b10;
out.b13 ← inC.b23; out.b14 ← inC.b19; out.b15 ← inC.b12; out.b16 ← inC.b4;
out.b17 ← inC.b26; out.b18 ← inC.b8; out.b19 ← inC.b16; out.b20 ← inC.b7;
out.b21 ← inC.b27; out.b22 ← inC.b20; out.b23 ← inC.b13; out.b24 ← inC.b2;

out.b25 ← inD.b13; out.b26 ← inD.b24; out.b27 ← inD.b3; out.b28 ← inD.b9;
out.b29 ← inD.b19; out.b30 ← inD.b27; out.b31 ← inD.b2; out.b32 ← inD.b12;
out.b33 ← inD.b23; out.b34 ← inD.b17; out.b35 ← inD.b5; out.b36 ← inD.b20;
out.b37 ← inD.b16; out.b38 ← inD.b21; out.b39 ← inD.b11; out.b40 ← inD.b28;
out.b41 ← inD.b6; out.b42 ← inD.b25; out.b43 ← inD.b18; out.b44 ← inD.b14;
out.b45 ← inD.b22; out.b46 ← inD.b8; out.b47 ← inD.b1; out.b48 ← inD.b4;


END;



XOR32: PROCEDURE[a, b, out: PBits32]  = INLINE
BEGIN

OPEN
  aP: LOOPHOLE[a, POINTER TO Words2],
  bP: LOOPHOLE[b, POINTER TO Words2],
  outP: LOOPHOLE[out, POINTER TO Words2];

outP.w1 ← Inline.BITXOR[aP.w1, bP.w1];
outP.w2 ← Inline.BITXOR[aP.w2, bP.w2];

END;



XOR48: PROCEDURE[a, b, out: PBits48] = INLINE
BEGIN

OPEN
  aP: LOOPHOLE[a, POINTER TO Words3],
  bP: LOOPHOLE[b, POINTER TO Words3],
  outP: LOOPHOLE[out, POINTER TO Words3];

outP.w1 ← Inline.BITXOR[aP.w1, bP.w1];
outP.w2 ← Inline.BITXOR[aP.w2, bP.w2];
outP.w3 ← Inline.BITXOR[aP.w3, bP.w3];

END;



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;



LeftShift28: PROCEDURE[aP: PBits32] = INLINE
BEGIN

OPEN
  inP: LOOPHOLE[aP, POINTER TO LeftShift28In];

temp32: Bits32;
outP: POINTER TO LeftShift28Out = LOOPHOLE[@temp32];

outP.f1 ← inP.f2;
outP.f2 ← inP.f3;
outP.f3 ← inP.f4;
outP.f4 ← inP.f1;

aP↑ ← temp32;

END;



SMap: PROCEDURE[in: PBits48, out: PBits32] = INLINE
BEGIN

OPEN
    inP: LOOPHOLE[in, POINTER TO Sixes],
    outP: LOOPHOLE[out, POINTER TO Fours];

sbox: Sbox;
sboxP: POINTER = @sbox;

sbox ← sbox1;
outP.f1 ← Map[sboxP, inP.s1];
sbox ← sbox2;
outP.f2 ← Map[sboxP, inP.s2];
sbox ← sbox3;
outP.f3 ← Map[sboxP, inP.s31*4+inP.s32];
sbox ← sbox4;
outP.f4 ← Map[sboxP, inP.s4];
sbox ← sbox5;
outP.f5 ← Map[sboxP, inP.s5];
sbox ← sbox6;
outP.f6 ← Map[sboxP, inP.s61*16+inP.s62];
sbox ← sbox7;
outP.f7 ← Map[sboxP, inP.s7];
sbox ← sbox8;
outP.f8 ← Map[sboxP, inP.s8];

END;



Map: PROCEDURE[p: POINTER, b: [0..63]]
    RETURNS[[0..15]] = MACHINE CODE
BEGIN

Mopcodes.zLI6;
Mopcodes.zSHIFT;
Mopcodes.zLI3;
Mopcodes.zADD;
Mopcodes.zRFS;

END;


cachedKey: Key;
cachedIKey: IKey;
noKeyCached: BOOLEAN ← TRUE;

BadParity: ERROR = CODE;

InternalizeKey: ENTRY PROC [keyP: POINTER TO Key,
        iKeyP: POINTER TO IKey] =
BEGIN

IF noKeyCached OR cachedKey # keyP↑ THEN
  BEGIN
  c, d: Bits32; cP: PBits32 = @c; dP: PBits32 = @d;
  FOR i: CARDINAL IN [0..7] DO
    IF keyP[i].p # parityTable[keyP[i].b]
      THEN RETURN WITH ERROR BadParity;
    ENDLOOP;
  cachedKey ← keyP↑;
  PermPC1[keyP,  cP, dP];
  FOR i: CARDINAL IN [1..16] DO
    THROUGH [1..shifts[i]] DO LeftShift28[cP]; LeftShift28[dP]; ENDLOOP;
    PermPC2[cP,dP,@cachedIKey[i]];
    ENDLOOP;
  noKeyCached ← FALSE;
  END;

iKeyP↑ ← cachedIKey;

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;
iKey: IKey;
iKeyP: POINTER TO IKey = @iKey;
iKeyStart: INTEGER = IF (direction=encrypt) THEN 1 ELSE 16;
iKeyIncr: INTEGER = IF (direction=encrypt) THEN 1 ELSE -1;
temp32: Bits32;
temp32Ptr: PBits32 = @temp32;
otherTemp32: Bits32;
otherTemp32Ptr: PBits32 = @otherTemp32;
left32: Bits32;
left32Ptr: PBits32 = @left32;
right32: Bits32;
right32Ptr: PBits32 = @right32;
temp48: Bits48;
temp48Ptr: PBits48 = @temp48;

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, iKeyP];
  FOR blk: CARDINAL IN [0 .. nBlks) DO
    i: INTEGER ← iKeyStart;
    IF mode#ecb THEN
      IF direction=encrypt
        THEN XOR64[@from[blk], seedP, @from[blk]]
        ELSE newSeed ← from[blk];
    PermInitial[@from[blk], left32Ptr, right32Ptr];
    THROUGH [1..16] DO  -- main encryption loop
      temp32 ← right32;  -- save old right half
      PermE[right32Ptr, temp48Ptr];  -- E permutation
      XOR48[temp48Ptr, @iKeyP[i], temp48Ptr];  -- XOR with key array element
      SMap[temp48Ptr, right32Ptr];  -- apply the SBoxes
      PermP[right32Ptr, otherTemp32Ptr];  -- P permutation
      XOR32[left32Ptr, otherTemp32Ptr, right32Ptr];
      left32 ← temp32;
      i ← i + iKeyIncr;
      ENDLOOP;
    PermInverseInitial[right32Ptr, left32Ptr, @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--


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
  ];


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

GetRandomIV: PUBLIC PROCEDURE RETURNS [iv: IV] =
  BEGIN
  -- Ideally, this should use a true random number generator --
  prevSeed: Block ← randomSeed;
  temp: Block;
  pulse: POINTER TO LONG CARDINAL = LOOPHOLE[@randomSeed];
  seedKey: POINTER TO Key = LOOPHOLE[@randomSeed];
  -- randomSeed ← slightly different one --
  -- This introduces a small number of bits of randomness --
  pulse↑ ← pulse↑ + System.GetClockPulses[];
  -- randomSeed ← [0] encrypted with adjusted randomSeed --
  -- This disperses the randomised bits --
  temp ← [0,0,0,0];
  CorrectParity[seedKey];
  CryptData[keyP: seedKey, nBlks: 1,
            from: LOOPHOLE[LONG[@temp], Blocks],
	    to:   LOOPHOLE[LONG[@randomSeed], Blocks],
            direction: encrypt, mode: ecb, seedP: NIL];
  -- k ← prevSeed encrypted with randomSeed --
  -- So that knowing K doesn't make randomSeed vulnerable to plain-text attack --
  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

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--