DESFace.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Andrew Birrell 16-Mar-82 8:36:51
Michael D. Schroeder, October 30, 1981 3:11 PM
Levin, May 26, 1983 4:20 pm
Russ Atkinson (RRA) February 19, 1985 2:10:27 pm PST
Doug Wyatt, February 22, 1985 1:41:13 pm PST
DESFace: DEFINITIONS
= BEGIN
Public types and constants
Block: TYPE = ARRAY [0 .. 3] OF WORD; -- 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 IVNIL];
END.