Exemple #1
0
    def test_gauntlet(self):
        for i in range(3):
            pkcs = PKCS1v15Padding(1024, block_type=i)

            for _ in range(10000):
                plaintext = Bytes.random(8)

                unpadded = pkcs.unpad(pkcs.pad(plaintext))

                if i == 0:
                    unpadded = unpadded.zfill(len(plaintext))

                self.assertEqual(unpadded, plaintext)
Exemple #2
0
    def decode_point(x_y_bytes: bytes):
        x_y_bytes = Bytes.wrap(x_y_bytes)

        # Uncompressed Point
        if x_y_bytes[0] == 4:
            x_y_bytes = x_y_bytes[1:]
        else:
            raise NotImplementedError(
                "Support for ECPoint decompression not implemented.")

        x, y = x_y_bytes[:len(x_y_bytes) //
                         2].int(), x_y_bytes[len(x_y_bytes) // 2:].int()
        return x, y
Exemple #3
0
 def __init__(self, key: bytes, nonce: bytes, r: bytes, cipher=Rijndael):
     """
     Parameters:
         key    (bytes): Bytes-like object to key the underlying cipher.
         nonce  (bytes): Bytes-like nonce.
         r      (bytes): Bytes-like polynomial.
         cipher (class): Instantiable class representing a block cipher.
     """
     Primitive.__init__(self)
     self.key    = key
     self.nonce  = nonce
     self.r      = Bytes.wrap(r, byteorder='little').to_int()
     self.cipher = cipher
Exemple #4
0
    def decrypt(self, key_and_ciphertext: (int, int)) -> Bytes:
        """
        Decrypts `key_and_ciphertext`.

        Parameters:
            key_and_ciphertext ((int, int)): Ephemeral key and ciphertext.
        
        Returns:
            Bytes: Plaintext.
        """
        c_1, ciphertext = key_and_ciphertext
        s = pow(c_1, self.key, self.p)
        return Bytes((mod_inv(s, self.p) * ciphertext) % self.p)
Exemple #5
0
    def encrypt(self, plaintext: bytes) -> Bytes:
        """
        Encrypts `plaintext`.

        Parameters:
            plaintext (bytes): Bytes-like object to be encrypted.
        
        Returns:
            Bytes: Resulting ciphertext.
        """
        keystream = Bytes(b'')
        plaintext = Bytes.wrap(plaintext)

        num_blocks = ceil(len(plaintext) / self.cipher.block_size)
        for _ in range(num_blocks):
            keystream += self.cipher.encrypt(
                self.nonce +
                self.counter.to_bytes(self.cipher.block_size -
                                      len(self.nonce), self.byteorder))
            self.counter += 1

        return keystream[:len(plaintext)] ^ plaintext
Exemple #6
0
    def pack(self, value: bytes, force_pack: bool = False) -> Bytes:
        """
        Packs bytes-coercible objects into length-encoded bytes.

        Parameters:
            value     (bytes): Value to encode.
            force_pack (bool): Whether or not to pack zero-length values.
        
        Returns:
            bytes: Packed bytes.
        """
        val = Bytes.wrap(value, byteorder=self.endianness)

        if issubclass(type(value), int):
            val = val.zfill(math.ceil((value.bit_length() + 1) / 8))

        if len(val) > 0 or force_pack:
            length = Bytes(len(val)).zfill(4)
        else:
            length = b''

        return length + val
Exemple #7
0
def compression_func(chunk, state):
    """Process a chunk of data and return the new digest variables."""
    assert len(chunk) == 64

    w = [0] * 80

    # Break chunk into sixteen 4-byte big-endian words w[i]
    for i in range(16):
        w[i] = struct.unpack(b'>I', chunk[i * 4:i * 4 + 4])[0]

    # Extend the sixteen 4-byte words into eighty 4-byte words
    for i in range(16, 80):
        w[i] = left_rotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1)

    # Initialize hash value for this chunk
    h0, h1, h2, h3, h4 = bytes_to_state(state)

    a = h0
    b = h1
    c = h2
    d = h3
    e = h4

    for i in range(80):
        if 0 <= i <= 19:
            # Use alternative 1 for f from FIPS PB 180-1 to avoid bitwise not
            f = d ^ (b & (c ^ d))
            k = 0x5A827999
        elif 20 <= i <= 39:
            f = b ^ c ^ d
            k = 0x6ED9EBA1
        elif 40 <= i <= 59:
            f = (b & c) | (b & d) | (c & d)
            k = 0x8F1BBCDC
        elif 60 <= i <= 79:
            f = b ^ c ^ d
            k = 0xCA62C1D6

        a, b, c, d, e = ((left_rotate(a, 5) + f + e + k + w[i]) & 0xffffffff,
                         a, left_rotate(b, 30), c, d)

    # Add this chunk's hash to result so far
    h0 = (h0 + a) & 0xffffffff
    h1 = (h1 + b) & 0xffffffff
    h2 = (h2 + c) & 0xffffffff
    h3 = (h3 + d) & 0xffffffff
    h4 = (h4 + e) & 0xffffffff

    state = [h0, h1, h2, h3, h4]

    return Bytes(state_to_bytes(state))
