Skip to content

Commit 37a609c

Browse files
committed
Added hash codecs
1 parent beeb8ad commit 37a609c

4 files changed

Lines changed: 110 additions & 4 deletions

File tree

codext/common/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from .a1z26 import *
33
from .cases import *
44
from .dummy import *
5+
from .hashes import *
56
from .octal import *
67
from .ordinal import *
78

codext/common/hashes.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# -*- coding: UTF-8 -*-
2+
"""Case Codecs - string hashing.
3+
4+
These are codecs for hashing strings, for use with other codecs in encoding chains.
5+
6+
These codecs:
7+
- transform strings from str to str
8+
- transform strings from bytes to bytes
9+
- transform file content from str to bytes (write)
10+
"""
11+
import hashlib
12+
13+
from ..__common__ import add, b, PY3
14+
15+
16+
# Python2/3-compatible hash functions
17+
add("md5", lambda s, error="strict": (hashlib.md5(b(s)).hexdigest(), len(s)), guess=None)
18+
add("sha1", lambda s, error="strict": (hashlib.sha1(b(s)).hexdigest(), len(s)), guess=None)
19+
add("sha224", lambda s, error="strict": (hashlib.sha224(b(s)).hexdigest(), len(s)), guess=None)
20+
add("sha256", lambda s, error="strict": (hashlib.sha256(b(s)).hexdigest(), len(s)), guess=None)
21+
add("sha384", lambda s, error="strict": (hashlib.sha384(b(s)).hexdigest(), len(s)), guess=None)
22+
add("sha512", lambda s, error="strict": (hashlib.sha512(b(s)).hexdigest(), len(s)), guess=None)
23+
24+
25+
# Python3 only
26+
if PY3:
27+
def blake_hash(c):
28+
def _hash_transform(l):
29+
l = (l or "64").lstrip("_-")
30+
def _encode(data, error="strict"):
31+
return getattr(hashlib, "blake2%s" % c)(b(data), digest_size=int(l)).hexdigest(), len(data)
32+
return _encode
33+
return _hash_transform
34+
35+
add("blake2b", blake_hash("b"), pattern=r"^blake2b(|[-_](?:[1-9]|[1-5]\d|6[0-4]))$", guess=None)
36+
add("blake2s", blake_hash("s"), pattern=r"^blake2s(|[-_](?:[1-9]|[1-2]\d|3[0-2]))$", guess=None)
37+
38+
def shake_hash(i):
39+
def _hash_transform(l):
40+
l = (l or str(i)).lstrip("_-")
41+
def _encode(data, error="strict"):
42+
return getattr(hashlib, "shake_%d" % i)(b(data)).hexdigest(int(l)), len(data)
43+
return _encode
44+
return _hash_transform
45+
46+
add("shake_128", shake_hash(128), pattern=r"^shake[-_]?128(|[-_][1-9]\d*)$", guess=None)
47+
add("shake_256", shake_hash(256), pattern=r"^shake[-_]?256(|[-_][1-9]\d*)$", guess=None)
48+
49+
add("sha3_224", lambda s, error="strict": (hashlib.sha3_224(b(s)).hexdigest(), len(s)), pattern=r"^sha3[-_]224$",
50+
guess=None)
51+
add("sha3_256", lambda s, error="strict": (hashlib.sha3_256(b(s)).hexdigest(), len(s)), pattern=r"^sha3[-_]256$",
52+
guess=None)
53+
add("sha3_384", lambda s, error="strict": (hashlib.sha3_384(b(s)).hexdigest(), len(s)), pattern=r"^sha3[-_]384$",
54+
guess=None)
55+
add("sha3_512", lambda s, error="strict": (hashlib.sha3_512(b(s)).hexdigest(), len(s)), pattern=r"^sha3[-_]512$",
56+
guess=None)
57+

docs/manipulations.md

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
# String manipulations
1+
# String tranformations
22

3-
`codext` also defines multiple dummy string manipulation codecs, essentially for use with the CLI tool and for the sake of simplicity.
3+
`codext` also defines multiple dummy string manipulation/transformation codecs, essentially for use with the CLI tool and for the sake of simplicity.
44

55
-----
66

77
### Case-related operations
88

9-
These "encodings" are simple string transformations, including `str`'s methods.
9+
These transformation functions are simple string transformations, including `str`'s methods.
1010

