`codext` also implements several simple cryptographic ciphers. But how does it relate to encoding while a key is required ? `codext` focuses on ciphers that have a weak key. With dynamically named encodings, it is then possible to define a bunch of encodings, one for each value of the key. For instance, Barbie Typewriter has a key with only 4 possible values. The `barbie` codec can then be `barbie-1`, ..., `barbie-4`.

!!! note "Available masks"
    
    Some cipher codecs use character masks to generate their alphabets. Groups of characters are indicated using a headin "`?`".
    
    `a`: printable characters
    `b`: all 8-bits chars
    `d`: digits
    `h`: lowercase hexadecimal
    `H`: uppercase hexadecimal
    `l`: lowercase letters
    `p`: punctuation characters
    `s`: whitespace
    `u`: uppercase letters
    
    When combining masks, only one occurrence of each character is taken in the final alphabet.
    
    So, for instance, the following masks yield the following alphabets:
    
    - `?l?u?d?s`: "`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 `"
    - `?s.,?!?u?d`: "` .,?!ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`"

-----

### Affine Cipher

This codec implements the Affine monoalphabetic substitution cipher. It is parametrizable with a mask for generating the alphabet and the parameters `a` and `b`. By default, it uses mask "`lus`" and parameters `a=1` and `b=2` but it can be set as in the examples hereafter.

**Codec** | **Conversions** | **Aliases** | **Comment**
:---: | :---: | --- | ---
`affine` | text <-> affine ciphertext | `affine`, `affine_cipher-?l?u?d?s-5,8`, `affine-?s.,?!?u?d-23,6`, ... | Mask-generated alphabet ; uses default mask "`?l?u?s`" with `a=1` and `b=2`

```python
>>> codext.encode("this is a test", "affine")
'vjkubkubcbvguv'
>>> codext.decode("vjkubkubcbvguv", "affine")
'this is a test'
>>> codext.encode("this is a test", "affine-?l?u?d?s-5,8")
'ORWJdWJdidOCJO'
>>> codext.decode("ORWJdWJdidOCJO", "affine-?l?u?d?s-5,8")
'this is a test'
>>> codext.encode("THIS IS A TEST", "affine-?s.,?!?u?d-5,8")
'AW1 D1 D2DAH A'
>>> codext.decode("AW1 D1 D2DAH A", "affine-?s.,?!?u?d-5,8")
'THIS IS A TEST'
```

!!! warning "Parameters `a` and `b`"
    
    Not all values are suitable for `a` and `b`. If a generated encoding map has mapping collisions, an exception is raised telling that `a` and `b` are bad.

-----

### Atbash Cipher

It implements the monoalphabetic substitution cipher used for the Hebrew alphabet. By default, it considers the lowercase and uppercase letters, inverted per group, as the alphabet. It can also use a mask to extend it. Note that it does not generate any error for characters that are not part of the alphabet.

**Codec** | **Conversions** | **Aliases** | **Comment**
:---: | :---: | --- | ---
`atbash` | text <-> Atbash ciphertext | `atbash`, `atbash_cipher-?l?d?s`, ... | Mask-generated alphabet ; uses default mask "`?u?l`"

```python
>>> codext.encode("this is a test", "atbash")
'gsrh rh z gvhg'
>>> codext.encode("this is a test", "atbash-[?l?u?p?s]")
'.^]/a]/a a.{/.'
>>> codext.decode(".^]/a]/a a.{/.", "atbash_cipher_[?l?u?p?s]")
'this is a test'
```

-----

### Autoclave/Autokey Cipher

