def rsa_echo(self, ctext):
        # Eve is actually MITMing, not just eavesdropping.
        # To simulate an eavesdrop, have Eve discard the plaintext.
        self.parley("echo", ctext)

        # Steve will reject repeat submissions.
        assert self.parley("echo", ctext) is None

        # Eve cracks the ciphertext on her own.
        C = from_bytes(ctext)
        E, N = self.remote_pubkey
        S = random.randint(2, N - 1)

        C_ = (C * modexp(S, E, N)) % N
        ptext_ = self.parley("echo", to_bytes(C_))
        P_ = from_bytes(ptext_)

        P = (P_ * invmod(S, N)) % N
        ptext = to_bytes(P)

        print("Eve cracked Carol's plaintext:")
        print()
        print(" " * 4 + ptext.decode())
        print()

        # Carol won't notice a thing :P
        return ptext
Exemple #2
0
    def srp_authn(self, email, input_hmac):
        account = self.accounts[email]

        salt = account["salt"]
        salt_bytes = to_bytes(salt)

        A, b, u = account["A"], account["b"], account["u"]

        for password in WORDS:
            # Find x as in Steven's `hello` step/Carla's `kexch` step.
            x_bytes = sha256(salt_bytes + password.encode()).digest()
            x = from_bytes(x_bytes)

            # Find v as in Steven's `hello` step.
            v = modexp(self.g, x, self.n)

            # Find S and K as in Steven's `kexch` step.
            S = modexp(A * modexp(v, u, self.n), b, self.n)
            K = sha256(to_bytes(S)).digest()

            if hmac_sha256(K, salt_bytes) == input_hmac:
                return f"{email}, your password is '{password}'. Muahahaha!"

        # Password wasn't found in the dictionary.
        return f"These are not the droids you're looking for."
Exemple #3
0
    def srp_kexch(self):
        a = random.getrandbits(1536)
        A = modexp(self.g, a, self.n)

        # Carol now receives u from Steve.
        self.salt, B, u = self.parley("kexch", self.email, A)

        x_bytes = sha256(to_bytes(self.salt) + self.password.encode()).digest()
        x = from_bytes(x_bytes)

        # k is not used anymore.
        S = modexp(B, a + u * x, self.n)

        self.K = sha256(to_bytes(S)).digest()
    def srp_kexch(self):
        a = random.getrandbits(1536)
        A = modexp(self.g, a, self.n)

        self.salt, B = self.parley("kexch", self.email, A)

        u_bytes = sha256(to_bytes(A, B)).digest()
        u = from_bytes(u_bytes)

        x_bytes = sha256(to_bytes(self.salt) + self.password.encode()).digest()
        x = from_bytes(x_bytes)

        S = modexp(B - self.k * modexp(self.g, x, self.n), a + u * x, self.n)

        self.K = sha256(to_bytes(S)).digest()
Exemple #5
0
def decryptor(ctext, pubkey, oracle, show=True):
    e, n = pubkey
    two = modexp(2, e, n)

    # Decryption algorithm as described in the challenge.
    # Mostly works, but usually fails for the last character.
    #
    # lower, upper, ptext = 0, n, b""
    # while lower < upper:
    #     mid = (upper + lower) // 2
    #     if oracle(ctext):
    #         upper -= mid
    #     else:
    #         lower += mid
    # return to_bytes(upper)

    lower, upper, bit_length = 0, 1, n.bit_length()

    for i in range(1, bit_length + 1):
        diff, lower, upper = upper - lower, lower << 1, upper << 1
        ctext = (ctext * two) % n
        if oracle(ctext):
            upper -= diff
        else:
            lower += diff
        print("\r" + to_str((upper * n) >> i) + "\033[K", end="", flush=True)
    else:
        print()

    return to_bytes((upper * n) >> bit_length)
    def srp_kexch(self, email, A):
        account = self.accounts[email]

        b = random.getrandbits(1536)
        B = self.k * account["v"] + modexp(self.g, b, self.n)

        u_bytes = sha256(to_bytes(A, B)).digest()
        u = from_bytes(u_bytes)

        # We can't simply calculate the `A * v ** u` part of
        # `S = (A * v ** u) ** b % n`; the result is huge. But it seems
        # that all arithmetic is performed modulo n of late. *hint hint*
        S = modexp(A * modexp(account["v"], u, self.n), b, self.n)

        account["K"] = sha256(to_bytes(S)).digest()

        return account["salt"], B
    def srp_hello(self, email, password):
        salt = random.getrandbits(32)

        x_bytes = sha256(to_bytes(salt) + password.encode()).digest()
        x = from_bytes(x_bytes)

        v = modexp(self.g, x, self.n)

        self.accounts[email] = {"password": password, "salt": salt, "v": v}

        return self.n, self.g, self.k
