Skip to content

Commit 6076259

Browse files
committed
Added new codec: shift
1 parent 0372892 commit 6076259

6 files changed

Lines changed: 97 additions & 1 deletion

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ This library extends the native `codecs` library and provides some new encodings
2929
`radio` | Radio <-> text | aka NATO or radio phonetic alphabet
3030
`resistor` | Resistor <-> text | aka resistor color codes
3131
`rot-N` | ROT(N) <-> text | aka Caesar cipher (N belongs to [1,25])
32+
`shift` | shift(N) <-> text | shift ordinals with N (belongs to [1,255])
3233
`url` | URL <-> text | aka URL encoding
3334
`xor-N` | XOR(N) <-> text | XOR with a single byte (N belongs to [1,255])
3435
`whitespace` | Whitespaces <-> text | replaces bits with whitespaces and tabs

codext/VERSION.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.4.3
1+
1.4.4

codext/crypto/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
from .bacon import *
55
from .barbie import *
66
from .rotn import *
7+
from .shift import *
78
from .xor_byte import *

codext/crypto/shift.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# -*- coding: UTF-8 -*-
2+
"""Shift-N Codec - Shift-ordinal-with-N content encoding.
3+
4+
This codec:
5+
- en/decodes strings from str to str
6+
- en/decodes strings from bytes to bytes
7+
- decodes file content to str (read)
8+
- encodes file content from str to bytes (write)
9+
"""
10+
from ..__common__ import *
11+
12+
13+
def ord_shift_decode(i):
14+
return ord_shift_encode(-i)
15+
16+
17+
def ord_shift_encode(i):
18+
def encode(text, errors="strict"):
19+
r = "".join(chr((ord(c) + i) % 256) for c in text)
20+
return r, len(r)
21+
return encode
22+
23+
24+
add("shiftN", ord_shift_encode, ord_shift_decode,
25+
r"(?i)(?:ord(?:inal)?[-_]?)?shift[-_]?([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$")

docs/ciphers.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,27 @@ This is a dynamic encoding, that is, it can be called with an integer to define
130130

131131
-----
132132

133+
### Shift
134+
135+
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.
136+
137+
**Codec** | **Conversions** | **Aliases** | **Comment**
138+
:---: | :---: | --- | ---
139+
`shiftN` | shift(1) <-> text | `shift1`, `shift-1`, `shift_1` |
140+
`shiftN` | shift(X) <-> text | ... |
141+
`shiftN` | shift(255) <-> text | `shift255`, `shift-255`, `shift_255` |
142+
143+
```python
144+
>>> codext.encode("this is a test", "shift-3")
145+
'wklv#lv#d#whvw'
146+
>>> codext.decode("wklv#lv#d#whvw", "shift10")
147+
'mabl\x19bl\x19Z\x19m^lm'
148+
>>> codext.encode("mabl\x19bl\x19Z\x19m^lm", "ordshift_7")
149+
'this is a test'
150+
```
151+
152+
-----
153+
133154
### XOR with 1 byte
134155

135156
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.

tests/test_shift.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#!/usr/bin/env python
2+
# -*- coding: UTF-8 -*-
3+
"""Shift codecs tests.
4+
5+
"""
6+
import os
7+
from six import binary_type, string_types
8+
from unittest import TestCase
9+
10+
from codext.__common__ import *
11+
12+
13+
class TestCodecsShift(TestCase):
14+
def test_codec_shift(self):
15+
STR = "this is a test"
16+
SH1 = "uijt!jt!b!uftu"
17+
SH9 = "}qr|)r|)j)}n|}"
18+
TFILE = "test-codec-shift.txt"
19+
self.assertTrue(isinstance(codecs.encode(STR, "shift-200"), string_types))
20+
self.assertEqual(codecs.encode(STR, "shift_1"), codecs.decode(STR, "shift_255"))
21+
self.assertEqual(codecs.encode(STR, "ord-shift_1"), SH1)
22+
self.assertEqual(codecs.encode(STR, "ordinal_shift-1"), SH1)
23+
self.assertEqual(codecs.encode(STR, "shift1"), SH1)
24+
self.assertEqual(codecs.encode(STR, "ordshift1"), SH1)
25+
self.assertEqual(codecs.encode(STR, "ordinalshift1"), SH1)
26+
self.assertEqual(codecs.encode(STR, "shift_9"), SH9)
27+
self.assertEqual(codecs.encode(STR, "ord_shift_9"), SH9)
28+
self.assertEqual(codecs.encode(STR, "ord-shift-9"), SH9)
29+
self.assertEqual(codecs.decode(SH1, "shift1"), STR)
30+
self.assertRaises(LookupError, codecs.decode, STR, "shift0")
31+
self.assertRaises(LookupError, codecs.decode, STR, "shift--10")
32+
self.assertRaises(LookupError, codecs.decode, STR, "shift256")
33+
self.assertRaises(LookupError, codecs.decode, STR, "shift300")
34+
s = STR
35+
for i in range(1, 256):
36+
old = s
37+
s = codecs.encode(s, "shift1")
38+
self.assertEqual(codecs.decode(s, "shift1"), old)
39+
self.assertTrue(not PY3 or isinstance(codecs.encode(b(STR), "shift1"), binary_type))
40+
with codecs.open(TFILE, 'w', encoding="shift-1") as f:
41+
f.write(b(STR))
42+
with open(TFILE) as f:
43+
r = f.read().strip()
44+
self.assertEqual(SH1, r)
45+
with codecs.open(TFILE, encoding="shift-1") as f:
46+
s = f.read().strip()
47+
self.assertEqual(STR, ensure_str(s))
48+
os.remove(TFILE)

0 commit comments

Comments
 (0)