def _kdf(self, z: bitarray, klen: int) -> bitarray: # 3.4.3 ct = bitarray(1, 32) t = bitarray() for i in range(math.ceil(klen / self._v)): t = bitarray.concat((t, self._hash(bitarray.concat((z, ct))))) ct = ct + bitarray(1, 32) return t[:klen]
def _padding(self, data: bitarray) -> bitarray: mlen = len(data) data = bitarray.concat((data, bitarray(1, 1))) plen = (-mlen - 65) % 512 data = bitarray.concat((data, bitarray(0, plen))) data = bitarray.concat((data, bitarray(mlen, 64))) return data.split(512)
def _reset_data(self): self._h = (bitarray(0x67452301, 32), bitarray(0xEFCDAB89, 32), bitarray(0x98BADCFE, 32), bitarray(0x10325476, 32), bitarray(0xC3D2E1F0, 32)) self.digest_size = 20 self.hmac_size = 512
def __call__(self, data: bytes) -> Digest: data = bitarray.from_bytes(data) chunks = self._padding(data) h0, h1, h2, h3, h4 = self._h for chunk in chunks: w = chunk.split(32) for i in range(16, 80): # 32 words -> 80 words w.append((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]) << 1) a, b, c, d, e = h0, h1, h2, h3, h4 for i in range(80): if 0 <= i <= 19: f = (b & c) | ((~b) & d) k = bitarray(0x5A827999, 32) elif 20 <= i <= 39: f = b ^ c ^ d k = bitarray(0x6ED9EBA1, 32) elif 40 <= i <= 59: f = (b & c) | (b & d) | (c & d) k = bitarray(0x8F1BBCDC, 32) elif 60 <= i <= 79: f = b ^ c ^ d k = bitarray(0xCA62C1D6, 32) temp = (a << 5) + f + e + k + w[i] a, b, c, d, e = temp, a, b << 30, c, d h0, h1, h2, h3, h4 = h0 + a, h1 + b, h2 + c, h3 + d, h4 + e digest = bitarray.concat((h0, h1, h2, h3, h4)) return Digest(digest.to_bytes())
def _pad10star1(self, data: bitarray) -> bitarray: q = (self._r - len(data) % self._r) // 8 if q == 1: data = bitarray.concat((data, bitarray(0x86, 8))) else: data = bitarray.concat( (data, bitarray(0x06, 8), bitarray(0, 8 * (q - 2)), bitarray(0x80, 8))) return data
def _sponge(self, data: bitarray, dlen: int) -> bitarray: data = self._pad10star1(data) data = self._permute(data) dseq = data.split(self._r) s = bitarray(0, self._b) for di in dseq: s = self._keccak_p(s ^ bitarray.concat((di, bitarray(0, self._c)))) z = bitarray() while len(z) < dlen: z = bitarray.concat((z, s[0:self._r])) s = self._keccak_p(s) z = self._permute(z) return z[0:dlen]
def _identity(self, uid:bitarray, PK) -> bitarray: entlen = bitarray(len(uid), 16) a = self._bytes2bits(self._elem2bytes(self._G.a)) b = self._bytes2bits(self._elem2bytes(self._G.b)) gx = self._bytes2bits(self._elem2bytes(self._G.x)) gy = self._bytes2bits(self._elem2bytes(self._G.y)) ax = self._bytes2bits(self._elem2bytes(PK.x)) ay = self._bytes2bits(self._elem2bytes(PK.y)) return self._hash(bitarray.concat((entlen, uid, a, b, gx, gy, ax, ay)))[:256]
def __call__(self, key: bytes, data: bytes) -> bytes: # padding key if len(key) > self._b // 8: key = self._hash_func(key).digest key = bitarray.from_bytes(key) k = bitarray.concat((key, bitarray(0, self._b - len(key)))) # process data data = bitarray.from_bytes(data) si = k ^ self._ipad data = bitarray.concat((si, data)) data = self._hash(data) so = k ^ self._opad data = bitarray.concat((so, data)) data = self._hash(data) return Digest(data.to_bytes())
def _reset_data(self): rc_int = [ 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 ] self._rc = [bitarray(c, 64).reverse() for c in rc_int] self._rotc = [[0, 36, 3, 41, 18], [1, 44, 10, 45, 2], [62, 6, 43, 15, 61], [28, 55, 25, 21, 56], [27, 20, 39, 8, 14]]
def __init__(self, hash_func: callable): self._hash_func = hash_func self._n = hash_func.digest_size * 8 self._b = hash_func.hmac_size self._ipad = bitarray.concat([bitarray(0x36, 8)] * (self._b // 8)) self._opad = bitarray.concat([bitarray(0x5C, 8)] * (self._b // 8))