This is a variant of the [Vigenere Cipher](#vigenere-cipher) using a key stream generated from the primer key and the message appended.

**Codec** | **Conversions** | **Aliases** | **Comment**
:---: | :---: | --- | ---
`autoclave` | text <-> Autoclave ciphertext | `autoclave-cipher`, `autokey` | 

```python
>>> codext.encode("This is a test !", "autoclave-test")
'Mlal bz i lmkt !'
>>> codext.decode("Mlal bz i lmkt !", "autokey_cipher-test")
'This is a test !'
```

-----

### Baconian Cipher

It support only letters.

**Codec** | **Conversions** | **Aliases** | **Comment**
:---: | :---: | --- | ---
`bacon` | text <-> Bacon ciphertext | `bacon-cipher`, `baconian_cipher`, `bacon-01`, `bacon-10` | Dynamic tokens mapping ; we can define a mapping of encoding's tokens (original tokens: `ab`)

```python
>>> codext.encode("this is a test", "bacon")
'baaba aabbb abaaa baaab  abaaa baaab  aaaaa  baaba aabaa baaab baaba'
>>> codext.encode("this is a test", "bacon_01")
'10010 00111 01000 10001  01000 10001  00000  10010 00100 10001 10010'
>>> codext.decode("-..-. ..--- .-... -...-  .-... -...-  .....  -..-. ..-.. -...- -..-.", "bacon_.-")
'THIS IS A TEST'
```

-----

### Barbie Typewriter

It implements the cipher for its 4 different keys.

**Codec** | **Conversions** | **Aliases** | **Comment**
:---: | :---: | --- | ---
`barbie` | text <-> Barbie ciphertext | `barbie-1`, `barbie-2`, `barbie-3`, `barbie-4`

```python
>>> codext.encode("this is a test", "barbie-1")
'hstf tf i hafh'
>>> codext.encode("this is a test", "barbie_3")
'fpsu su h ftuf'
>>> codext.decode("fpsu su h ftuf", "barbie-3")
'this is a test'
```

-----

### Beaufort Cipher

This is a variant of the [Vigenere Cipher](#vigenere-cipher). There is no default key, meaning that `beaufort` as the encoding scheme throws a `LookupError` indicating that the _key must be a non-empty alphabetic string_.

**Codec** | **Conversions** | **Aliases** | **Comment**
:---: | :---: | --- | ---
`beaufort` | text <-> Beaufort ciphertext | `beaufort-abcdef`, `beaufort_MySuperSecret` | key only consists of characters, not digits

```python
>>> codext.encode("This is a test !", "beaufort-abababa")
'Husj sj a hxii !'
>>> codext.encode("This is a test !", "beaufort_MySuperSecret")
'Trkc hm r zaky !'
>>> codext.decode("Husj sj a hxii !", "vigenere-abababa")
'This is a test !'
```

-----

### Citrix CTX1

This implements the Citrix CTX1 password encoding algorithm.

**Codec** | **Conversions** | **Aliases** | **Comment**
:---: | :---: | --- | ---
`citrix` | text <-> Citrix CTX1 ciphertext | `citrix`, `citrix-1`, `citrix_ctx1` | 

```python
>>> codext.encode("this is a test", "citrix-ctx1")
'NBBMNAAGIDEPJJBMNIFNIMEMJKEL'
>>> codext.decode("NBBMNAAGIDEPJJBMNIFNIMEMJKEL", "citrix-ctx1")
'this is a test'
```

-----

### Phillips Cipher

This implements Phillips cipher, a polyalphabetic code using 8 grids generated with one keyword.

**Codec** | **Conversions** | **Aliases** | **Comment**
:---: | :---: | --- | ---
`phillips` | text <-> phillips ciphertext | `phillips-key`, `phillips_password`, ... |

```python
>>> codext.encode("this is a test", "phillips_mysuperkey")
'ZCNM NM E XKMVZ'
>>> codext.encode("Another Test String", "phillips-PaSsWoRd")
'SMEZKBE LBON OLEHQHV'
>>> codext.decode("SMEZKBE LBON OLEHQHV", "phillips-password")
'ANOTHER TEST STRINGX'
```

-----

### Polybius Square Cipher

This implements the well-known Polybius Square cipher, using the square with the alphabet in normal order as the default. It can be used dynamically with a custom alphabet.

**Codec** | **Conversions** | **Aliases** | **Comment**
:---: | :---: | --- | ---
`polybius` | text <-> polybius square ciphertext | `polybius-square`, `polybius_BACDEFGHIKLMNOPQRSTUVWXYZ`, ... |

```python
>>> codext.encode("this is a test", "polybius")
'44232443 2443 11 44154344'
>>> codext.encode("this is a test", "polybius_BACDEFGHIKLMNOPQRSTUVWXYZ")
'44232443 2443 12 44154344'
>>> codext.decode("44232443 2443 11 441543445", "polybius-square", errors="replace")
'THIS IS A TEST?'
```

-----

### Rail Fence Cipher

This implements the Rail Fence encoding algorithm, using 3 rails and offset 0 as the default parameters. The encoding fence is built from the top ; the `up` flag can be used to build the fence from the bottom. Note that trying parameters that do not fit the input length will trigger a `ValueError` mentioning the bad value.

**Codec** | **Conversions** | **Aliases** | **Comment**
:---: | :---: | --- | ---
`rail` | text <-> rail fence ciphertext, X rails and Y offset | `rail-X-Y`, `rail_X_Y`, `rail-X-Y-up`, `zigzag`, ... | 

```python
>>> codext.encode("this is a test", "zigzag")
't ashsi  etist'
>>> codext.encode("this is a test", "rail-5-3")
'it sss etiath '
>>> codext.decode("it sss etiath ", "zigzag_5-3")
'this is a test'
```

-----
### ROT N

This is a dynamic encoding, that is, it can be called with an integer to define the ROT offset. Encoding will apply a positive offset, decoding will apply a negative one.

**Codec** | **Conversions** | **Aliases** | **Comment**
:---: | :---: | --- | ---
`rot` | text <-> rot(1) ciphertext | `rot1`, `rot-1`, `rot_25`, `caesar13` | Dynamic ROT parameter ; belongs to [1, 26[
`rot47` | text <-> rot47 ciphertext |  | 

```python
>>> codext.encode("this is a test", "rot-15")
'iwxh xh p ithi'
>>> codext.encode("iwxh xh p ithi", "rot20")
'cqrb rb j cnbc'
>>> codext.decode("cqrb rb j cnbc", "rot_9")
'this is a test'
```

-----

### Shift

This is a dynamic encoding, that is, it can be called with an integer to define the shift offset. Encoding will apply a positive offset, decoding will apply a negative one.

**Codec** | **Conversions** | **Aliases** | **Comment**
:---: | :---: | --- | ---
`shift` | text <-> shift(1) ciphertext | `shift1`, `shift-158`, `shift_255` | Dynamic shift parameter ; belongs to [1, 256[

```python
>>> codext.encode("this is a test", "shift-3")
'wklv#lv#d#whvw'
>>> codext.decode("wklv#lv#d#whvw", "shift10")
'mabl\x19bl\x19Z\x19m^lm'
>>> codext.encode("mabl\x19bl\x19Z\x19m^lm", "ordshift_7")
'this is a test'
```

-----

### Playfair Cipher

The Playfair cipher is a symmetric encryption method using polygram substitution with bigrams (pairs of letters), invented in 1854 by Charles Wheatstone, but popularized by Lord Playfair.

**Codec** | **Conversions** | **Aliases** | **Comment**
:---: | :---: | --- | ---
`playfair` | text <-> Playfair ciphertext | `playfair`, `playfair-playfairexample`, `playfair-keyword` | Dynamic key parameter ; letters only ; `J` is normalized to `I`

```python
>>> codext.encode("HIDETHEGOLDINTHETREESTUMP", "playfair-playfairexample")
'BMODZBXDNABEKUDMUIXMMOUVIF'
>>> codext.decode("BMODZBXDNABEKUDMUIXMMOUVIF", "playfair-playfairexample")
'HIDETHEGOLDINTHETREXESTUMP'
>>> codext.decode(codext.encode("INSTRUMENT", "playfair-keyword"), "playfair-keyword")
'INSTRUMENT'
```

-----

### Trithemius Cipher

This is a variant of the [Vigenere Cipher](#vigenere-cipher) with key `"ABCDEFGHIJKLMNOPQRSTUVWXYZ"`.

**Codec** | **Conversions** | **Aliases** | **Comment**
:---: | :---: | --- | ---
`trithemius` | text <-> Trithemius ciphertext | `trithemius`, `trithemius_cipher` | 

```python
>>> codext.encode("This is a test !", "trithemius")
'Tikv mx g ambd !'
>>> codext.decode("Tikv mx g ambd !", "trithemius")
'This is a test !'
```

-----

### VIC Cipher

The VIC cipher combines a straddling checkerboard substitution (converting letters to a stream of digits) and an over-encryption based on a modulo-10 sum with eventually a conversion from digits to text.

**Codec** | **Conversions** | **Aliases** | **Comment**
:---: | :---: | --- | ---
`vic` | text <-> VIC digit/text ciphertext | `vic-keyword`, `vic-key-12`, `vic-^-26-0248`, `vic-*-73-534T` | optional checkerboard keyword or alphabet marker, blank positions (exactly 2 distinct digits), over-encryption key (digits), "`T`" marker for text conversion

Alphabet markers:
- `*`: uses "`ABC[...]XYZ./`" (uppercase letters + "`./`")
- `^`: uses "`./ZYX[...]CBA`" ("`./`" + reversed uppercase letters)

```python
>>> import codext
>>> codext.encode("VICTOR", "vic-^-26-0248T")
'VVXYWYY.XYJ'
>>> codext.decode("VVXYWYY.XYJ", "vic-^-26-0248T")
'VICTOR2'  # trailing superfluous letter because of text conversion
>>> codext.encode("LONGTESTSTRING", "vic-^-85-72564")
'5031237844273727064454072378'
```

-----

### Vigenere Cipher

This is a dynamic encoding, that is, it holds the key. There is no default key, meaning that `vigenere` as the encoding scheme throws a `LookupError` indicating that the _key must be a non-empty alphabetic string_.

**Codec** | **Conversions** | **Aliases** | **Comment**
:---: | :---: | --- | ---
`vigenere` | text <-> Vigenere ciphertext | `vigenere-abcdef`, `vigenere_MySuperSecret` | key only consists of characters, not digits

```python
>>> codext.encode("This is a test !", "vigenere-abababa")
'Tiit it a tfsu !'
>>> codext.encode("This is a test !", "vigenere_MySuperSecret")
'Ffam xw r liuk !'
>>> codext.decode("Tiit it a tfsu !", "vigenere-abababa")
'This is a test !'
```

-----

### XOR with 1 byte

This is a dynamic encoding, that is, it can be called with an integer to define the ordinal of the byte to XOR with the input text.

**Codec** | **Conversions** | **Aliases** | **Comment**
:---: | :---: | --- | ---
`xor` | text <-> XOR(1) ciphertext | `XOR1`, `xor22`, `xor-158`, `xor_255` | Dynamic XOR parameter ; belongs to [1, 256[

```python
>>> codext.encode("this is a test", "xor-10")
'~bcy*cy*k*~oy~'
>>> codext.encode("this is a test", "xor-30")
'jvwm>wm>\x7f>j{mj'
>>> codext.decode("this is a test", "xor-30")
'jvwm>wm>\x7f>j{mj'
>>> codext.encode("~bcy*cy*k*~oy~", "xor-10")
'this is a test'
```