Exemple #8
0
    def hash(self, message: bytes) -> Bytes:
        """
        Hashes the `message`.

        Parameters:
            message (bytes): Message to be hashed.
        
        Returns:
            Bytes: The hash digest.
        """
        message = Bytes(message, 'little')
        state = deepcopy(self.IV)

        last_block_size = len(message) % self.IMPL_BLOCK_SIZE

        if last_block_size == 0 and len(message) > 0:
            last_block_size = self.IMPL_BLOCK_SIZE

        state[0] ^= (0x0101 << 16) + (len(self.key) << 8) + (self.digest_size)

        if len(self.key) > 0:
            message = self.padding_func(self.key) + message

        padded_msg = self.padding_func(message)
        bytes_compressed = 0

        msg_chunks = padded_msg.chunk(self.IMPL_BLOCK_SIZE)

        for i, chunk in enumerate(msg_chunks):
            is_last_block = i == (len(msg_chunks) - 1)
            bytes_compressed += last_block_size if is_last_block else self.IMPL_BLOCK_SIZE
            state = self.compress(state, self.IV, chunk, bytes_compressed,
                                  is_last_block)

        return sum([
            Bytes(h, byteorder='little').zfill(self.WORD_SIZE // 8)
            for h in state
        ])[:self.digest_size]
Exemple #9
0
    def pad(self, plaintext: bytes, seed: bytes=None) -> Bytes:
        """
        Pads the `plaintext`.

        Parameters:
            plaintext (bytes): Plaintext to pad.
            seed      (bytes): (Optional) Random seed for the MGF.
        
        Returns:
            Bytes: Padded plaintext.
        """
        plaintext = Bytes.wrap(plaintext)
        k = (self.modulus_len + 7) // 8

        # Step 1: Length checking
        h_len = self.hash_obj.digest_size
        m_len = len(plaintext)
        ps_len = k - m_len - (2 * h_len) - 2

        if ps_len < 0:
            raise ValueError("Plaintext is too long")


        # Step 2: EME-OAEP encoding
        l_hash = self.hash_obj.hash(self.label)

        ps = Bytes(b'').zfill(ps_len)
        db = l_hash + ps + b'\x01' + plaintext

        seed = seed or Bytes.random(h_len)

        db_mask = self.mgf(seed, k - h_len - 1)
        masked_db = db ^ db_mask

        seed_mask = self.mgf(masked_db, h_len)
        masked_seed = seed ^ seed_mask

        return b'\x00' + masked_seed + masked_db
Exemple #10
0
    def test_all_vecs(self):
        for key, nonce, data, size, plaintext, expected_ciphertext in TEST_VECTORS:
            key = Bytes(key)
            nonce = Bytes(nonce)
            data = Bytes(data)
            data = data.zfill(len(data) + 1)
            plaintext = Bytes(plaintext)

            ccm = CCM(Rijndael(key), size)
            ciphertext = ccm.encrypt(nonce, plaintext, data)
            self.assertEqual(ciphertext, Bytes(expected_ciphertext))
            self.assertEqual(ccm.decrypt(nonce, ciphertext, data), plaintext)
Exemple #11
0
    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)
        C = ciphertext.int()

        kw = [self.kw[2], self.kw[3], self.kw[0], self.kw[1]]
        ke = self.ke[::-1]
        k = self.k[::-1]

        D1 = C >> 64
        D2 = C & MASK64

        D1 = D1 ^ kw[0]
        D2 = D2 ^ 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, ke[(i-1) * 2])
                D2 = FLINV(D2, ke[(i-1) * 2 + 1])
            for j in range(0, 6, 2):
                D2 ^= self.F(D1, k[i*6 + j])
                D1 ^= self.F(D2, k[i*6 + j +1])


        D2 = D2 ^ kw[2]
        D1 = D1 ^ kw[3]

        return Bytes(((D2  & MASK64) << 64) | (D1 & MASK64)).zfill(16)
