kryptools 1.0.2__tar.gz → 1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {kryptools-1.0.2 → kryptools-1.1}/PKG-INFO +6 -1
- {kryptools-1.0.2 → kryptools-1.1}/README.md +5 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/__init__.py +4 -2
- kryptools-1.1/kryptools/keccak.py +203 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/la.py +6 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/poly.py +9 -1
- kryptools-1.1/kryptools/sha1.py +86 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools.egg-info/PKG-INFO +6 -1
- {kryptools-1.0.2 → kryptools-1.1}/kryptools.egg-info/SOURCES.txt +5 -1
- {kryptools-1.0.2 → kryptools-1.1}/pyproject.toml +1 -1
- kryptools-1.1/tests/test_keccak.py +54 -0
- kryptools-1.1/tests/test_sha1.py +16 -0
- {kryptools-1.0.2 → kryptools-1.1}/LICENSE +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/GF2.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/Zmod.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/aes.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/blockcipher.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/conway_polynomials.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/des.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/dlp.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/dlp_bsgs.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/dlp_ic.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/dlp_qs.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/dlp_rho.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/ec.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/factor.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/factor_dix.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/factor_ecm.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/factor_fmt.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/factor_pm1.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/factor_qs.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/factor_rho.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/intfuncs.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/lat.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/nt.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools/primes.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools.egg-info/dependency_links.txt +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/kryptools.egg-info/top_level.txt +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/setup.cfg +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/tests/test_GF2.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/tests/test_Zmod.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/tests/test_aes.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/tests/test_des.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/tests/test_dlog.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/tests/test_ec.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/tests/test_factor.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/tests/test_factor_fmt.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/tests/test_factor_pm1.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/tests/test_factor_qs.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/tests/test_intfuncs.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/tests/test_la.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/tests/test_lat.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/tests/test_nt.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/tests/test_poly.py +0 -0
- {kryptools-1.0.2 → kryptools-1.1}/tests/test_primes.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kryptools
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1
|
|
4
4
|
Summary: Implemenation of same basic algorithms used in cryptography.
|
|
5
5
|
Author-email: Gerald Teschl <gerald.teschl@univie.ac.at>
|
|
6
6
|
License: MIT
|
|
@@ -49,5 +49,10 @@ The tools contained are:
|
|
|
49
49
|
* AESCipher: individual AES operations
|
|
50
50
|
* DESCipher: individual DES operations
|
|
51
51
|
|
|
52
|
+
* SHA1
|
|
53
|
+
* Keccak individual sponge operations
|
|
54
|
+
* SHA3
|
|
55
|
+
* SHAKE
|
|
56
|
+
|
|
52
57
|
Documentation can be found in the jupyter notebook
|
|
53
58
|
(mostly done, but might not contain everything: use the force, read the source).
|
|
@@ -31,5 +31,10 @@ The tools contained are:
|
|
|
31
31
|
* AESCipher: individual AES operations
|
|
32
32
|
* DESCipher: individual DES operations
|
|
33
33
|
|
|
34
|
+
* SHA1
|
|
35
|
+
* Keccak individual sponge operations
|
|
36
|
+
* SHA3
|
|
37
|
+
* SHAKE
|
|
38
|
+
|
|
34
39
|
Documentation can be found in the jupyter notebook
|
|
35
40
|
(mostly done, but might not contain everything: use the force, read the source).
|
|
@@ -3,9 +3,9 @@ Implemenation of same basic algorithms used in cryptography.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
__author__ = "Gerald Teschl"
|
|
6
|
-
__copyright__ = "Copyright 2024, Gerald Teschl"
|
|
6
|
+
__copyright__ = "Copyright 2024-2025, Gerald Teschl"
|
|
7
7
|
__license__ = "MIT License"
|
|
8
|
-
__version__ = "1.
|
|
8
|
+
__version__ = "1.1"
|
|
9
9
|
__email__ = "Gerald.Teschl@univie.ac.at"
|
|
10
10
|
|
|
11
11
|
from .nt import egcd, cf, convergents, legendre_symbol, jacobi_symbol, sqrt_mod, euler_phi, carmichael_lambda, moebius_mu, is_carmichael_number, order, crt
|
|
@@ -22,3 +22,5 @@ from .GF2 import GF2, GF2_aes, GF2_miniaes, GF2_ghash
|
|
|
22
22
|
from .blockcipher import BlockCipher, bytexor
|
|
23
23
|
from .aes import AESKeySchedule, AESCipher, AESBlockCipher
|
|
24
24
|
from .des import list2int, int2list, permute, invert_permutation, rotate_left, SDESKeySchedule, SDESCipher, DESKeySchedule, DESCipher, DESBlockCipher
|
|
25
|
+
from .keccak import Keccak, SHA3, SHAKE
|
|
26
|
+
from .sha1 import SHA1
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Keccak Sponge, SHA3, SHAKE
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Keccak:
|
|
7
|
+
"Keccak sponge"
|
|
8
|
+
MASK_64 = (1 << 64) - 1
|
|
9
|
+
rounds = 24
|
|
10
|
+
|
|
11
|
+
def __init__(self, rate: int = 1088):
|
|
12
|
+
if rate % 64:
|
|
13
|
+
raise ValueError(f"Rate {rate} must be a multiple of 64.")
|
|
14
|
+
self.pad = [b'\x81', b'\x01', b'\x80']
|
|
15
|
+
self.rate = rate // 8 # in bytes
|
|
16
|
+
self.reset()
|
|
17
|
+
|
|
18
|
+
def reset(self):
|
|
19
|
+
self.state = [0] * 25
|
|
20
|
+
self.lfsr = 1
|
|
21
|
+
self.buffer = b''
|
|
22
|
+
self.rnd_bytes = None
|
|
23
|
+
|
|
24
|
+
def __repr__(self):
|
|
25
|
+
out = ""
|
|
26
|
+
for i in range(5):
|
|
27
|
+
for j in range(5):
|
|
28
|
+
out += "%016x" % self.state[5 * i + j]
|
|
29
|
+
if j < 4:
|
|
30
|
+
out += " "
|
|
31
|
+
if i < 4:
|
|
32
|
+
out += "\n"
|
|
33
|
+
return out
|
|
34
|
+
|
|
35
|
+
def f(self) -> None:
|
|
36
|
+
"Apply f to the state."
|
|
37
|
+
self.lfsr = 1
|
|
38
|
+
for r in range(Keccak.rounds):
|
|
39
|
+
self.theta()
|
|
40
|
+
self.pi()
|
|
41
|
+
self.rho()
|
|
42
|
+
self.chi()
|
|
43
|
+
self.iota()
|
|
44
|
+
|
|
45
|
+
def absorb(self, msg: bytes | str) -> None:
|
|
46
|
+
"Absorbe a message into the state."
|
|
47
|
+
if isinstance(msg, str):
|
|
48
|
+
msg = msg.encode()
|
|
49
|
+
msg = self.buffer + msg
|
|
50
|
+
msg_len = len(msg) - len(msg) % self.rate
|
|
51
|
+
msg, self.buffer = msg[:msg_len], msg[msg_len:]
|
|
52
|
+
for i in range(len(msg)//self.rate):
|
|
53
|
+
self.absorb_block(msg[i*self.rate:(i+1)*self.rate])
|
|
54
|
+
|
|
55
|
+
def absorb_block(self, block: bytes) -> None:
|
|
56
|
+
"Absorbe a block into the state. Pad the block if neccessary."
|
|
57
|
+
|
|
58
|
+
if len(block) > self.rate:
|
|
59
|
+
raise ValueError(f"Block must be at most {self.rate} bytes.")
|
|
60
|
+
padlen = self.rate - len(block)
|
|
61
|
+
if padlen == 1:
|
|
62
|
+
block += self.pad[0]
|
|
63
|
+
else:
|
|
64
|
+
block += self.pad[1] + (b'\x00' * (padlen - 2)) + self.pad[2]
|
|
65
|
+
for i in range(len(block)//8):
|
|
66
|
+
self.state[i] ^= int.from_bytes(block[i*8:(i+1)*8], 'little')
|
|
67
|
+
self.f()
|
|
68
|
+
|
|
69
|
+
def squeeze(self, r: int) -> bytes:
|
|
70
|
+
"Squeesze out 'r' bytes from the state."
|
|
71
|
+
if r <= 0:
|
|
72
|
+
raise ValueError("Number of bytes must be positive.")
|
|
73
|
+
if self.rnd_bytes is None:
|
|
74
|
+
self.absorb_block(self.buffer)
|
|
75
|
+
self.rnd_bytes = self.extract_block()
|
|
76
|
+
while r > len(self.rnd_bytes):
|
|
77
|
+
self.f()
|
|
78
|
+
self.rnd_bytes += self.extract_block()
|
|
79
|
+
out, self.rnd_bytes = self.rnd_bytes[:r], self.rnd_bytes[r:]
|
|
80
|
+
return out
|
|
81
|
+
|
|
82
|
+
def extract_block(self) -> bytes:
|
|
83
|
+
"Extract one block from the state."
|
|
84
|
+
out = b''
|
|
85
|
+
for i in range(self.rate//8):
|
|
86
|
+
out += self.state[i].to_bytes(8, 'little')
|
|
87
|
+
return out
|
|
88
|
+
|
|
89
|
+
def left_rotate(self, w: int, n: int) -> int:
|
|
90
|
+
"Left rotate a 64-bit integer w by n bits."
|
|
91
|
+
return ((w << n) & Keccak.MASK_64) | (w >> (64 - n))
|
|
92
|
+
|
|
93
|
+
def theta(self) -> None:
|
|
94
|
+
"Apply Theta to the state."
|
|
95
|
+
v = [0] * 5
|
|
96
|
+
for j in range(5):
|
|
97
|
+
for i in range(5):
|
|
98
|
+
v[j] ^= self.state[5 * i + j]
|
|
99
|
+
|
|
100
|
+
for j in range(5):
|
|
101
|
+
h = v[(j + 4) % 5] ^ self.left_rotate(v[(j + 1) % 5], 1)
|
|
102
|
+
for i in range(5):
|
|
103
|
+
self.state[5 * i + j] ^= h
|
|
104
|
+
|
|
105
|
+
def pi(self) -> None:
|
|
106
|
+
"Apply Pi to the state."
|
|
107
|
+
i, j = 0, 1
|
|
108
|
+
|
|
109
|
+
for t in range(1, 25):
|
|
110
|
+
idx = 5 * i + j
|
|
111
|
+
w = (t * (t + 1) // 2) % 64
|
|
112
|
+
self.state[idx] = self.left_rotate(self.state[idx], w)
|
|
113
|
+
i, j = (3 * i + 2 * j) % 5, i
|
|
114
|
+
|
|
115
|
+
def rho(self) -> None:
|
|
116
|
+
"Apply Rho to the state."
|
|
117
|
+
i, j = 0, 1
|
|
118
|
+
vv = self.state[1]
|
|
119
|
+
|
|
120
|
+
for _ in range(24):
|
|
121
|
+
i, j = (3 * i + 2 * j) % 5, i
|
|
122
|
+
idx = 5 * i + j
|
|
123
|
+
self.state[idx], vv = vv, self.state[idx]
|
|
124
|
+
|
|
125
|
+
def chi(self) -> None:
|
|
126
|
+
"Apply Chi to the state."
|
|
127
|
+
v = [0] * 5
|
|
128
|
+
|
|
129
|
+
for i in range(0, 25, 5):
|
|
130
|
+
for j in range(5):
|
|
131
|
+
v[j] = self.state[i + j]
|
|
132
|
+
for j in range(5):
|
|
133
|
+
self.state[i + j] ^= (v[(j + 1) % 5] ^
|
|
134
|
+
Keccak.MASK_64) & v[(j + 2) % 5]
|
|
135
|
+
|
|
136
|
+
def iota(self) -> None:
|
|
137
|
+
"Apply Iota to the state."
|
|
138
|
+
for w in [0, 1, 3, 7, 15, 31, 63]:
|
|
139
|
+
self.state[0] ^= ((self.lfsr & 1) << w)
|
|
140
|
+
self.lfsr <<= 1
|
|
141
|
+
self.lfsr &= Keccak.MASK_64
|
|
142
|
+
if (self.lfsr & 0x100):
|
|
143
|
+
self.lfsr ^= 0x171
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class SHA3():
|
|
147
|
+
"""
|
|
148
|
+
SHA3 secure hash algorithm
|
|
149
|
+
|
|
150
|
+
Example:
|
|
151
|
+
|
|
152
|
+
>>>sha3 = SHA3(256)
|
|
153
|
+
>>>sha3("abc").hex()
|
|
154
|
+
'3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532'
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
def __init__(self, n: int = 256):
|
|
158
|
+
if n not in (224, 256, 384, 512):
|
|
159
|
+
raise ValueError(f"n must be one of: 224, 256, 384, 512")
|
|
160
|
+
self.keccak = Keccak(rate=1600-2*n)
|
|
161
|
+
self.keccak.pad = [b'\x86', b'\x06', b'\x80']
|
|
162
|
+
self.hash_length = n // 8 # in bytes
|
|
163
|
+
|
|
164
|
+
def __call__(self, msg: bytes | str) -> bytes:
|
|
165
|
+
"Compute the hash of the message given or absorbed."
|
|
166
|
+
self.keccak.reset()
|
|
167
|
+
self.keccak.absorb(msg)
|
|
168
|
+
return self.keccak.squeeze(self.hash_length)
|
|
169
|
+
|
|
170
|
+
def update(self, msg: bytes | str) -> None:
|
|
171
|
+
"Absorb the given message into the sponge."
|
|
172
|
+
self.keccak.absorb(msg)
|
|
173
|
+
|
|
174
|
+
def digest(self, msg: bytes | str | None = None) -> bytes:
|
|
175
|
+
"Compute the hash of the message given or absorbed."
|
|
176
|
+
if msg is not None:
|
|
177
|
+
self.keccak.absorb(msg)
|
|
178
|
+
digest = self.keccak.squeeze(self.hash_length)
|
|
179
|
+
self.keccak.reset()
|
|
180
|
+
return digest
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
class SHAKE():
|
|
184
|
+
"""
|
|
185
|
+
SHAKE Extendable output function
|
|
186
|
+
|
|
187
|
+
Example:
|
|
188
|
+
|
|
189
|
+
>>> shake = SHAKE(b'secret', n = 128)
|
|
190
|
+
>>> shake(8)
|
|
191
|
+
b'O:dn&\\xb2i>'
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
def __init__(self, msg: bytes | str, n: int = 128) -> None:
|
|
195
|
+
if n not in (128, 256):
|
|
196
|
+
raise ValueError(f"n must be one of: 128, 256")
|
|
197
|
+
self.keccak = Keccak(rate=1600-2*n)
|
|
198
|
+
self.keccak.pad = [b'\x9f', b'\x1f', b'\x80']
|
|
199
|
+
self.keccak.absorb(msg)
|
|
200
|
+
|
|
201
|
+
def __call__(self, r: int) -> bytes:
|
|
202
|
+
"Extract `r` bytes."
|
|
203
|
+
return self.keccak.squeeze(r)
|
|
@@ -50,6 +50,12 @@ class Matrix:
|
|
|
50
50
|
out[i] += self.__class__.print_post
|
|
51
51
|
return '\n'.join(out)
|
|
52
52
|
|
|
53
|
+
def _repr_mimebundle_(self, **kwargs):
|
|
54
|
+
return {
|
|
55
|
+
"text/plain": self.__repr__(),
|
|
56
|
+
"text/latex": "$\\displaystyle" + self.latex() + "$"
|
|
57
|
+
}
|
|
58
|
+
|
|
53
59
|
def latex(self) -> str:
|
|
54
60
|
"Produce LaTeX code for the matrix."
|
|
55
61
|
res = "\\begin{pmatrix}\n"
|
|
@@ -44,12 +44,14 @@ class Poly:
|
|
|
44
44
|
def __len__(self):
|
|
45
45
|
return len(self.coeff)
|
|
46
46
|
|
|
47
|
-
def __repr__(self):
|
|
47
|
+
def __repr__(self, latex = False):
|
|
48
48
|
def prx(i: int) -> str:
|
|
49
49
|
if i == 0:
|
|
50
50
|
return ""
|
|
51
51
|
if i == 1:
|
|
52
52
|
return self.__class__.print_x
|
|
53
|
+
if latex:
|
|
54
|
+
return self.__class__.print_x + "^{" + str(i) +"}"
|
|
53
55
|
return self.__class__.print_x + self.__class__.print_pow + str(i)
|
|
54
56
|
|
|
55
57
|
if not self:
|
|
@@ -91,6 +93,12 @@ class Poly:
|
|
|
91
93
|
plus = " + "
|
|
92
94
|
return tmp.strip()
|
|
93
95
|
|
|
96
|
+
def _repr_mimebundle_(self, **kwargs):
|
|
97
|
+
return {
|
|
98
|
+
"text/plain": self.__repr__(),
|
|
99
|
+
"text/latex": "$" + self.__repr__(latex = True) + "$"
|
|
100
|
+
}
|
|
101
|
+
|
|
94
102
|
def __eq__(self, other):
|
|
95
103
|
if not isinstance(other, self.__class__):
|
|
96
104
|
return False
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SHA1
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
class SHA1:
|
|
6
|
+
"SHA1 Hash function"
|
|
7
|
+
|
|
8
|
+
h_init = (0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0)
|
|
9
|
+
|
|
10
|
+
def __init__(self):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
def __call__(self, message: bytes|str, h_init: list = h_init, length: int = None) -> int:
|
|
14
|
+
return self.hash(message, h_init, length)
|
|
15
|
+
|
|
16
|
+
def left_rotate(self, w: int, n: int) -> int:
|
|
17
|
+
"""Left rotate a 32-bit integer w by n bits."""
|
|
18
|
+
return ((w << n) | (w >> (32 - n))) & 0xffffffff
|
|
19
|
+
def pad(self, msg: bytes, length: int = None) -> bytes:
|
|
20
|
+
"""Pad a message. Optionally augment the message length."""
|
|
21
|
+
msg=bytearray(msg)
|
|
22
|
+
l=len(msg)
|
|
23
|
+
if length:
|
|
24
|
+
l+=length
|
|
25
|
+
msg+=b'\x80'+b'\x00'*((55 - l) % 64) # append 1 plus zeros such that the length % 64 = 56
|
|
26
|
+
msg += int(l*8).to_bytes(8, byteorder='big') # add the bit length of the message
|
|
27
|
+
return bytes(msg)
|
|
28
|
+
|
|
29
|
+
def compression_function(self, h: list, chunk: bytes) -> list:
|
|
30
|
+
"""Process a chunk of data and return the new digest variables."""
|
|
31
|
+
assert len(chunk) == 64, "Chunk must be 64 bytes."
|
|
32
|
+
|
|
33
|
+
w = [0] * 80
|
|
34
|
+
|
|
35
|
+
# Break chunk into sixteen 4-byte big-endian words w[i]
|
|
36
|
+
for i in range(16):
|
|
37
|
+
w[i] = int.from_bytes(chunk[i * 4:(i+1) * 4], byteorder='big')
|
|
38
|
+
|
|
39
|
+
# Message schedule: extend the sixteen 32-bit words into eighty 32-bit words
|
|
40
|
+
for i in range(16, 80):
|
|
41
|
+
# Note: SHA-0 differs by not having this leftrotate
|
|
42
|
+
w[i] = self.left_rotate(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1)
|
|
43
|
+
|
|
44
|
+
# Initialize hash value for this chunk
|
|
45
|
+
a, b, c, d, e = h
|
|
46
|
+
|
|
47
|
+
for i in range(80):
|
|
48
|
+
if 0 <= i <= 19:
|
|
49
|
+
# Use alternative 1 for f from FIPS PB 180-1 to avoid bitwise not
|
|
50
|
+
f = d ^ (b & (c ^ d))
|
|
51
|
+
k = 0x5A827999
|
|
52
|
+
elif 20 <= i <= 39:
|
|
53
|
+
f = b ^ c ^ d
|
|
54
|
+
k = 0x6ED9EBA1
|
|
55
|
+
elif 40 <= i <= 59:
|
|
56
|
+
f = (b & c) | (b & d) | (c & d)
|
|
57
|
+
k = 0x8F1BBCDC
|
|
58
|
+
elif 60 <= i <= 79:
|
|
59
|
+
f = b ^ c ^ d
|
|
60
|
+
k = 0xCA62C1D6
|
|
61
|
+
|
|
62
|
+
a, b, c, d, e = ((self.left_rotate(a, 5) + f + e + k + w[i]) & 0xffffffff,
|
|
63
|
+
a, self.left_rotate(b, 30), c, d)
|
|
64
|
+
|
|
65
|
+
# Add this chunk's hash to result so far
|
|
66
|
+
h0 = (h[0] + a) & 0xffffffff
|
|
67
|
+
h1 = (h[1] + b) & 0xffffffff
|
|
68
|
+
h2 = (h[2] + c) & 0xffffffff
|
|
69
|
+
h3 = (h[3] + d) & 0xffffffff
|
|
70
|
+
h4 = (h[4] + e) & 0xffffffff
|
|
71
|
+
|
|
72
|
+
return [h0, h1, h2, h3, h4]
|
|
73
|
+
|
|
74
|
+
def hash(self, message: bytes|str, h_init: list = h_init, length: int = None) -> int:
|
|
75
|
+
"""
|
|
76
|
+
Computes SHA1 of a given message.
|
|
77
|
+
Optinally the initial hash can be given and the length of the message can be augmented.
|
|
78
|
+
"""
|
|
79
|
+
if isinstance(message, str):
|
|
80
|
+
message = message.encode()
|
|
81
|
+
message= self.pad(message, length)
|
|
82
|
+
h = h_init # initialize the status
|
|
83
|
+
for i in range(0, len(message), 64):
|
|
84
|
+
h = self.compression_function(h, message[i:i+64])
|
|
85
|
+
#return (h[0] << 128) | (h[1] << 96) | (h[2] << 64) | (h[3] << 32) | h[4]
|
|
86
|
+
return b''.join(map(lambda n: int.to_bytes(n,4), h))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kryptools
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1
|
|
4
4
|
Summary: Implemenation of same basic algorithms used in cryptography.
|
|
5
5
|
Author-email: Gerald Teschl <gerald.teschl@univie.ac.at>
|
|
6
6
|
License: MIT
|
|
@@ -49,5 +49,10 @@ The tools contained are:
|
|
|
49
49
|
* AESCipher: individual AES operations
|
|
50
50
|
* DESCipher: individual DES operations
|
|
51
51
|
|
|
52
|
+
* SHA1
|
|
53
|
+
* Keccak individual sponge operations
|
|
54
|
+
* SHA3
|
|
55
|
+
* SHAKE
|
|
56
|
+
|
|
52
57
|
Documentation can be found in the jupyter notebook
|
|
53
58
|
(mostly done, but might not contain everything: use the force, read the source).
|
|
@@ -22,11 +22,13 @@ kryptools/factor_pm1.py
|
|
|
22
22
|
kryptools/factor_qs.py
|
|
23
23
|
kryptools/factor_rho.py
|
|
24
24
|
kryptools/intfuncs.py
|
|
25
|
+
kryptools/keccak.py
|
|
25
26
|
kryptools/la.py
|
|
26
27
|
kryptools/lat.py
|
|
27
28
|
kryptools/nt.py
|
|
28
29
|
kryptools/poly.py
|
|
29
30
|
kryptools/primes.py
|
|
31
|
+
kryptools/sha1.py
|
|
30
32
|
kryptools.egg-info/PKG-INFO
|
|
31
33
|
kryptools.egg-info/SOURCES.txt
|
|
32
34
|
kryptools.egg-info/dependency_links.txt
|
|
@@ -42,8 +44,10 @@ tests/test_factor_fmt.py
|
|
|
42
44
|
tests/test_factor_pm1.py
|
|
43
45
|
tests/test_factor_qs.py
|
|
44
46
|
tests/test_intfuncs.py
|
|
47
|
+
tests/test_keccak.py
|
|
45
48
|
tests/test_la.py
|
|
46
49
|
tests/test_lat.py
|
|
47
50
|
tests/test_nt.py
|
|
48
51
|
tests/test_poly.py
|
|
49
|
-
tests/test_primes.py
|
|
52
|
+
tests/test_primes.py
|
|
53
|
+
tests/test_sha1.py
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from kryptools import Keccak, SHA3
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_KECCAK():
|
|
7
|
+
result = [ 0xf1258f7940e1dde7, 0x84d5ccf933c0478a, 0xd598261ea65aa9ee, 0xbd1547306f80494d, 0x8b284e056253d057,
|
|
8
|
+
0xff97a42d7f8e6fd4, 0x90fee5a0a44647c4, 0x8c5bda0cd6192e76, 0xad30a6f71b19059c, 0x30935ab7d08ffc64,
|
|
9
|
+
0xeb5aa93f2317d635, 0xa9a6e6260d712103, 0x81a57c16dbcf555f, 0x43b831cd0347c826, 0x1f22f1a11a5569f,
|
|
10
|
+
0x5e5635a21d9ae61, 0x64befef28cc970f2, 0x613670957bc46611, 0xb87c5a554fd00ecb, 0x8c3ee88a1ccf32c8,
|
|
11
|
+
0x940c7922ae3a2614, 0x1841f924a2c509e4, 0x16f53526e70465c2, 0x75f644e97f30a13b, 0xeaf1ff7b5ceca249 ]
|
|
12
|
+
keccak = Keccak()
|
|
13
|
+
keccak.f()
|
|
14
|
+
assert keccak.state == result
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# https://www.di-mgt.com.au/sha_testvectors.html
|
|
18
|
+
all_tests = [
|
|
19
|
+
{"message" : { "data" : "abc", "count" : 1},
|
|
20
|
+
"SHA-3-224" : "e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf",
|
|
21
|
+
"SHA-3-256" : "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532",
|
|
22
|
+
"SHA-3-384" : "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25",
|
|
23
|
+
"SHA-3-512" : "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"
|
|
24
|
+
},
|
|
25
|
+
{"message" : { "data" : "", "count" : 1},
|
|
26
|
+
"SHA-3-224" : "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7",
|
|
27
|
+
"SHA-3-256" : "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a",
|
|
28
|
+
"SHA-3-384" : "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004",
|
|
29
|
+
"SHA-3-512" : "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"
|
|
30
|
+
},
|
|
31
|
+
{"message" : { "data" : "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "count" : 1},
|
|
32
|
+
"SHA-3-224" : "8a24108b154ada21c9fd5574494479ba5c7e7ab76ef264ead0fcce33",
|
|
33
|
+
"SHA-3-256" : "41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376",
|
|
34
|
+
"SHA-3-384" : "991c665755eb3a4b6bbdfb75c78a492e8c56a22c5c4d7e429bfdbc32b9d4ad5aa04a1f076e62fea19eef51acd0657c22",
|
|
35
|
+
"SHA-3-512" : "04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e"
|
|
36
|
+
},
|
|
37
|
+
{"message" : { "data" : "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", "count" : 1},
|
|
38
|
+
"SHA-3-224" : "543e6868e1666c1a643630df77367ae5a62a85070a51c14cbf665cbc",
|
|
39
|
+
"SHA-3-256" : "916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18",
|
|
40
|
+
"SHA-3-384" : "79407d3b5916b59c3e30b09822974791c313fb9ecc849e406f23592d04f625dc8c709b98b43b3852b337216179aa7fc7",
|
|
41
|
+
"SHA-3-512" : "afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185"
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
def test_SHA3():
|
|
46
|
+
for test in all_tests:
|
|
47
|
+
msg = bytes(test["message"]["data"], 'utf-8')
|
|
48
|
+
for key in test:
|
|
49
|
+
if key[:5] != "SHA-3":
|
|
50
|
+
continue
|
|
51
|
+
n = int(key[6:])
|
|
52
|
+
h = int(test[key], 16)
|
|
53
|
+
k = SHA3(n)(msg)
|
|
54
|
+
assert int.from_bytes(k, 'big') == h, f"{n}: {msg}"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from kryptools import SHA1
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# tests from https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf
|
|
7
|
+
|
|
8
|
+
test_vectors = [
|
|
9
|
+
[b'abc', 0xA9993E364706816ABA3E25717850C26C9CD0D89D ],
|
|
10
|
+
[b'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', 0x84983E441C3BD26EBAAE4AA1F95129E5E54670F1]
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
def test_sha1():
|
|
14
|
+
sha1 = SHA1()
|
|
15
|
+
for msg, digest in test_vectors:
|
|
16
|
+
assert int.from_bytes(sha1(msg)) == digest
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|