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 _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 decrypt_data(self, C: bitarray, SK: int) -> bitarray: c1, C = C[:self._byteLen * 8 * 2 + 8], C[self._byteLen * 8 * 2 + 8:] c3, c2 = C[:self._v], C[self._v:] c1 = self._bytes2point(self._bits2bytes(c1)) p2 = SK * c1 x2 = self._bytes2bits(self._elem2bytes(p2.x)) y2 = self._bytes2bits(self._elem2bytes(p2.y)) t = self._kdf(bitarray.concat((x2, y2)), len(c2)) M = c2 ^ t u = self._hash(bitarray.concat((x2, M, y2))) assert u == c3 return M
def encrypt_data(self, M: bitarray, PK: ECC) -> bitarray: k = random.randint(1, self._n - 1) c1 = k * self._G c1 = self._bytes2bits(self._point2bytes(c1)) p2 = k * PK x2 = self._bytes2bits(self._elem2bytes(p2.x)) y2 = self._bytes2bits(self._elem2bytes(p2.y)) t = self._kdf(bitarray.concat((x2, y2)), len(M)) c2 = M ^ t c3 = self._hash(bitarray.concat((x2, M, y2))) C = bitarray.concat((c1, c3, c2)) return C
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 __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 __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 _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 verify(self, M:bytes, sign:tuple, uid:bytes, PK): r, s = sign r, s = self._bytes2int(r), self._bytes2int(s) assert 1 <= r <= self._n-1 and 1 <= s <= self._n-1 M, uid = self._bytes2bits(M), self._bytes2bits(uid) Z = self._identity(uid, PK) M = bitarray.concat((Z, M)) e = self._bytes2int(self._bits2bytes(self._hash(M))) t = (r + s) % self._n assert t != 0 P = s * self._G + t * PK x1 = self._elem2int(P.x) R = (e + x1) % self._n return R == r
def sign(self, M:bytes, uid:bytes, SK:int) -> tuple: M, uid = self._bytes2bits(M), self._bytes2bits(uid) PK = SK * self._G Z = self._identity(uid, PK) M = bitarray.concat((Z, M)) e = self._bytes2int(self._bits2bytes(self._hash(M))) while True: k = random.randint(1, self._n-1) P = k * self._G x1 = self._elem2int(P.x) r = (e + x1) % self._n if r == 0 or r+k == self._n: continue s = (inverse(1+SK, self._n) * (k-r*SK)) % self._n if s != 0: break r, s = self._int2bytes(r, self._byteLen), self._int2bytes(s, self._byteLen) return (r, s)
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))
def _permute(self, b: bitarray) -> bitarray: # little order transform blist = b.split(8) # per byte return bitarray.concat([blist[i].reverse() for i in range(len(blist))])
def _state2bits(self, state: list) -> bitarray: return bitarray.concat( [state[x][y] for y in range(5) for x in range(5)])