DESDummy.mesa - Dummy implementation of DES (used by RPCRuntime)
Copyright © 1985 by Xerox Corporation. All rights reserved.
Andrew Birrell, September 7, 1983 4:45 pm
Bob Hagmann February 11, 1985 10:13:49 am PST
Russ Atkinson (RRA) February 13, 1985 12:28:51 pm PST
DIRECTORY
BasicTime USING [ GetClockPulses ],
DESFace,
Basics USING [ BITXOR ];
DESDummy: MONITOR
IMPORTS Basics, BasicTime
EXPORTS DESFace
SHARES DESFace
= { OPEN DESFace;
Words4: TYPE = MACHINE DEPENDENT RECORD[w1, w2, w3, w4: WORD];
XOR64: PROC[a, b, out: LONG POINTER] = INLINE {
OPEN
aLP: LOOPHOLE[a, LONG POINTER TO Words4],
bLP: LOOPHOLE[b, LONG POINTER TO Words4],
outP: LOOPHOLE[out, LONG POINTER TO Words4];
outP.w1 ← Basics.BITXOR[aLP.w1, bLP.w1];
outP.w2 ← Basics.BITXOR[aLP.w2, bLP.w2];
outP.w3 ← Basics.BITXOR[aLP.w3, bLP.w3];
outP.w4 ← Basics.BITXOR[aLP.w4, bLP.w4];
};
Words2: TYPE = MACHINE DEPENDENT RECORD[w1, w2: WORD];
XOR32: PROC[a, b: LONG UNSPECIFIED, out: POINTER] = INLINE {
OPEN
aP: LOOPHOLE[a, Words2],
bP: LOOPHOLE[b, Words2],
outP: LOOPHOLE[out, POINTER TO Words2];
outP.w1 ← Basics.BITXOR[aP.w1, bP.w1];
outP.w2 ← Basics.BITXOR[aP.w2, bP.w2];
};
cachedKey: Key;
noKeyCached: BOOLEANTRUE;
BadKey: PUBLIC ERROR = CODE;
checkingForParity: BOOLTRUE;
Turn this to false to avoid the BadKey error. This is to allow servers that are not prepared to handle this to continue to function (more or less). Of course, the best thing to do is to handle this error and do "the right thing."
InternalizeKey: ENTRY PROC [keyP: POINTER TO Key] = {
IF noKeyCached OR cachedKey # keyP^ THEN {
IF checkingForParity THEN
FOR i: CARDINAL IN [0..7] DO
IF keyP[i].p # parityTable[keyP[i].b] THEN RETURN WITH ERROR BadKey;
ENDLOOP;
cachedKey ← keyP^;
noKeyCached ← FALSE;
};
};
NotImplemented: ERROR = CODE;
CryptData: PUBLIC PROC [keyP: POINTER TO Key, nBlks: CARDINAL, from, to: Blocks, direction: Direction, mode: Mode, seedP: LONG POINTER TO IVNIL] = {
newSeed: IV;
IF mode = checksum THEN ERROR NotImplemented;
IF mode = cbcCheck AND direction = encrypt AND nBlks > 0 THEN
FOR blk: CARDINAL IN [0..nBlks-1) DO
XOR64[@from[nBlks-1], @from[blk], @from[nBlks-1]];
ENDLOOP;
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 {
FOR blk: CARDINAL IN [0..nBlks-1) DO
XOR64[@to[nBlks-1], @to[blk], @to[nBlks-1]];
ENDLOOP;
}
};
randomSeed: Block ← [1,2,3,4];
GetRandomIV: PUBLIC PROC RETURNS [iv: IV] = {
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^ + BasicTime.GetClockPulses[];
XOR32[pulse2^, BasicTime.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];
};
GetRandomKey: PUBLIC PROC RETURNS [k: Key] = {
k ← LOOPHOLE[GetRandomIV[]];
CorrectParity[@k];
};
MakeKey: PUBLIC PROC [source: LONG STRING] RETURNS [key: Key] = {
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 ← Basics.BITXOR[LOOPHOLE[c, [0 .. 127]], key[j].b];
ENDLOOP;
CorrectParity[@key];
};
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] = {
FOR i: CARDINAL IN [0 .. 7] DO
keyP[i].p ← parityTable[keyP[i].b];
ENDLOOP;
};
[] ← GetRandomKey[];
}.