Lorenz

Category: Bletchley

Status: Registered and callable in the CyberChef 11.3.0 compatibility inventory.

Input / output: string → string

Background: https://wikipedia.org/wiki/Lorenz_cipher

What it does

The Lorenz SZ40/42 cipher attachment was a WW2 German rotor cipher machine with twelve rotors which attached in-line between remote teleprinters. It used the Vernam cipher with two groups of five rotors (named the psi(ψ) wheels and chi(χ) wheels at Bletchley Park) to create two pseudorandom streams of five bits, encoded in ITA2, which were XOR added to the plaintext. Two other rotors, dubbed the mu(μ) or motor wheels, could hold up the stepping of the psi wheels meaning they stepped intermittently. Each rotor has a different number of cams/lugs around their circumference which could be set active or inactive changing the key stream. Three models of the Lorenz are emulated, SZ40, SZ42a and SZ42b and three example wheel patterns (the lug settings) are included (KH, ZMUG & BREAM) with the option to set a custom set using the letter ‘x’ for active or ‘.’ for an inactive lug. The input can either be plaintext or ITA2 when sending and ITA2 when receiving. To learn more, Virtual Lorenz, an online, browser based simulation of the Lorenz SZ40/42 is available at lorenz.virtualcolossus.co.uk. A more detailed description of this operation can be found here.

Note

Status here means the operation name is implemented and callable. It does not by itself promise byte-for-byte parity for every upstream option. See Compatibility and current status for the verified scope and known boundaries.

Warning

Historical machine presets currently cover a documented compatibility subset.

Arguments and options

Arguments are positional. Keep their order when using bake() or Pipeline.then().

Index

Name

UI type

PyChef default

Accepted values / format

0

Model

option

'SZ40'

'SZ40', 'SZ42a', 'SZ42b'

1

Wheel Pattern

argSelector

'KH Pattern'

'KH Pattern', 'ZMUG Pattern', 'BREAM Pattern', 'No Pattern', 'Custom'

2

KT-Schalter

boolean

False

True or False

3

Mode

argSelector

'Send'

'Send', 'Receive'

4

Input Type

option

'Plaintext'

'Plaintext', 'ITA2'

5

Output Type

option

'Plaintext'

'Plaintext', 'ITA2'

6

ITA2 Format

option

'5/8/9'

'5/8/9', '+/-/.'

7

Ψ1 start (1-43)

number

1

A Python integer or floating-point value

8

Ψ2 start (1-47)

number

1

A Python integer or floating-point value

9

Ψ3 start (1-51)

number

1

A Python integer or floating-point value

10

Ψ4 start (1-53)

number

1

A Python integer or floating-point value

11

Ψ5 start (1-59)

number

1

A Python integer or floating-point value

12

Μ37 start (1-37)

number

1

A Python integer or floating-point value

13

Μ61 start (1-61)

number

1

A Python integer or floating-point value

14

Χ1 start (1-41)

number

1

A Python integer or floating-point value

15

Χ2 start (1-31)

number

1

A Python integer or floating-point value

16

Χ3 start (1-29)

number

1

A Python integer or floating-point value

17

Χ4 start (1-26)

number

1

A Python integer or floating-point value

18

Χ5 start (1-23)

number

1

A Python integer or floating-point value

19

Ψ1 lugs (43)

string

'.x...xx.x.x..xxx.x.x.xxxx.x.x.x.x.x..x.xx.x'

'.x...xx.x.x..xxx.x.x.xxxx.x.x.x.x.x..x.xx.x'

20

Ψ2 lugs (47)

string

'.xx.x.xxx..x.x.x..x.xx.x.xxx.x....x.xx.x.x.x..x'

'.xx.x.xxx..x.x.x..x.xx.x.xxx.x....x.xx.x.x.x..x'

21

Ψ3 lugs (51)

string

'.x.x.x..xxx....x.x.xx.x.x.x..xxx.x.x..x.x.xx..x.x.x'

'.x.x.x..xxx....x.x.xx.x.x.x..xxx.x.x..x.x.xx..x.x.x'

22

Ψ4 lugs (53)

string

'.xx...xxxxx.x.x.xx...x.xx.x.x..x.x.xx.x..x.x.x.x.x.x.'

'.xx...xxxxx.x.x.xx...x.xx.x.x..x.x.xx.x..x.x.x.x.x.x.'

23

Ψ5 lugs (59)

string

'xx...xx.x..x.xx.x...x.x.x.x.x.x.x.x.xx..xxxx.x.x...xx.x..x.'

'xx...xx.x..x.xx.x...x.x.x.x.x.x.x.x.xx..xxxx.x.x...xx.x..x.'

24

Μ37 lugs (37)

string

'x.x.x.x.x.x...x.x.x...x.x.x...x.x....'

'x.x.x.x.x.x...x.x.x...x.x.x...x.x....'

25

Μ61 lugs (61)

string

'.xxxx.xxxx.xxx.xxxx.xx....xxx.xxxx.xxxx.xxxx.xxxx.xxx.xxxx...'

'.xxxx.xxxx.xxx.xxxx.xx....xxx.xxxx.xxxx.xxxx.xxxx.xxx.xxxx...'

26

Χ1 lugs (41)

string

'.x...xxx.x.xxxx.x...x.x..xxx....xx.xxxx..'

