1 (* SimpleCipher.mod implements a pegalogical caesar cipher.
3 Copyright (C) 2008-2023 Free Software Foundation, Inc.
4 Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
6 This file is part of GNU Modula-2.
8 GNU Modula-2 is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 GNU Modula-2 is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. *)
27 IMPLEMENTATION MODULE SimpleCipher ;
30 FROM SYSTEM IMPORT ADDRESS, ADR, CARDINAL8, LOC ;
31 FROM RTio IMPORT GetDeviceId ;
32 FROM RTdata IMPORT ModuleId, MakeModuleId, InitData, GetData, KillData ;
33 FROM IOLink IMPORT DeviceId, DeviceTable, DeviceTablePtr, DeviceTablePtrValue, AllocateDeviceId, RAISEdevException ;
34 FROM IOChan IMPORT ChanExceptions ;
35 FROM IOConsts IMPORT ReadResults ;
36 FROM Storage IMPORT ALLOCATE, DEALLOCATE ;
37 FROM ASCII IMPORT nul, lf ;
38 FROM Strings IMPORT Insert, Append ;
39 FROM CharClass IMPORT IsLower, IsUpper, IsNumeric ;
43 PtrToLoc = POINTER TO LOC ;
44 PtrToChar = POINTER TO CHAR ;
45 CipherInfo = POINTER TO RECORD
59 PROCEDURE RotateChar (ch, lower, upper: CHAR; key: INTEGER) : CHAR ;
63 r := VAL(INTEGER, ORD(upper)-ORD(lower))+1 ;
66 RETURN( RotateChar(ch, lower, upper, r-key) )
72 (* key is now positive and within a sensible range *)
73 IF ORD(ch)+VAL(CARDINAL, key)>ORD(upper)
75 RETURN( CHR((ORD(ch)+VAL(CARDINAL, key))-VAL(CARDINAL, r)) )
77 RETURN( CHR(ORD(ch)+VAL(CARDINAL, key)) )
84 encryptChar - encrypts, ch, using Caesar cipher. Only
85 characters [A-Z][a-z][0-9] are encrypted.
86 Also these character ranges are only rotated
87 around their own range.
90 PROCEDURE encryptChar (ch: CHAR; key: INTEGER) : CHAR ;
94 RETURN( RotateChar(ch, 'a', 'z', key) )
97 RETURN( RotateChar(ch, 'A', 'Z', key) )
100 RETURN( RotateChar(ch, '0', '9', key) )
108 decryptChar - decrypts, ch, using Caesar cipher. Only
109 characters [A-Z][a-z][0-9] are decrypted.
110 Also these character ranges are only rotated
111 around their own range.
114 PROCEDURE decryptChar (ch: CHAR; key: INTEGER) : CHAR ;
116 RETURN( encryptChar(ch, -key) )
124 PROCEDURE RotateLoc (cid: ChanId;
126 l: LOC; key: INTEGER) : LOC ;
133 RAISEdevException(cid, did, notAvailable, 'SimpleCipher: unable to cipher LOCs of this size')
137 RETURN( RotateLoc(cid, did, l, -key+VAL(INTEGER, MAX(CARDINAL8))) )
139 IF key>VAL(INTEGER, MAX(CARDINAL8))
141 key := key MOD (VAL(INTEGER, MAX(CARDINAL8))+1)
143 c := VAL(CARDINAL8, l) ;
144 u := VAL(INTEGER, MAX(CARDINAL8))+1 ;
145 IF u-VAL(INTEGER, c)>key
149 c := key-(u-VAL(INTEGER, c))
151 RETURN( VAL(LOC, c) )
158 encryptLoc - encrypts, l, by, key.
161 PROCEDURE encryptLoc (cid: ChanId; did: DeviceId; l: LOC; key: INTEGER) : LOC ;
163 RETURN( RotateLoc(cid, did, l, key) )
168 decryptLoc - decrypts, l, by, key.
171 PROCEDURE decryptLoc (cid: ChanId; did: DeviceId; l: LOC; key: INTEGER) : LOC ;
173 RETURN( RotateLoc(cid, did, l, -key) )
177 PROCEDURE dolook (d: DeviceTablePtr;
178 VAR ch: CHAR; VAR r: ReadResults) ;
182 c := GetData(d, mid) ;
184 lower.doLook(d, ch, r) ;
185 IF (r=allRight) OR (r=endOfLine)
187 ch := decryptChar(ch, key)
193 PROCEDURE doskip (d: DeviceTablePtr) ;
197 c := GetData(d, mid) ;
204 PROCEDURE doskiplook (d: DeviceTablePtr;
205 VAR ch: CHAR; VAR r: ReadResults) ;
209 c := GetData(d, mid) ;
211 lower.doSkipLook(d, ch, r) ;
212 IF (r=allRight) OR (r=endOfLine)
214 ch := decryptChar(ch, key)
220 PROCEDURE dowriteln (d: DeviceTablePtr) ;
225 dotextwrite(d, ADR(ch), 1)
229 PROCEDURE dotextread (d: DeviceTablePtr;
232 VAR charsRead: CARDINAL) ;
239 c := GetData(d, mid) ;
243 WHILE charsRead<maxChars DO
244 c^.lower.doTextRead(d, ADR(ch), SIZE(ch), i) ;
247 p^ := decryptChar(ch, key) ;
258 PROCEDURE dotextwrite (d: DeviceTablePtr;
260 charsToWrite: CARDINAL);
267 c := GetData(d, mid) ;
271 WHILE i<charsToWrite DO
272 ch := encryptChar(p^, key) ;
273 c^.lower.doTextWrite(d, ADR(ch), SIZE(ch)) ;
281 PROCEDURE dorawread (d: DeviceTablePtr;
284 VAR locsRead: CARDINAL) ;
291 c := GetData(d, mid) ;
295 WHILE locsRead<maxLocs DO
296 lower.doRawRead(d, ADR(l), SIZE(l), i) ;
299 p^ := decryptLoc(d^.cid, d^.did, l, key) ;
310 PROCEDURE dorawwrite (d: DeviceTablePtr;
312 locsToWrite: CARDINAL) ;
319 c := GetData(d, mid) ;
323 WHILE i<locsToWrite DO
324 l := encryptLoc(d^.cid, d^.did, p^, key) ;
325 lower.doRawWrite(d, ADR(l), SIZE(l)) ;
333 PROCEDURE dogetname (d: DeviceTablePtr;
334 VAR a: ARRAY OF CHAR) ;
338 c := GetData(d, mid) ;
340 lower.doGetName(d, a) ;
341 Insert('SimpleCipher (', 0, a) ;
348 freeData - disposes of, c.
351 PROCEDURE freeData (c: CipherInfo) ;
358 dofree - replace original methods and then delete data pertaining
359 to, mid. The idea is that our new methods will call the
360 old methods and then decrypt data when reading and visa
361 versa for writing. We write CHARs and LOCs at a time so
362 ensure no plaintext data is ever passed outside this
366 PROCEDURE dofree (d: DeviceTablePtr) ;
370 c := GetData(d, mid) ;
372 doLook := c^.lower.doLook ;
373 doLook := c^.lower.doLook ;
374 doSkip := c^.lower.doSkip ;
375 doSkipLook := c^.lower.doSkipLook ;
376 doLnWrite := c^.lower.doLnWrite ;
377 doTextRead := c^.lower.doTextRead ;
378 doTextRead := c^.lower.doTextRead ;
379 doRawRead := c^.lower.doRawRead ;
380 doRawWrite := c^.lower.doRawWrite ;
381 doGetName := c^.lower.doGetName ;
382 doReset := c^.lower.doReset ;
383 doFlush := c^.lower.doFlush ;
384 doFree := c^.lower.doFree
390 InsertCipherLayer - inserts a Caesar cipher below channel, cid.
391 The encryption, key, is specified.
394 PROCEDURE InsertCipherLayer (cid: ChanId; key: INTEGER) ;
400 did := GetDeviceId(cid) ;
401 d := DeviceTablePtrValue(cid, did) ;
402 IF GetData(d, mid)=NIL
407 InitData(d, mid, c, freeData) ;
411 doSkipLook := doskiplook ;
412 doLnWrite := dowriteln ;
413 doTextRead := dotextread ;
414 doTextWrite := dotextwrite ;
415 doRawRead := dorawread ;
416 doRawWrite := dorawwrite ;
417 doGetName := dogetname ;
418 (* doReset := doreset ; no need for either of these *)
419 (* doFlush := doflush ; *)
423 RAISEdevException(cid, did, notAvailable,
424 'SimpleCipher: unable to insert multiple cipher layers from the same module under a channel')
426 END InsertCipherLayer ;
430 RemoveCipherLayer - removes a Caesar cipher below channel, cid.
433 PROCEDURE RemoveCipherLayer (cid: ChanId) ;
438 did := GetDeviceId(cid) ;
439 d := DeviceTablePtrValue(cid, did) ;
440 IF GetData(d, mid)=NIL
442 RAISEdevException(cid, did, notAvailable,
443 'SimpleCipher: no cipher layer to remove from this channel')
447 END RemoveCipherLayer ;