def main():
    # NOTE BEFORE STARTING: Do not be fooled! Signatures are created using
    # private keys, notwithstanding the (perhaps intentionally misleading?)
    # wording in this and the previous challenge that might imply otherwise.

    lines = loader("44.txt", lambda l: l.rstrip("\n").split(": "))

    msgs = []

    for i in range(0, len(lines), 4):
        block = lines[i:i + 4]

        # After the rstrip() and split() above, a block looks like:
        #
        #   [["msg", "Listen for me, you better listen for me now. "],
        #    ["s", "1267396447369736888040262262183731677867615804316"],
        #    ["r", "1105520928110492191417703162650245113664610474875"],
        #    ["m", "a4db3de27e2db3e5ef085ced2bced91b82e0df19"]]
        #
        # We have a message, the components of a DSA signature, and the SHA1
        # hash of the message. Everything here's a `str` at the moment, so
        # we'll transform the values.
        #
        # There's an error in "m" for one of the blocks in the challenge data,
        # but we can just calculate the hash ourselves.
        block[0][1] = block[0][1].encode()
        block[1][1] = int(block[1][1])
        block[2][1] = int(block[2][1])
        block[3][1] = from_bytes(SHA1(block[0][1]).digest())

        msgs.append({data[0]: data[1] for data in block})

    print(f"Loaded {len(msgs)} DSA-signed messages.")
    print("Recovering private key from the first repeated nonce we detect.")

    for msg1, msg2 in combinations(msgs, 2):
        if msg1["r"] != msg2["r"]:
            continue

        m1, m2 = msg1["m"], msg2["m"]
        s1, s2 = msg1["s"], msg2["s"]

        k = (((m1 - m2) % Q) * invmod(s1 - s2, Q)) % Q

        privkey = recover_dsa_privkey(k, msg1["r"], s1, m1)
        digest = SHA1(to_hexstring(to_bytes(privkey))).hexdigest()
        assert digest == "ca8f6f7c66fa362d40760d135b763eb8527d3d52"

        print()
        print("Recovered key:", privkey)

        break
    else:
        print("Failed to recover key!")
Exemple #9
0
def forge_rsa_e3(bs, pubkey, hash_cls=SHA1):
    e, n = pubkey
    n_byte_length = byte_length(n)

    # Создание дополненного хэша, который начинается с "0x0001ff00 <ASN.1> <ptext_digest>",
    # заканчивается практически чем угодно, и имеет такой же размер, как и модуль.
    phash = b"\x00\x01\xff" + ASN_1 + hash_cls(bs).digest()
    phash = phash.ljust(n_byte_length, b"\xff")

    # Найти целое число от корня этого хэша; это не должно быть идеально.
    eth_root = nth_root(from_bytes(phash), e)
    forged_sig = to_bytes(eth_root)

    # Окончательная поддельная подпись корректна по праву и равна модулю.
    return forged_sig.rjust(n_byte_length, b"\x00")
Exemple #10
0
    def srp_kexch(self, email, A):
        account = self.accounts[email]

        b = random.getrandbits(1536)
        B = modexp(self.g, b, self.n)

        # u is now simply a random uint128.
        u = random.getrandbits(128)

        S = modexp(A * modexp(account["v"], u, self.n), b, self.n)

        account["K"] = sha256(to_bytes(S)).digest()

        # Steven now sends u to Carl.
        return account["salt"], B, u
