Skip to content

Commit 68b9aef

Browse files
committed
Added bacon codec
1 parent ae87a80 commit 68b9aef

1 file changed

Lines changed: 149 additions & 0 deletions

File tree

codext/crypto/bacon.py

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# -*- coding: UTF-8 -*-
2+
"""Bacon's Cipher Codec - bacon 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+
Reference: https://en.wikipedia.org/wiki/Bacon%27s_cipher
11+
"""
12+
from ..__common__ import *
13+
14+
15+
ENCMAP = {
16+
'A': "aaaaa",
17+
}
18+
REPLACE_CHAR = "?"
19+
20+
#FIXME
21+
"""
22+
VERSION 1
23+
24+
Letter Code Binary
25+
A aaaaa 00000
26+
B aaaab 00001
27+
C aaaba 00010
28+
D aaabb 00011
29+
E aabaa 00100
30+
F aabab 00101
31+
G aabba 00110
32+
H aabbb 00111
33+
I, J abaaa 01000
34+
K abaab 01001
35+
L ababa 01010
36+
M ababb 01011
37+
38+
Letter Code Binary
39+
N abbaa 01100
40+
O abbab 01101
41+
P abbba 01110
42+
Q abbbb 01111
43+
R baaaa 10000
44+
S baaab 10001
45+
T baaba 10010
46+
U, V baabb 10011
47+
W babaa 10100
48+
X babab 10101
49+
Y babba 10110
50+
Z babbb 10111
51+
52+
Letter Code Binary
53+
A aaaaa 00000
54+
B aaaab 00001
55+
C aaaba 00010
56+
D aaabb 00011
57+
E aabaa 00100
58+
F aabab 00101
59+
G aabba 00110
60+
H aabbb 00111
61+
I abaaa 01000
62+
J abaab 01001
63+
K ababa 01010
64+
L ababb 01011
65+
M abbaa 01100
66+
67+
VERSION 2
68+
69+
Letter Code Binary
70+
N abbab 01101
71+
O abbba 01110
72+
P abbbb 01111
73+
Q baaaa 10000
74+
R baaab 10001
75+
S baaba 10010
76+
T baabb 10011
77+
U babaa 10100
78+
V babab 10101
79+
W babba 10110
80+
X babbb 10111
81+
Y bbaaa 11000
82+
Z bbaab 11001
83+
"""
84+
85+
class BaconError(ValueError):
86+
pass
87+
88+
89+
class BaconDecodeError(BaconError):
90+
pass
91+
92+
93+
class BaconEncodeError(BaconError):
94+
pass
95+
96+
97+
def bacon_encode(code):
98+
def encode(text, errors="strict"):
99+
std0, stdn = [c for c in STD[0]], [c for c in STD[code]]
100+
spec0, specn = SPEC[0].split(), SPEC[code].split()
101+
mapping = {d: e for d, e in zip(std0 + spec0, stdn + specn)}
102+
r = ""
103+
for i, c in enumerate(ensure_str(text)):
104+
try:
105+
r += mapping[c]
106+
except KeyError:
107+
if errors == "strict":
108+
raise BaconEncodeError("'bacon' codec can't encode"
109+
" character '{}' in position {}"
110+
.format(c, i))
111+
elif errors == "replace":
112+
r += REPLACE_CHAR
113+
elif errors == "ignore":
114+
continue
115+
else:
116+
raise ValueError("Unsupported error handling {}"
117+
.format(errors))
118+
return r, len(text)
119+
return encode
120+
121+
122+
def bacon_decode(code):
123+
def decode(text, errors="strict"):
124+
std0, stdn = [c for c in STD[0]], [c for c in STD[code]]
125+
spec0, specn = SPEC[0].split(), SPEC[code].split()
126+
mapping = {e: d for d, e in zip(std0 + spec0, stdn + specn)}
127+
r = ""
128+
for i, c in enumerate(ensure_str(text)):
129+
try:
130+
r += mapping[c]
131+
except KeyError:
132+
if errors == "strict":
133+
raise BaconDecodeError("'bacon' codec can't decode"
134+
" character '{}' in position {}"
135+
.format(c, i))
136+
elif errors == "replace":
137+
r += REPLACE_CHAR
138+
elif errors == "ignore":
139+
continue
140+
else:
141+
raise ValueError("Unsupported error handling {}"
142+
.format(errors))
143+
return r, len(text)
144+
return decode
145+
146+
147+
# note: the integer behind "bacon" is captured for sending to the
148+
# parametrizable encode and decode functions "bacon_**code"
149+
add("bacon", bacon_encode, bacon_decode, r"bacon(?:onian[-_]cipher)$")

0 commit comments

Comments
 (0)