1111
**Codec** | **Conversions** | **Aliases** | **Comment**
1212
:---: | :---: | --- | ---
@@ -39,7 +39,7 @@ test-string
3939

4040
### Dummy string operations
4141

42-
These "encodings" are also simple string transformations.
42+
These transformation functions are simple string transformations.
4343

4444
**Codec** | **Conversions** | **Aliases** | **Comment**
4545
:---: | :---: | --- | ---
@@ -61,3 +61,27 @@ Or using encodings chaining:
6161
$ echo -en "test string" | codext encode reverse-words reverse
6262
string test
6363
```
64+
65+
-----
66+
67+
### Hash functions
68+
69+
These one-way transformation functions rely on the native [`hashlib`](https://docs.python.org/3/library/hashlib.html) library.
70+
71+
**Codec** | **Conversions** | **Aliases** | **Comment**
72+
:---: | :---: | --- | ---
73+
`blake2b` | data --> Blake2b(data, length) | | Python3 only, parametrized ; *length* belongs to [1,64]
74+
`blake2s` | data --> Blake2s(data, length) | | Python3 only, parametrized ; *length* belongs to [1,32]
75+
`md5` | data --> MD5(data) | |
76+
`sha1` | data --> SHA1(data) | |
77+
`sha224` | data --> SHA224(data) | |
78+
`sha256` | data --> SHA256(data) | |
79+
`sha384` | data --> SHA384(data) | |
80+
`sha3_224` | data --> SHA3-224(data) | | Python3 only
81+
`sha3_256` | data --> SHA3-256(data) | | Python3 only
82+
`sha3_384` | data --> SHA3-384(data) | | Python3 only
83+
`sha3_512` | data --> SHA3-512(data) | | Python3 only
84+
`sha512` | data --> SHA512(data) | |
85+
`shake_128` | data --> Shake128(data, length) | | Python3 only, parametrized ; *length* belongs to [1,[
86+
`shake_256` | data --> Shake256(data, length) | | Python3 only, parametrized ; *length* belongs to [1,[
87+

tests/test_manual.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,30 @@ def test_codec_dummy_str_manips(self):
9696
self.assertEqual(codecs.decode(STR, "reverse_words"), "siht si a tset")
9797
self.assertEqual(codecs.decode(STR.split()[0], "reverse"), codecs.decode(STR.split()[0], "reverse-words"))
9898

99+
def test_codec_hash_functions(self):
100+
STR = b"This is a test string!"
101+
for h in ["md5", "sha1", "sha224", "sha256", "sha384", "sha512"]:
102+
self.assertIsNotNone(codecs.encode(STR, h))
103+
self.assertRaises(NotImplementedError, codecs.decode, STR, h)
104+
if PY3:
105+
self.assertEqual(len(codecs.encode(STR, "blake2b_64")), 128)
106+
self.assertRaises(LookupError, codecs.encode, STR, "blake2b_0")
107+
self.assertRaises(LookupError, codecs.encode, STR, "blake2b-65")
108+
self.assertRaises(NotImplementedError, codecs.decode, STR, "blake2b")
109+
self.assertEqual(len(codecs.encode(STR, "blake2s_32")), 64)
110+
self.assertRaises(LookupError, codecs.encode, STR, "blake2s_0")
111+
self.assertRaises(LookupError, codecs.encode, STR, "blake2s-33")
112+
self.assertRaises(NotImplementedError, codecs.decode, STR, "blake2s")
113+
self.assertIsNotNone(codecs.encode(STR, "shake128"))
114+
self.assertRaises(LookupError, codecs.encode, STR, "shake128_0")
115+
self.assertRaises(NotImplementedError, codecs.decode, STR, "shake128")
116+
self.assertIsNotNone(codecs.encode(STR, "shake256"))
117+
self.assertRaises(LookupError, codecs.encode, STR, "shake256-0")
118+
self.assertRaises(NotImplementedError, codecs.decode, STR, "shake256")
119+
for h in ["sha3_224", "sha3_256", "sha3_384", "sha3_512"]:
120+
self.assertIsNotNone(codecs.encode(STR, h))
121+
self.assertRaises(NotImplementedError, codecs.decode, STR, h)
122+
99123
def test_codec_markdown(self):
100124
HTM = "<h1>Test title</h1>\n\n<p>Test paragraph</p>\n"
101125
MD = "# Test title\n\nTest paragraph"

0 commit comments

Comments
 (0)