Exemple #12
0
    def _generate_mac(self, nonce: bytes, plaintext: bytes, data: bytes) -> bytes:
        data_len, _q, _flags, b_0 = self._calculate_formatting_params(nonce, plaintext, data)

        data_len_encoded = b''
        if data_len > 0:
            if data_len < ((2 ** 16) - (2 ** 8)):
                size = 2

            elif data_len < (2 ** 32):
                data_len_encoded = b'\xFF\xFE'
                size = 4

            else:
                data_len_encoded = b'\xFF\xFF'
                size = 8

            data_len_encoded += int.to_bytes(data_len, size, 'big')

        padded_data = Bytes.wrap(data_len_encoded + data).pad_congruent_right(16)
        padded_plaintext = Bytes.wrap(plaintext).pad_congruent_right(16)

        T = self.cmac.generate(b_0 + padded_data + padded_plaintext, pad=False)
        return T
Exemple #13
0
 def __init__(self, cost: int, constant: bytes=CONSTANT, output_size: int=23, version: str='2a', use_specs_eks: bool=False):
     """
     Parameters:
         cost           (int): Cost factor.
         constant     (bytes): (Optional) The constant or magic to use for bcrypt.
         output_size    (int): (Optional) Size to limit output to.
         version        (str): Version of bcrypt to use. Only supports '2a' for now (pads with a NUL byte if '2a').
         use_specs_eks (bool): Use the original specification's order for processing salt and password.
     """
     self.cost = cost
     self.constant = Bytes.wrap(constant)
     self.output_size = output_size
     self.version = version
     self.use_specs_eks = use_specs_eks
 def __init__(self, oracle: PaddingOracle, iv: bytes, block_size: int=16, alphabet=[byte for byte in range(256)], batch_requests: bool=False):
     """
     Parameters:
         oracle (PaddingOracle): An oracle that takes in a bytes-like object and returns a boolean
                                 indicating whether the padding was correct.
         iv             (bytes): Initialization vector (or previous ciphertext block) of the ciphertext
                                 to crack.
         block_size       (int): Block size of the block cipher being used.
     """
     self.oracle     = oracle
     self.iv         = Bytes.wrap(iv)
     self.block_size = block_size
     self.alphabet   = alphabet
     self.batch_requests = batch_requests
    def decode(buffer: bytes, **kwargs):
        from samson.protocols.diffie_hellman import DiffieHellman
        items = bytes_to_der_sequence(buffer)

        y_sequence_bytes = Bytes(int(items[1]))
        y = int(decoder.decode(y_sequence_bytes)[0])
        p, g = [int(item) for item in items[0][1]]

        dh = DiffieHellman(p=p, g=g)

        # Err, where do we put this?
        dh.y = y

        return dh
 def encode(ecdsa_key: object, **kwargs):
     zero_fill = math.ceil(ecdsa_key.G.curve.q.bit_length() / 8)
     encoded = export_der([
         1,
         Bytes(ecdsa_key.d).zfill(zero_fill),
         ber_decoder.decode(b'\x06' + bytes([len(ecdsa_key.G.curve.oid)]) +
                            ecdsa_key.G.curve.oid)[0].asTuple(),
         ecdsa_key.format_public_point()
     ],
                          item_types=[
                              Integer, OctetString, NamedCurve, PublicPoint
                          ])
     encoded = PKCS1ECDSAPrivateKey.transport_encode(encoded, **kwargs)
     return encoded
Exemple #17
0
    def test_crack(self):
        for _ in range(10):
            seed = Bytes.random(16).int()

            ref_lcg = LCG(X=seed, a=1103515245, c=12345, m=2**31)
            outputs = [ref_lcg.generate() for _ in range(15)]

            cracked_lcg = LCG.crack(outputs)

            self.assertTrue(
                all([
                    ref_lcg.generate() == cracked_lcg.generate()
                    for _ in range(10000)
                ]))
Exemple #18
0
    def decrypt(self, authenticator: bytes,
                encrypted_password: bytes) -> Bytes:
        """
        Decrypts the `encrypted_password`.

        Parameters:
            authenticator      (bytes): Client authenticator.
            encrypted_password (bytes): RADIUS-encrypted password.
        
        Returns:
            Bytes: Plaintext password.
        """
        return Bytes(
            self.encrypt(authenticator, encrypted_password).rstrip(b'\x00'))
