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