def forge_rsa_e3(bs, pubkey, hash_cls=SHA1):
    e, n = pubkey
    n_byte_length = byte_length(n)

    # Craft a padded hash that begins with "0x0001ff00<ASN.1><ptext_digest>",
    # ends with pretty much anything, and is as long as the modulus.
    phash = b"\x00\x01\xff" + ASN_1 + hash_cls(bs).digest()
    phash = phash.ljust(n_byte_length, b"\xff")

    # Find the integer e'th root of this hash; it doesn't need to be perfect.
    eth_root = nth_root(from_bytes(phash), e)
    forged_sig = to_bytes(eth_root)

    # Final forged signature is right-justified to be as long as the modulus.
    return forged_sig.rjust(n_byte_length, b"\x00")
Exemple #12
0
def decryptor(ctext, pubkey, oracle, show=True):
    e, n = pubkey
    two = modexp(2, e, n)

    lower, upper, bit_length = 0, 1, n.bit_length()

    for i in range(1, bit_length + 1):
        diff, lower, upper = upper - lower, lower << 1, upper << 1
        ctext = (ctext * two) % n
        if oracle(ctext):
            upper -= diff
        else:
            lower += diff
        print("\r" + to_str((upper * n) >> i) + "\033[K", end="", flush=True)
    else:
        print()

    return to_bytes((upper * n) >> bit_length)
def main():
    print("First, we'll test our DSA implementation.")
    _test_dsa()
    print()

    print("Now, let's bruteforce a DSA private key from a 16-bit subkey.")
    print()

    ptext = (
        b"For those that envy a MC it can be hazardous to your health\n"
        b"So be friendly, a matter of life and death, just like a etch-a-sketch\n"
    )
    sig = [
        548099063082341131477253921760299949438196259240,
        857042759984254168557880549501802188789837994940,
    ]

    print(f"Plaintext:")
    print_indent(*ptext.split(b"\n"), width=70, as_hex=False)

    print(f"Bruteforced private key:")
    privkey = bruteforce_dsa_privkey(ptext, sig)
    print_indent(privkey, as_hex=False)

    # This part is a little convoluted, but the SHA-1 hashes mentioned
    # in the challenge must've been mentioned ~for a reason~!!
    known_sha1s = [
        "d2d0714f014a9784047eaeccf956520045c45265",
        "0954edd5e0afe5542a4adf012611a91912a3ec16",
    ]
    sha1s = [
        SHA1(ptext).hexdigest(),
        SHA1(to_hexstring(to_bytes(privkey))).hexdigest()
    ]
    print(
        "Calculated hashes match for plaintext and private key:",
        all(a == b for a, b in zip(known_sha1s, sha1s)),
    )
Exemple #14
0
def main():
    ptext = random.choice(PTEXTS)

    print("Generating 3 public RSA keys and encrypting a plaintext.")
    print()

    n, c = [], []

    for i in range(3):
        pubkey, privkey = make_rsa_keys()
        ctext = rsa(ptext, pubkey)
        assert rsa(ctext, privkey) == ptext

        print(f"Ciphertext {i}:")
        print_indent(ctext)

        n.append(pubkey[1])
        c.append(from_bytes(ctext))

    if len(set(c)) == 1:
        print("The ciphertexts are sometimes identical.")
        print("This is fine; we also rely upon the public keys differing.")
        print()

    result, n_012 = 0, 1

    for i in range(3):
        ms = n[(i + 1) % 3] * n[(i + 2) % 3]
        result += c[i] * ms * invmod(ms, n[i])

        n_012 *= n[i]

    result = nth_root(result % n_012, 3)

    print("Cracked plaintext:")
    print_indent(to_bytes(result), as_hex=False)
    def srp_authn(self, email, input_hmac):
        account = self.accounts[email]
        hmac = hmac_sha256(account["K"], to_bytes(account["salt"]))

        return f"Login {'OK' if hmac == input_hmac else 'FAIL'}, {email}."