-- MESA access the DES encryption facilities

-- DESFace.mesa

-- Andrew Birrell  16-Mar-82  8:36:51
-- Michael D. Schroeder, October 30, 1981  3:11 PM


DESFace: DEFINITIONS = BEGIN


-- Public types and constants

Block:		TYPE = ARRAY [0 .. 3] OF UNSPECIFIED;
  -- plain or cipher text block --

Blocks:		TYPE = LONG POINTER TO ARRAY OF Block;

Key:		TYPE = PACKED ARRAY [0 .. 7] OF
		MACHINE DEPENDENT RECORD[b: [0 .. 127], p: [0 .. 1]];

nullKey:	Key = ALL[[b:0, p:0]];
  -- Note that this has incorrect parity --

IV:		TYPE = Block;
  -- Initialization vector for CBC --



-- Key and IV generation and conversion

GetRandomIV:	PROC RETURNS [IV];

GetRandomKey:	PROC RETURNS [Key];
  -- Returns pseudo-random or random key (depending on
  -- available hardware), with odd parity --

MakeKey:	PROC[ source: LONG STRING ]
		RETURNS [Key];
  -- Canonical conversion of characters into key;
  -- Parity bits are set to odd parity. --

CorrectParity:	PROC[keyP: LONG POINTER TO Key];
  -- Forces parity bits of keyP↑ to odd parity --



-- Single-block encryption and decryption --

EncryptBlock:	PROC[ key: Key, from, to: LONG POINTER TO Block] =
  INLINE { CryptData[@key, 1, LOOPHOLE[from], LOOPHOLE[to], encrypt, ecb, NIL] };

DecryptBlock:	PROC[ key: Key, from, to: LONG POINTER TO Block] =
  INLINE { CryptData[@key, 1, LOOPHOLE[from], LOOPHOLE[to], decrypt, ecb, NIL] };



-- Encryption and decryption of runs of blocks

  -- "from" and "to" must be totally disjoint or fully congruent!
  -- For speed, try to align them on quad-word boundaries.

  -- There are three modes: ECB, CBC and CBCCheck.

  -- "ECB" = Electronic Code Book:
	-- No state kept between 64-bit blocks.
  -- "CBC" = Cipher Block Chaining:
	-- 64-bits of state kept between blocks. 
	-- This state is XOR'd with the next incoming clear text block before encryption.
	-- seed is the 64-bit initial value of this state.
	-- Encryption:
	--	to[0] ← Encrypt[from[0] XOR seed↑]
	--	to[i] = Encrypt[from[i] XOR to[i-1]]
	-- Decryption:
	--	to[0] = Decrypt[from↑[0]] XOR seed↑
	--	to[i] = Decrypt[from↑[i]] XOR from↑[i-1]
  -- "CBCCheck" = CBC with checksum:
        -- When encrypting:
	--	Let chk = 64-bit XOR of from↑[0] through from↑[nBlks-1].
	--	to[0] ← Encrypt[from[0] XOR seed↑]
	--	to[i] = Encrypt[from[i] XOR to[i-1]]
	--      to[nBlks-1] ← Encrypt[chk XOR to[nBlks-2]]
	-- The inverse operation is performed on decryption.
	-- Thus after decryption, to[nBlks-1] should hold its initial value.
	-- If any cipher text is modified by an intruder, this is likely to
	-- alter decrypted to[nBlks-1]:  for any change to cipher text, each bit
	-- in to[nBlks-1] is altered with probability 1/2.  So if the client
	-- can verify N bits of to[nBlks-1], he can detect modified cipher
	-- text with probability (1 - 2↑-N).

BadKey:		ERROR;
  -- Key parity bad: may be raised by any en- or de- cryption proc.

ECBEncrypt:	PROC[ key: Key, nBlks: CARDINAL, from, to: Blocks] =
  INLINE {CryptData[@key, nBlks, from, to, encrypt, ecb] };

ECBDecrypt:	PROC[ key: Key, nBlks: CARDINAL, from, to: Blocks] =
  INLINE {CryptData[@key, nBlks, from, to, decrypt, ecb] };

CBCEncrypt:	PROC[ key: Key, nBlks: CARDINAL, from, to: Blocks,
		      seed: IV] =
  INLINE {CryptData[@key, nBlks, from, to, encrypt, cbc, @seed] };

CBCDecrypt:	PROC[ key: Key, nBlks: CARDINAL, from, to: Blocks,
		      seed: IV] =
  INLINE {CryptData[@key, nBlks, from, to, decrypt, cbc, @seed] };

CBCCheckEncrypt: PROC[ key: Key, nBlks: CARDINAL, from, to: Blocks,
		       seed: IV] =
  INLINE {CryptData[@key, nBlks, from, to, encrypt, cbcCheck, @seed] };

CBCCheckDecrypt: PROC[ key: Key, nBlks: CARDINAL, from, to: Blocks,
		      seed: IV] =
  INLINE {CryptData[@key, nBlks, from, to, decrypt, cbcCheck, @seed] };



Checksum:	PROC[ key: Key, nBlks: CARDINAL, from: Blocks,
		      seed: IV]
		RETURNS[ newSeed: IV] =
  INLINE {CryptData[@key, nBlks, from, NIL, encrypt, checksum, @seed];
          RETURN[seed]};
  -- Calculate CBC checksum function; "from" is undisturbed. --



  -- Internal types and procedures

Direction:	PRIVATE TYPE = {encrypt, decrypt};
Mode:		PRIVATE TYPE = {ecb, cbc, cbcCheck, checksum};

CryptData:	PRIVATE PROC [keyP: POINTER TO Key, nBlks: CARDINAL,
			      from, to: Blocks, direction: Direction, mode: Mode,
			      seedP: LONG POINTER TO IV ← NIL];

END. -- DESFace --