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
    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()
示例#3
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."
    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!")
def bruteforce_dsa_privkey(bs, sig, max_k=2**16, p=P, q=Q, g=G):
    r, s = sig
    z = from_bytes(SHA1(bs).digest())

    for k in range(1, max_k):
        k_inv = invmod(k, q)
        if k_inv is None:
            continue

        x = (((((s * k) % q) - z) % q) * invmod(r, q)) % q

        sk, rk = (k_inv * (z + x * r)) % q, modexp(g, k, p) % q
        if s == sk and r == rk:
            return x
示例#7
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()
示例#8
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")
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")
示例#10
0
    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
示例#11
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)