def decrypt(self, ciphertext: bytes) -> Bytes: """ Decrypts `ciphertext`. Parameters: ciphertext (bytes): Bytes-like object to be decrypted. Returns: Bytes: Resulting plaintext. """ ciphertext = Bytes.wrap(ciphertext).zfill(self.block_size // 4) A = ciphertext[:self.block_size // 8].int() B = ciphertext[self.block_size // 8:].int() for i in range(self.num_rounds, 0, -1): B = right_rotate((B - self.S[2 * i + 1]) % self.mod, A % self.block_size, bits=self.block_size) ^ A A = right_rotate((A - self.S[2 * i]) % self.mod, B % self.block_size, bits=self.block_size) ^ B A = (A - self.S[0]) % self.mod B = (B - self.S[1]) % self.mod return Bytes( (Bytes(A, 'little').zfill(self.block_size // 8) + Bytes(B, 'little').zfill(self.block_size // 8)).int()).zfill( self.block_size // 4)
def Q_PERMUTE(x, Q): a_0, b_0 = x // 16, x % 16 a_1 = a_0 ^ b_0 b_1 = (a_0 ^ right_rotate(b_0, 1, bits=4) ^ (a_0 * 8)) % 16 a_2, b_2 = Q[0][a_1], Q[1][b_1] a_3 = a_2 ^ b_2 b_3 = (a_2 ^ right_rotate(b_2, 1, bits=4) ^ (a_2 * 8)) % 16 a_4, b_4 = Q[2][a_3], Q[3][b_3] return (b_4 * 16) + a_4
def compression_func(self, block: bytes, state: bytes) -> Bytes: """ SHA-2 compression function. Parameters: block (bytes): Block being digested. state (bytes): Current digest state. Returns: Bytes: Hash output. """ bit_mask = 0xFFFFFFFF if self.state_size == 4 else 0xFFFFFFFFFFFFFFFF bit_size = self.state_size * 8 state = [int.from_bytes(chunk, 'big') for chunk in state.chunk(self.state_size)] w = [int.from_bytes(b, 'big') for b in get_blocks(block, self.state_size)] + ([None] * (self.rounds - 16)) for i in range(16, self.rounds): s0 = right_rotate(w[i-15], self.rot[0], bit_size) ^ right_rotate(w[i-15], self.rot[1], bit_size) ^ (w[i-15] >> self.rot[2]) s1 = right_rotate(w[i-2], self.rot[3], bit_size) ^ right_rotate(w[i-2], self.rot[4], bit_size) ^ (w[i-2] >> self.rot[5]) w[i] = (w[i-16] + s0 + w[i-7] + s1) & bit_mask a = state[0] b = state[1] c = state[2] d = state[3] e = state[4] f = state[5] g = state[6] h = state[7] for i in range(self.rounds): S1 = right_rotate(e, self.rot[6], bit_size) ^ right_rotate(e, self.rot[7], bit_size) ^ right_rotate(e, self.rot[8], bit_size) ch = g ^ (e & (f ^ g)) temp1 = (h + S1 + ch + self.k[i] + w[i]) S0 = right_rotate(a, self.rot[9], bit_size) ^ right_rotate(a, self.rot[10], bit_size) ^ right_rotate(a, self.rot[11], bit_size) maj = (a & b) ^ (a & c) ^ (b & c) temp2 = (S0 + maj) h = g g = f f = e e = (d + temp1) & bit_mask d = c c = b b = a a = (temp1 + temp2) & bit_mask state[0] += a state[1] += b state[2] += c state[3] += d state[4] += e state[5] += f state[6] += g state[7] += h return Bytes(b''.join([int.to_bytes(h_i & bit_mask, self.state_size, 'big') for h_i in state]))
def mix(self, V_a, V_b, V_c, V_d, x, y): V_a = (V_a + V_b + x) & self.MASKBITS V_d = right_rotate(V_d ^ V_a, self.ROTATIONS[0], bits=self.WORD_SIZE) V_c = (V_c + V_d) & self.MASKBITS V_b = right_rotate(V_b ^ V_c, self.ROTATIONS[1], bits=self.WORD_SIZE) V_a = (V_a + V_b + y) & self.MASKBITS V_d = right_rotate(V_d ^ V_a, self.ROTATIONS[2], bits=self.WORD_SIZE) V_c = (V_c + V_d) & self.MASKBITS V_b = right_rotate(V_b ^ V_c, self.ROTATIONS[3], bits=self.WORD_SIZE) return V_a, V_b, V_c, V_d
def decrypt(self, ciphertext: bytes) -> Bytes: """ Decrypts `ciphertext`. Parameters: ciphertext (bytes): Bytes-like object to be decrypted. Returns: Bytes: Resulting plaintext. """ ciphertext = Bytes.wrap(ciphertext) ct_chunks = [ chunk.zfill(4)[::-1].int() for chunk in ciphertext.chunk(4) ] # Dewhitening R = [ct_chunks[i] ^ self.K[i + 4] for i in range(len(ct_chunks))] for i in range(ROUNDS - 1, -1, -1): FR_0, FR_1 = self.F(R[0], R[1], i) R = [ R[0], R[1], left_rotate(R[2], 1) ^ FR_0, right_rotate(R[3] ^ FR_1, 1) ] R[0], R[2] = R[2], R[0] R[1], R[3] = R[3], R[1] R = [R[(i + 2) % 4] ^ self.K[i] for i in range(len(ct_chunks))] return Bytes(b''.join([int.to_bytes(r, 4, 'little') for r in R]), 'little')[::-1]
def encrypt(self, plaintext: bytes) -> Bytes: """ Encrypts `plaintext`. Parameters: plaintext (bytes): Bytes-like object to be encrypted. Returns: Bytes: Resulting ciphertext. """ plaintext = Bytes.wrap(plaintext)[::-1] pt_chunks = [chunk.zfill(4).int() for chunk in plaintext.chunk(4)] # Whitening R = [pt_chunks[i] ^ self.K[i] for i in range(len(pt_chunks))] for i in range(ROUNDS): FR_0, FR_1 = self.F(R[0], R[1], i) R = [ R[0], R[1], right_rotate(R[2] ^ FR_0, 1), left_rotate(R[3], 1) ^ FR_1 ] R[0], R[2] = R[2], R[0] R[1], R[3] = R[3], R[1] R = [R[(i + 2) % 4] ^ self.K[i + 4] for i in range(len(pt_chunks))] return Bytes(b''.join([int.to_bytes(r, 4, 'little') for r in R]))
def rrot(self, amount: int, bits: int=None): """ Performs a right-rotate. Parameters: amount (int): Amount to rotate by. bits (int): Bitspace to rotate over. Returns: Bytes: A new instance of Bytes with the transformation applied. """ if not bits: bits = len(self) * 8 back_to_bytes = int.to_bytes(right_rotate(self.to_int(), amount % bits, bits), bits // 8, self.byteorder) return Bytes(back_to_bytes, self.byteorder)
def V32_64_XSH_RR(x, mult, inc): count = x >> 59 state = (x * mult + inc) & 0xFFFFFFFFFFFFFFFF x ^= x >> 18 return state, right_rotate((x >> 27) & 0xFFFFFFFF, count)