def decrypt(self, nonce: bytes, authed_ciphertext: bytes, data: bytes = b'') -> Bytes: """ Decrypts `ciphertext`. Parameters: nonce (bytes): Bytes-like nonce. authed_ciphertext (bytes): Bytes-like object to be decrypted. data (bytes): Bytes-like additional data to be authenticated. Returns: Bytes: Resulting plaintext. """ from samson.utilities.runtime import RUNTIME authed_ciphertext = Bytes.wrap(authed_ciphertext) ciphertext, orig_tag = authed_ciphertext[:-16], authed_ciphertext[-16:] tag_mask = self.clock_ctr(nonce) data = Bytes.wrap(data) tag = self.auth(ciphertext, data, tag_mask) if not RUNTIME.compare_bytes(tag, orig_tag): raise Exception('Tag mismatch: authentication failed!') return self.ctr.decrypt(ciphertext)
def decrypt(self, ciphertext: bytes, unpad: bool=True) -> Bytes: """ Decrypts `ciphertext`. Parameters: ciphertext (bytes): Bytes-like object to be decrypted. unpad (bool): Unpads the plaintext with PKCS7. Returns: Bytes: Resulting plaintext. """ plaintext = b'' ciphertext = Bytes.wrap(ciphertext) if len(ciphertext) % self.cipher.block_size != 0: raise Exception("Ciphertext is not a multiple of the block size") last_block = self.iv for block in get_blocks(ciphertext, self.cipher.block_size): enc_block = last_block ^ Bytes.wrap(self.cipher.decrypt(block)) plaintext += enc_block last_block = block if unpad: plaintext = self.padder.unpad(plaintext) return plaintext
def derive(self, password: bytes, salt: bytes=None, format_output: bool=True) -> Bytes: """ Derives the bcrypt hash. Parameters: password (bytes): Password. salt (bytes): Salt. format_output (bool): Whether or not to use bcrypt formatting or just output the hash. Returns: Bytes: Derived key/hash. """ if not salt: salt = Bytes.random(16) salt = Bytes.wrap(salt) password = Bytes.wrap(password) bf = self.eks_blowfish_setup(salt, password) ciphertext = self.constant ecb = ECB(bf) for _ in range(64): ciphertext = ecb.encrypt(ciphertext) to_return = ciphertext[:self.output_size] if format_output: to_return = Bytes(f'${self.version}$'.encode('utf-8') + str(self.cost).zfill(2).encode('utf-8') + b'$' + bcrypt_b64_encode(salt) + bcrypt_b64_encode(ciphertext[:self.output_size])) return to_return
def verify(self, plaintext: bytes, signature: bytes) -> bool: """ Verifies the `plaintext` against the `signature`. Parameters: plaintext (bytes): Plaintext to verify. signature (bytes): Signature to verify against plaintext. Returns: bool: Whether or not the plaintext is verified. """ from samson.utilities.runtime import RUNTIME plaintext = Bytes.wrap(plaintext) signature = Bytes.wrap(signature).zfill((self.modulus_len + 7) // 8) mHash = self.hash_obj.hash(plaintext) em_bits = self.modulus_len - 1 em_len = (em_bits + 7) // 8 if em_len < (self.hash_obj.digest_size + self.salt_len + 2): return False if bytes([signature[-1]]) != b'\xbc': return False # Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, # and let H be the next hLen octets. mask_len = em_len - self.hash_obj.digest_size - 1 masked_db = signature[:mask_len] H = signature[mask_len:mask_len + self.hash_obj.digest_size] # If the leftmost 8emLen - emBits bits of the leftmost octet in # maskedDB are not all equal to zero, output "inconsistent" and # stop. left_mask = (2**(len(masked_db) * 8) - 1) >> ((8 * em_len) - em_bits) if masked_db & left_mask != masked_db: return False db_mask = self.mgf(H, mask_len) DB = masked_db ^ db_mask DB &= left_mask # If the emLen - hLen - sLen - 2 leftmost octets of DB are not # zero or if the octet at position emLen - hLen - sLen - 1 (the # leftmost position is "position 1") does not have hexadecimal # value 0x01, output "inconsistent" and stop. if DB[:em_len - self.hash_obj.digest_size - self.salt_len - 1].int() != 1: return False salt = DB[-self.salt_len:] if self.salt_len else b'' m_prime = b'\x00' * 8 + mHash + salt h_prime = self.hash_obj.hash(m_prime) return RUNTIME.compare_bytes(h_prime, H)
def test_vec1(self): key = Bytes.wrap(0x0001020304050607).zfill(8) plaintext = Bytes(0x00010203).zfill(4)[::-1] test_vector = Bytes.wrap(0x23A8D72E).zfill(4) self._run_test(key=key, plaintext=plaintext, test_vector=test_vector, block_size=32, num_rounds=16)
def test_vec2(self): key = Bytes.wrap(0x000102030405060708090A0B0C0D0E0F, 'big').zfill(16) plaintext = int.to_bytes(0x0001020304050607, 8, 'little') test_vector = Bytes.wrap(0x2A0EDC0E9431FF73).zfill(8) self._run_test(key=key, plaintext=plaintext, test_vector=test_vector, block_size=64, num_rounds=20)
def __init__(self, F: FunctionType, K1: bytes, K2: bytes = None): """ Parameters: F (func): Unkeyed pseudorandom permutation. K1 (bytes): Bytes-like object to key the cipher. K2 (bytes): (Optional) Bytes-like object to key the cipher. """ self.F = F self.K1 = Bytes.wrap(K1) self.K2 = Bytes.wrap(K2 or K1) self.block_size = len(self.K1)
def test_vec3(self): key = Bytes.wrap(0x000102030405060708090A0B0C0D0E0F1011121314151617, 'big').zfill(24) plaintext = int.to_bytes(0x000102030405060708090A0B0C0D0E0F, 16, 'little') test_vector = Bytes.wrap(0xA46772820EDBCE0235ABEA32AE7178DA).zfill(16) self._run_test(key=key, plaintext=plaintext, test_vector=test_vector, block_size=128, num_rounds=24)
def execute(self, ciphertexts: list, iterations: int=3) -> list: """ Executes the attack. Parameters: ciphertexts (list): List of bytes-like ciphertexts using the same keystream. iterations (int): Number of iterations of the full-text analysis phase. Accuracy-time trade-off. Returns: list: List of recovered plaintexts. """ min_size = min([len(ciphertext) for ciphertext in ciphertexts]) same_size_ciphers = [ciphertext[:min_size] for ciphertext in ciphertexts] transposed_ciphers = [bytearray(transposed) for transposed in zip(*same_size_ciphers)] assert [bytearray(transposed) for transposed in zip(*transposed_ciphers)] == same_size_ciphers log.debug("Starting initial transposition analysis") # Transposition analysis first (transposition) transposed_plaintexts = [] for cipher in RUNTIME.report_progress(transposed_ciphers, desc='Transposition analysis', unit='ciphers'): all_chars = {} for char in range(256): plaintext = Bytes(struct.pack('B', char)).stretch(len(cipher)) ^ cipher all_chars[char] = (self.analyzer.analyze(plaintext), plaintext) transposed_plaintexts.append(sorted(all_chars.items(), key=lambda kv: kv[1][0], reverse=True)[0][1][1]) retransposed_plaintexts = [bytearray(transposed) for transposed in zip(*transposed_plaintexts)] log.debug("Starting full-text analysis on retransposed text") # Clean up with a character-by-character, higher-context analysis (retransposed) for j in RUNTIME.report_progress(range(iterations), desc='Higher-context analysis'): log.debug("Starting iteration {}/{}".format(j + 1, iterations)) differential_mask = bytearray() for i in RUNTIME.report_progress(range(min_size), desc='Building differential mask', unit='bytes'): all_chars = {} for char in range(256): full_text_analyses = [] for curr_cipher in retransposed_plaintexts: cipher_copy = bytearray([_ for _ in curr_cipher]) cipher_copy[i] = ord(Bytes(struct.pack('B', char)) ^ struct.pack('B', curr_cipher[i])) full_text_analyses.append(self.analyzer.analyze(cipher_copy)) all_chars[char] = (sum(full_text_analyses), char) best_char = sorted(all_chars.items(), key=lambda kv: kv[1][0], reverse=True)[0][1][1] differential_mask += struct.pack('B', best_char) retransposed_plaintexts = [Bytes.wrap(cipher) ^ differential_mask for cipher in retransposed_plaintexts] return retransposed_plaintexts
def __init__(self, curve: TwistedEdwardsCurve = EdwardsCurve25519, hash_obj: object = SHA512(), d: int = None, A: TwistedEdwardsPoint = None, a: int = None, h: bytes = None, clamp: bool = True): """ Parameters: curve (TwistedEdwardsCurve): Curve used for calculations. hash_obj (object): Instantiated object with compatible hash interface. d (int): Private key. A (TwistedEdwardsPoint): (Optional) Public point. a (int): (Optional) Public scalar. h (bytes): (Optional) Hashed private key. clamp (bool): Whether or not to clamp the public scalar. """ Primitive.__init__(self) self.B = curve.B self.curve = curve self.d = Bytes.wrap(d or max(1, Bytes.random(hash_obj.digest_size).int())) self.H = hash_obj self.h = h or hash_obj.hash(self.d) a = a or self.h[:self.curve.b // 8].int() self.a = curve.clamp_to_curve(a, True) if clamp else a self.A = A or self.B * self.a
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) block_size = self.underlying_mode.cipher.block_size pt_len = len(plaintext) assert pt_len > block_size pt_chunks = plaintext.chunk(block_size, allow_partials=True) padding_len = (block_size - (pt_len % block_size)) % block_size ciphertext_chunks = self.underlying_mode.encrypt( sum(pt_chunks[:-1]), pad=False).chunk(block_size) padding = ciphertext_chunks[-1][-padding_len:][:padding_len] last_block = self.underlying_mode.encrypt(pt_chunks[-1] + padding, pad=False) return (sum(ciphertext_chunks[:-1]) + last_block + ciphertext_chunks[-1])[:pt_len]
def generate(self, message: bytes) -> Bytes: """ Generates a keyed MAC for `message`. Parameters: message (bytes): Message to generate a MAC for. Returns: Bytes: The MAC. """ message = Bytes.wrap(message) incomplete_block = len(message) % self.cipher.block_size message_chunks = message.chunk(self.cipher.block_size, allow_partials=True) if len(message_chunks) == 0: message_chunks = [Bytes(b'')] M_last = message_chunks[-1] if incomplete_block or not len(message): M_last += b'\x80' M_last = (M_last + (b'\x00' * (self.cipher.block_size - len(M_last)))) ^ self.k2 else: M_last ^= self.k1 return self.cbc_mac.generate(b''.join(message_chunks[:-1]) + M_last, pad=False)
def unpack(encoded_bytes: bytes, decryptor: FunctionType=None, already_unpacked: bool=False) -> (object, bytes): """ Unpacks bytes into an DSAPrivateKey object. Parameters: encoded_bytes (bytes): Bytes to be (partially?) decoded. already_unpacked (bool): Whether or not to do the initial length-decoding. Returns: (DSAPrivateKey, bytes): The decoded object and unused bytes. """ encoded_bytes = Bytes.wrap(encoded_bytes) if already_unpacked: params, encoded_bytes = encoded_bytes, None else: params, encoded_bytes = PackedBytes('private_key').unpack(encoded_bytes) check_bytes, params = check_decrypt(params, decryptor) _header, params = PackedBytes('dsa-header').unpack(params) p, params = PackedBytes('p').unpack(params) q, params = PackedBytes('q').unpack(params) g, params = PackedBytes('g').unpack(params) y, params = PackedBytes('y').unpack(params) x, params = PackedBytes('x').unpack(params) host, params = PackedBytes('host').unpack(params) return DSAPrivateKey('private_key', check_bytes=check_bytes, p=p.int(), q=q.int(), g=g.int(), y=y.int(), x=x.int(), host=host), encoded_bytes
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 encrypt(self, plaintext: bytes) -> Bytes: """ Encrypts `plaintext`. Parameters: plaintext (bytes): Bytes-like object to be encrypted. Returns: Bytes: Resulting ciphertext. """ plaintext = Bytes.wrap(plaintext) M = plaintext.int() D1 = M >> 64 D2 = M & MASK64 D1 = D1 ^ self.kw[0] D2 = D2 ^ self.kw[1] num_super_rounds = 3 if len(self.key) == 16 else 4 for i in range(num_super_rounds): if i > 0: D1 = FL (D1, self.ke[(i-1) * 2]) D2 = FLINV(D2, self.ke[(i-1) * 2 + 1]) for j in range(0, 6, 2): D2 ^= self.F(D1, self.k[i*6 + j]) D1 ^= self.F(D2, self.k[i*6 + j +1]) D2 = D2 ^ self.kw[2] D1 = D1 ^ self.kw[3] return Bytes(((D2 & MASK64) << 64) | (D1 & MASK64)).zfill(16)
def internal_pmac(self, data): data = Bytes.wrap(data) data_chunks = data.chunk(self.cipher.block_size, allow_partials=True) offset = self.cipher.encrypt(Bytes(b'').zfill(self.cipher.block_size)) offset = triple(offset) offset = triple(offset) checksum = Bytes(b'').zfill(self.cipher.block_size) for i in range(len(data_chunks) - 1): offset = dbl(offset) checksum ^= self.cipher.encrypt(offset ^ data_chunks[i]) offset = dbl(offset) M_last = data_chunks[-1] if len(M_last) % self.cipher.block_size == 0: offset = triple(offset) checksum ^= M_last else: M_last += b'\x80' M_last = (M_last + (b'\x00' * (self.cipher.block_size - len(M_last)))) checksum ^= M_last offset = triple(offset) offset = triple(offset) return self.cipher.encrypt(offset ^ checksum)
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 encrypt(self, plaintext: bytes, pad: bool=True) -> Bytes: """ Encrypts `plaintext`. Parameters: plaintext (bytes): Bytes-like object to be encrypted. pad (bool): Pads the plaintext with PKCS7. Returns: Bytes: Resulting ciphertext. """ plaintext = Bytes.wrap(plaintext) if pad: plaintext = self.padder.pad(plaintext) if len(plaintext) % self.cipher.block_size != 0: raise Exception("Plaintext is not a multiple of the block size") ciphertext = Bytes(b'') last_block = self.iv for block in get_blocks(plaintext, self.cipher.block_size): enc_block = self.cipher.encrypt(bytes(last_block ^ block)) ciphertext += enc_block last_block = enc_block return ciphertext
def execute(self, auth_data_a: bytes, ciphertext_a: bytes, tag_a: bytes, auth_data_b: bytes, ciphertext_b: bytes, tag_b: bytes) -> Bytes: """ Executes the attack. Parameters: ciphertext (bytes): Bytes-like ciphertext generated by the system. Returns: Bytes: The key to the cipher. """ auth_data_a, ciphertext_a, tag_a, auth_data_b, ciphertext_b, tag_b = [ Bytes.wrap(item) for item in [ auth_data_a, ciphertext_a, tag_a, auth_data_b, ciphertext_b, tag_b ] ] poly_a = gcm_to_poly(auth_data_a, ciphertext_a, tag_a) poly_b = gcm_to_poly(auth_data_b, ciphertext_b, tag_b) # 3 is the smallest factor of (2**128) - 1 factors = (poly_a + poly_b).factor(subgroup_divisor=3) return [ elem_to_int(candidate.coeffs[0]) for candidate in factors if candidate.degree() == 1 ]
def unpack(encoded_bytes: bytes, already_unpacked: bool = False) -> (object, bytes): """ Unpacks bytes into an ECDSAPublicKey object. Parameters: encoded_bytes (bytes): Bytes to be (partially?) decoded. already_unpacked (bool): Whether or not to do the initial length-decoding. Returns: (ECDSAPublicKey, bytes): The decoded object and unused bytes. """ encoded_bytes = Bytes.wrap(encoded_bytes) if already_unpacked: params, encoded_bytes = encoded_bytes, None else: params, encoded_bytes = PackedBytes('public_key').unpack( encoded_bytes) _header, params = PackedBytes('ecdsa-header').unpack(params) curve, params = PackedBytes('curve').unpack(params) x_y_bytes, params = PackedBytes('x_y_bytes').unpack(params) return ECDSAPublicKey('public_key', curve=curve, x_y_bytes=x_y_bytes), encoded_bytes
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) half = len(ciphertext) // 2 L_i, R_i = ciphertext[:half].to_int(), ciphertext[half:].to_int() L_i ^= self.P[17] R_i ^= self.P[16] R_i, L_i = L_i, R_i for i in range(15, -1, -1): R_i, L_i = L_i, R_i R_i ^= round_func( self.S[0][(L_i >> 24) & 0xFF], self.S[1][(L_i >> 16) & 0xFF], self.S[2][(L_i >> 8) & 0xFF], self.S[3][L_i & 0xFF] ) & 0xFFFFFFFF L_i ^= self.P[i] L_i &= 0xFFFFFFFF return Bytes(L_i).zfill(4) + Bytes(R_i).zfill(4)
def unpad(self, plaintext: bytes, allow_mangers: bool=False, skip_label_check: bool=False) -> Bytes: """ Unpads the `plaintext`. Parameters: plaintext (bytes): Plaintext to pad. allow_mangers (bool): Whether or not to explicitly help Manger's attack. skip_label_check (bool): Whether or not to skip checking the label. Returns: Bytes: Unpadded plaintext. """ k = (self.modulus_len + 7) // 8 h_len = self.hash_obj.digest_size plaintext = Bytes.wrap(plaintext).zfill(k) if allow_mangers: if plaintext[0] != 0: raise ValueError("First byte is not zero! ;)") masked_seed, masked_db = plaintext[1:(h_len + 1)], plaintext[(h_len + 1):] seed_mask = self.mgf(masked_db, h_len) seed = masked_seed ^ seed_mask db_mask = self.mgf(seed, k - h_len - 1) db = masked_db ^ db_mask l_hash, m = db[:h_len], db[h_len + db[h_len:].index(b'\x01') + 1:] if not skip_label_check and l_hash != self.hash_obj.hash(self.label): raise ValueError("Label hashes do not match") return m
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).zfill(self.block_size // 4) A = plaintext[self.block_size // 8:].int() B = plaintext[:self.block_size // 8].int() A = (A + self.S[0]) % self.mod B = (B + self.S[1]) % self.mod for i in range(1, self.num_rounds + 1): A = (left_rotate(A ^ B, B % self.block_size, bits=self.block_size) + self.S[2 * i]) % self.mod B = (left_rotate(B ^ A, A % self.block_size, bits=self.block_size) + self.S[2 * i + 1]) % self.mod return (Bytes(A, 'little').zfill(self.block_size // 8) + Bytes(B, 'little').zfill(self.block_size // 8))
def encrypt(self, plaintext: bytes, pad: bool=False) -> Bytes: """ Encrypts `plaintext`. Parameters: plaintext (bytes): Bytes-like object to be encrypted. pad (bool): Whether or not to use RFC5649 padding. Returns: Bytes: Resulting ciphertext. """ iv = self.iv length = len(plaintext) plaintext = Bytes.wrap(plaintext) if pad: r = ((length) + 7) // 8 plaintext = plaintext + ((r * 8) - length) * b'\x00' iv = self.iv + Bytes(length).zfill(4) A = iv R = plaintext.chunk(8) n = len(R) # RFC5649 specific if n == 1: return self.cipher.encrypt(iv + plaintext) for j in range(6): for i in range(n): ct = self.cipher.encrypt(A + R[i]) A, R[i] = ct[:8], ct[8:] A ^= Bytes(n * j + i + 1).zfill(len(A)) return A + b''.join(R)
def __init__(self, h: int = 2, p: int = DiffieHellman.MODP_1536, key: bytes = None, exp1: int = None, exp2: int = None, validate: bool = True): """ Parameters: h (int): Generator. p (int): Prime modulus. key (bytes): Secret. exp1 (int): First random exponent. exp2 (int): Second random exponent. validate (bool): Whether or not to validate challenges to prevent exploits. """ self.h = h self.p = p self.key = Bytes.wrap(key).int() or Bytes.random(16).int() self.validate = validate # We do this explicitly with None so users can easily set these values to zero :) if exp1 is None: exp1 = Bytes.random(16).int() if exp2 is None: exp2 = Bytes.random(16).int() self.exp1 = exp1 self.exp2 = exp2 self.P_b = None self.P = None self.Q = None
def decrypt(self, ciphertext: bytes) -> Bytes: """ Decrypts `ciphertext`. Parameters: ciphertext (bytes): Bytes-like object to be decrypted. Returns: Bytes: Resulting plaintext. """ plaintext = FeistelNetwork.decrypt(self, self.key, Bytes.wrap(ciphertext)) half = len(plaintext) // 2 plaintext = Bytes.wrap(plaintext) L_i, R_i = plaintext[:half], plaintext[half:] return R_i + L_i
def unpack(encoded_bytes: bytes, decryptor: FunctionType = None, already_unpacked: bool = False) -> (object, bytes): """ Unpacks bytes into an ECDSAPrivateKey object. Parameters: encoded_bytes (bytes): Bytes to be (partially?) decoded. already_unpacked (bool): Whether or not to do the initial length-decoding. Returns: (ECDSAPrivateKey, bytes): The decoded object and unused bytes. """ encoded_bytes = Bytes.wrap(encoded_bytes) if already_unpacked: params, encoded_bytes = encoded_bytes, None else: params, encoded_bytes = PackedBytes('private_key').unpack( encoded_bytes) check_bytes, params = check_decrypt(params, decryptor) _header, params = PackedBytes('ecdsa-header').unpack(params) curve, params = PackedBytes('curve').unpack(params) x_y_bytes, params = PackedBytes('x_y_bytes').unpack(params) d, params = PackedBytes('d').unpack(params) host, params = PackedBytes('host').unpack(params) return ECDSAPrivateKey('private_key', check_bytes=check_bytes, curve=curve, x_y_bytes=x_y_bytes, d=d.int(), host=host), encoded_bytes
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 unpack(encoded_bytes: bytes, already_unpacked: bool = False) -> (object, bytes): """ Unpacks bytes into an DSAPublicKey object. Parameters: encoded_bytes (bytes): Bytes to be (partially?) decoded. already_unpacked (bool): Whether or not to do the initial length-decoding. Returns: (DSAPublicKey, bytes): The decoded object and unused bytes. """ encoded_bytes = Bytes.wrap(encoded_bytes) if already_unpacked: params, encoded_bytes = encoded_bytes, None else: params, encoded_bytes = PackedBytes('public_key').unpack( encoded_bytes) _header, params = PackedBytes('dsa-header').unpack(params) p, params = PackedBytes('p').unpack(params) q, params = PackedBytes('q').unpack(params) g, params = PackedBytes('g').unpack(params) y, params = PackedBytes('y').unpack(params) if already_unpacked: encoded_bytes = params return DSAPublicKey('public_key', p=p.int(), q=q.int(), g=g.int(), y=y.int()), encoded_bytes
def __init__(self, key: bytes): """ Parameters: key (bytes): Bytes-like object to key the cipher. """ Primitive.__init__(self) self.key = Bytes.wrap(key) self.key_schedule = key_schedule self.round_func = round_func