Exemple #19
0
    def break_vigenere(ciphertext: str,
                       alphabet: bytes = bytes(string.ascii_lowercase,
                                               'utf-8'),
                       expected_distribution=letter_distribution,
                       min_key_length: int = 1,
                       max_key_length: int = 20):
        ciphertext = Bytes.wrap(ciphertext)
        cipher_scores = []
        cipher_len = len(ciphertext)

        analyzer = EnglishAnalyzer()

        for i in range(min_key_length, max_key_length):
            transposed = ciphertext.transpose(i)
            total_key_score = 1
            top_chunk_scores = []

            for chunk in transposed.chunk(cipher_len // i):
                curr_chunk_scores = []

                for char in alphabet:
                    tmp_vig = Vigenere(bytes([char]))
                    new_chunk = tmp_vig.decrypt(chunk)

                    chunk_score = chisquare(count_items(new_chunk),
                                            expected_distribution)
                    curr_chunk_scores.append((char, chunk_score))

                top_chunk_scores.append(
                    sorted(curr_chunk_scores,
                           key=lambda chunk_score: chunk_score[1],
                           reverse=False)[0])

            for chunk_score in top_chunk_scores:
                total_key_score += chunk_score[1]

            cipher_scores.append((total_key_score, top_chunk_scores))

        analyzer_scores = []
        for _total_score, top_chunk_scores in cipher_scores:
            vig = Vigenere(bytes([char for char, score in top_chunk_scores]),
                           alphabet=alphabet)
            analyzer_scores.append(
                (analyzer.analyze(vig.decrypt(ciphertext)) / len(vig.key),
                 vig))

        top_analyzed_score = sorted(analyzer_scores,
                                    key=lambda kv: kv[0],
                                    reverse=True)[0]
        return top_analyzed_score[1]
Exemple #20
0
    def __init__(self, key: bytes):
        """
        Parameters:
            key (bytes): Bytes-like object to key the cipher.
        """
        Primitive.__init__(self)

        key = Bytes.wrap(key)
        if not len(key) in [8, 16, 24]:
            raise ValueError('`key` size must be in [8, 16, 24]')

        self.key = key
        self.des_arr = [DES(subkey.zfill(8)) for subkey in key.chunk(8)]
        self.block_size = 8
Exemple #21
0
    def encrypt(self, authenticator: bytes, password: bytes) -> Bytes:
        """
        Encrypts the `password`.

        Parameters:
            authenticator (bytes): Client authenticator.
            password      (bytes): Password.
        
        Returns:
            Bytes: RADIUS-encrypted password.
        """
        if len(password) > 128:
            raise ValueError('Password exceeds maximum of 128 bytes')

        password = Bytes.wrap(password).pad_congruent_right(16)
        md5 = MD5()

        result, last = Bytes(), authenticator
        for chunk in password.chunk(16):
            result += md5.hash(self.key + last) ^ chunk
            last = result[-16:]

        return result
Exemple #22
0
    def decode(len_bytes: bytes) -> object:
        encoding_len = len(len_bytes)

        if encoding_len == 1:
            length = Bytes.wrap(len_bytes).int()

        elif encoding_len == 2:
            length = ((len_bytes[0] - 192) << 8) + len_bytes[1] + 192

        else:
            length = (len_bytes[1] << 24) + (len_bytes[2] << 16) + (
                len_bytes[3] << 8) + len_bytes[4]

        return PGPLength(length)
Exemple #23
0
    def encode(ec_key: object, **kwargs) -> str:
        """
        Encodes the key as a JWK JSON string.

        Parameters:
            ec_key (ECDSA): ECDSA key to encode.
        
        Returns:
            str: JWK JSON string.
        """
        jwk = JWKECPublicKey.build_pub(ec_key)
        jwk['d'] = url_b64_encode(Bytes(ec_key.d)).decode()

        return json.dumps(jwk).encode('utf-8')
Exemple #24
0
    def downconvert(self,
                    attack_model: AttackModel,
                    generator: FunctionType = lambda: Bytes.random(8)):
        if attack_model == self.ATTACK_MODEL:
            return self

        elif self.ATTACK_MODEL.implies(attack_model):
            return ChosenCiphertextOracle(self.request).downconvert(
                attack_model, generator)

        else:
            raise ValueError(
                f"{self.ATTACK_MODEL} cannot be downconverted to {attack_model}"
            )
Exemple #25
0
    def generate_fixed_point(block_cipher: object, message: bytes,
                             block_size: int):
        """
        Generates a Davies-Meyer fixed point. A fixed point is a state in which its output matches
        its input, and, therefore, infinitely produces itself.

        Parameters:
            block_cipher (type): Block cipher type.
            message     (bytes): Message you want to be fixed point.
            block_size    (int): Block size of `block_cipher`.

        Returns:
            DaviesMeyerConstruction: A DaviesMeyerConstruction with the initial state set to the fixed point.
        """
        message = Bytes.wrap(message)
        first_block = message.chunk(block_size)[0]

        initial_state = block_cipher(first_block).decrypt(
            Bytes(b'').zfill(block_size))

        return DaviesMeyerConstruction(
            initial_state=initial_state,
            encryptor=lambda key, msg: block_cipher(key).encrypt(msg))
Exemple #26
0
    def test_k_derivation(self):
        ecdsa = ECDSA(P256.G)
        k = Bytes.random(32).int()
        msgA = b'my first message'
        msgB = b'uh oh, two messages?!'

        sigA = ecdsa.sign(msgA, k)
        sigB = ecdsa.sign(msgB, k)

        found_k = ecdsa.derive_k_from_sigs(msgA, sigA, msgB, sigB)
        self.assertEqual(found_k, k)

        d = ecdsa.d
        self.assertEqual(ecdsa.derive_x_from_k(msgA, found_k, sigA), d)
Exemple #27
0
    def parse(token: bytes) -> object:
        """
        Parses a compact bytestring `token` into a JWS object.

        Parameters:
            token (bytes): The JWS token to parse.
        
        Returns:
            JWS: JWS representation.
        """
        header, body, signature = [
            url_b64_decode(part) for part in token.split(b'.')
        ]
        return JWS(header, body, Bytes.wrap(signature))
Exemple #28
0
 def __init__(self,
              identity: bytes,
              password: bytes,
              g: int = 2,
              N: int = MODP_1024,
              hash_obj: object = SHA256(),
              a: int = None):
     """
     Parameters:
         identity  (bytes): Username.
         password  (bytes): Password.
         g           (int): Generator.
         N           (int): Prime modulus.
         hash_obj (object): Instantiated object with compatible hash interface.
         a           (int): Random private value.
     """
     self.a = a or Bytes.random(4).int() % N
     self.g = g
     self.A = pow(g, self.a, N)
     self.identity = identity
     self.password = password
     self.N = N
     self.hash_obj = hash_obj
     self.k = hash_obj.hash(Bytes(N) + self.PAD(g)).int()
Exemple #29
0
    def sign(self, plaintext: bytes, salt: bytes=None) -> Bytes:
        """
        Pads and hashes the `plaintext`.

        Parameters:
            plaintext (bytes): Plaintext to sign.
            salt      (bytes): (Optional) Random salt.
        
        Returns:
            Bytes: Probabilistic signature.
        """
        plaintext = Bytes.wrap(plaintext)
        mHash     = self.hash_obj.hash(plaintext)

        salt    = salt or Bytes.random(self.salt_len)
        m_prime = b'\x00' * 8 + mHash + salt

        H = self.hash_obj.hash(m_prime)

        em_bits = self.modulus_len - 1
        em_len  = (em_bits + 7) // 8
        ps_len = em_len - self.hash_obj.digest_size - self.salt_len - 2

        if ps_len < 0:
            raise ValueError("Plaintext is too long")

        PS = Bytes(b'').zfill(ps_len)

        DB        = PS + b'\x01' + salt
        db_mask   = self.mgf(H, em_len - self.hash_obj.digest_size - 1)
        masked_db = DB ^ db_mask

        # Set the leftmost 8emLen - emBits bits of the leftmost octet in maskedDB to zero.
        masked_db &= (2**(len(masked_db) * 8) - 1) >> ((8 * em_len) - em_bits)

        return masked_db + H + b'\xbc'
Exemple #30
0
    def encrypt_and_auth(self, key: bytes, iv: bytes, plaintext: bytes,
                         auth_data: bytes) -> (Bytes, Bytes):
        mac_key, enc_key = key.chunk(self.chunk_size)

        rij = Rijndael(enc_key)
        cbc = CBC(rij, iv=iv)

        ciphertext = cbc.encrypt(plaintext)
        hmac = HMAC(
            mac_key,
            self.hash_obj).generate(auth_data + iv + ciphertext +
                                    Bytes(len(auth_data) *
                                          8).zfill(8))[:self.chunk_size]

        return ciphertext, hmac