'.x...xxx.x.xxxx.x...x.x..xxx....xx.xxxx..'

27

Χ2 lugs (31)

string

'x..xxx...x.xxxx..xx..x..xx.xx..'

'x..xxx...x.xxxx..xx..x..xx.xx..'

28

Χ3 lugs (29)

string

'..xx..x.xxx...xx...xx..xx.xx.'

'..xx..x.xxx...xx...xx..xx.xx.'

29

Χ4 lugs (26)

string

'xx..x..xxxx..xx.xxx....x..'

'xx..x..xxxx..xx.xxx....x..'

30

Χ5 lugs (23)

string

'xx..xx....xxxx.x..x.x..'

'xx..xx....xxxx.x..x.x..'

Recipe template

Important

This is a call template built from the documented defaults. Replace placeholder values such as empty keys, paths, patterns, or lookup data before running it.

from pychef import bake

input_value = "example"
args = ['SZ40', 'KH Pattern', False, 'Send', 'Plaintext', 'Plaintext', '5/8/9', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, '.x...xx.x.x..xxx.x.x.xxxx.x.x.x.x.x..x.xx.x', '.xx.x.xxx..x.x.x..x.xx.x.xxx.x....x.xx.x.x.x..x', '.x.x.x..xxx....x.x.xx.x.x.x..xxx.x.x..x.x.xx..x.x.x', '.xx...xxxxx.x.x.xx...x.xx.x.x..x.x.xx.x..x.x.x.x.x.x.', 'xx...xx.x..x.xx.x...x.x.x.x.x.x.x.x.xx..xxxx.x.x...xx.x..x.', 'x.x.x.x.x.x...x.x.x...x.x.x...x.x....', '.xxxx.xxxx.xxx.xxxx.xx....xxx.xxxx.xxxx.xxxx.xxxx.xxx.xxxx...', '.x...xxx.x.xxxx.x...x.x..xxx....xx.xxxx..', 'x..xxx...x.xxxx..xx..x..xx.xx..', '..xx..x.xxx...xx...xx..xx.xx.', 'xx..x..xxxx..xx.xxx....x..', 'xx..xx....xxxx.x..x.x..']
result = bake(input_value, [{"op": 'Lorenz', "args": args}])
print(result)

Pipeline example

from pychef import Pipeline

args = ['SZ40', 'KH Pattern', False, 'Send', 'Plaintext', 'Plaintext', '5/8/9', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, '.x...xx.x.x..xxx.x.x.xxxx.x.x.x.x.x..x.xx.x', '.xx.x.xxx..x.x.x..x.xx.x.xxx.x....x.xx.x.x.x..x', '.x.x.x..xxx....x.x.xx.x.x.x..xxx.x.x..x.x.xx..x.x.x', '.xx...xxxxx.x.x.xx...x.xx.x.x..x.x.xx.x..x.x.x.x.x.x.', 'xx...xx.x..x.xx.x...x.x.x.x.x.x.x.x.xx..xxxx.x.x...xx.x..x.', 'x.x.x.x.x.x...x.x.x...x.x.x...x.x....', '.xxxx.xxxx.xxx.xxxx.xx....xxx.xxxx.xxxx.xxxx.xxxx.xxx.xxxx...', '.x...xxx.x.xxxx.x...x.x..xxx....xx.xxxx..', 'x..xxx...x.xxxx..xx..x..xx.xx..', '..xx..x.xxx...xx...xx..xx.xx.', 'xx..x..xxxx..xx.xxx....x..', 'xx..xx....xxxx.x..x.x..']
transform = Pipeline().then('Lorenz', *args)
result = transform("example")

Dedicated operation module

The registered entry point lives in pychef.operations.by_operation.lorenz. Direct calls receive the input value and a positional argument tuple:

from pychef.operations.by_operation.lorenz import run

result = run("example", tuple(['SZ40', 'KH Pattern', False, 'Send', 'Plaintext', 'Plaintext', '5/8/9', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, '.x...xx.x.x..xxx.x.x.xxxx.x.x.x.x.x..x.xx.x', '.xx.x.xxx..x.x.x..x.xx.x.xxx.x....x.xx.x.x.x..x', '.x.x.x..xxx....x.x.xx.x.x.x..xxx.x.x..x.x.xx..x.x.x', '.xx...xxxxx.x.x.xx...x.xx.x.x..x.x.xx.x..x.x.x.x.x.x.', 'xx...xx.x..x.xx.x...x.x.x.x.x.x.x.x.xx..xxxx.x.x...xx.x..x.', 'x.x.x.x.x.x...x.x.x...x.x.x...x.x....', '.xxxx.xxxx.xxx.xxxx.xx....xxx.xxxx.xxxx.xxxx.xxxx.xxx.xxxx...', '.x...xxx.x.xxxx.x...x.x..xxx....xx.xxxx..', 'x..xxx...x.xxxx..xx..x..xx.xx..', '..xx..x.xxx...xx...xx..xx.xx.', 'xx..x..xxxx..xx.xxx....x..', 'xx..xx....xxxx.x..x.x..']))
pychef.operations.by_operation.lorenz.run(value, args)

Run this operation using its shared internal implementation.

Parameters:
  • value (str | bytes)

  • args (Sequence[Any])

Return type:

str | bytes