Skip to content

Commit 0ca59c1

Browse files
committed
Added codec: vernam
1 parent 7f05da9 commit 0ca59c1

4 files changed

Lines changed: 58 additions & 0 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ This category also contains `ascii85`, `adobe`, `[x]btoa`, `zeromq` with the `ba
383383
- [X] `skip`: aka Skip Cipher (transposition reading every N-th character, looping on the text)
384384
- [X] `trithemius`: aka Trithemius Cipher (variant of Vigenere Cipher)
385385
- [X] `twosquare`: aka Two-square Cipher or Double Playfair (bigrams substituted with two keyed squares, vertically or horizontally)
386+
- [X] `vernam`: aka Vernam Cipher (XOR with a repeating key)
386387
- [X] `vic`: aka VIC Cipher
387388
- [X] `vigenere`: aka Vigenere Cipher
388389
- [X] `xorN`: XOR with a single byte (*N* belongs to [1,255])

‎docs/pages/enc/crypto.md‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,23 @@ Alphabet markers:
759759

760760
-----
761761

762+
### Vernam Cipher
763+
764+
This is a dynamic encoding, that is, it holds the key. Each character of the text is XORed with the corresponding character of the repeated key ; with a random key as long as the text, used only once, it becomes the one-time pad. As XOR is its own inverse, decoding is the same as encoding. There is no default key, meaning that `vernam` as the encoding scheme throws a `LookupError` indicating that the _key must be a non-empty string_.
765+
766+
**Codec** | **Conversions** | **Aliases** | **Comment**
767+
:---: | :---: | --- | ---
768+
`vernam` | text <-> Vernam ciphertext | `vernam-key`, `vernam_cipher-My Secret!` | key is case-sensitive and may hold any character
769+
770+
```python
771+
>>> codext.encode("this is a test", "vernam-key")
772+
'\x1f\r\x10\x18E\x10\x18E\x18K\x11\x1c\x18\x11'
773+
>>> codext.decode("\x1f\r\x10\x18E\x10\x18E\x18K\x11\x1c\x18\x11", "vernam-key")
774+
'this is a test'
775+
```
776+
777+
-----
778+
762779
### Vigenere Cipher
763780

764781
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_.

‎src/codext/crypto/__init__.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,6 @@
3232
from .skip import *
3333
from .twosquare import *
3434
from .vic import *
35+
from .vernam import *
3536
from .vigenere import *
3637
from .xor import *

‎src/codext/crypto/vernam.py‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# -*- coding: UTF-8 -*-
2+
"""Vernam Cipher Codec - vernam content encoding.
3+
4+
The Vernam cipher, patented by Gilbert Vernam in 1919, XORs each character of the text with the corresponding character
5+
of a repeated key ; with a random key as long as the text, used only once, it becomes the one-time pad. As XOR is its
6+
own inverse, decoding is the same as encoding.
7+
8+
This codec:
9+
- en/decodes strings from str to str
10+
- en/decodes strings from bytes to bytes
11+
- decodes file content to str (read)
12+
- encodes file content from str to bytes (write)
13+
14+
Reference: https://en.wikipedia.org/wiki/Gilbert_Vernam
15+
"""
16+
from ..__common__ import *
17+
18+
19+
__examples__ = {
20+
'enc(vernam|vernam-cipher)': None,
21+
'enc(vernam-key)': {'this is a test': "\x1f\r\x10\x18E\x10\x18E\x18K\x11\x1c\x18\x11"},
22+
'enc(vernam_cipher-Key)': {'this is a test': "?\r\x108E\x108E\x18k\x11\x1c8\x11"},
23+
'dec(vernam-key)': {"\x1f\r\x10\x18E\x10\x18E\x18K\x11\x1c\x18\x11": 'this is a test'},
24+
'enc-dec(vernam-secret|vernam-a b!)': ["", "this is a test", "@random{256}", "Caf\xe9 €"],
25+
}
26+
__guess__ = ["vernam-key", "vernam-password", "vernam-secret"]
27+
28+
29+
def vernam(key=None):
30+
def code(text, errors="strict"):
31+
if not key:
32+
raise LookupError("Bad parameter for encoding 'vernam': key must be a non-empty string")
33+
r = "".join(chr(ord(c) ^ ord(key[i % len(key)])) for i, c in enumerate(ensure_str(text)))
34+
return r, len(r)
35+
return code
36+
37+
38+
add("vernam", vernam, vernam, r"^vernam(?:[-_]cipher)?(?:[-_](.+))?$", examples=__examples__, guess=__guess__,
39+
transitive=True, penalty=.1)

0 commit comments

Comments
 (0)