예제 #1
0
    def sign(self, msg: bytes, k: int = None) -> bytes:
        """Sign a message `msg` with DSA and return the signature tuple `(r, s)`
        """
        r = s = 0
        while r == 0 or s == 0:
            k = k or randint(1, self.q - 1)

            r = modpow(self.g, k, self.p) % self.q
            hm = int.from_bytes(sha1(msg), 'big')
            s = (modinv(k, self.q) * (hm + self.x * r)) % self.q

        return r, s
예제 #2
0
    def verify(self, msg: bytes, r: int, s: int) -> bool:
        """Verify a signature `(r, s)` is for a given `msg`.
        """
        valid = 0 < r < self.q and 0 < s < self.q

        w = modinv(s, self.q)
        hm = int.from_bytes(sha1(msg), 'big')
        u1 = (hm * w) % self.q
        u2 = (r * w) % self.q
        v = ((modpow(self.g, u1, self.p) * modpow(self.y, u2, self.p)) %
             self.p) % self.q

        print(f'W: {w}')
        print(f'V: {v}')
        print(f'R: {r}')

        return valid and v == r
예제 #3
0
            return plaintext
        else:
            raise ValueError('Ciphertext already seen')
        """
        return plaintext


if __name__ == '__main__':
    print('Challenge #41 - Implement unpadded message recovery oracle')

    server = RSAServer()

    # With a generated, good plaintext
    plaintext = int.from_bytes(bytes(json.dumps({
        'time': timegm(datetime.now(tz=timezone.utc).timetuple()),
        'social': '555-55-5555'
    }).encode('UTF-8')), 'big')

    e, n = server.public_key
    c = modpow(plaintext, e, n)

    s = randint(2, 1000)
    c_prime = (modpow(s, e, n) * c) % n

    p_prime = server.decrypt(c_prime)

    recovered_p = p_prime * modinv(s, n)

    print(plaintext)
    print(recovered_p)
예제 #4
0
            logger.debug(f'Calculating intervals from:')
            logger.debug(f'    a: {a}')
            logger.debug(f'    b: {b}')
            r_start = divceil(a * s[i] - 3 * B + 1, rsa.n)
            r_end = (b * s[i] - 2 * B) // rsa.n
            logger.debug(f'    {r_start}, {r_end}')
            for r in range(r_start, r_end + 1):  # r_start <= r <= r_end
                interval_start = max(a, divceil(2 * B + r * rsa.n, s[i]))
                interval_end = min(b, (3 * B - 1 + r * rsa.n) // s[i])
                intervals.add((interval_start, interval_end))
        M[i] = list(intervals)

        logger.debug(f'Built {len(M[i])} intervals:')
        for a, b in M[i]:
            logger.debug(f'    {hex(a)}')
            logger.debug(f'    {hex(b)}')
            logger.debug(f'    m is in interval? {a <= m <= b}')
            logger.debug(f'    {b - a}')

        # Step 4: Computing the solution
        if len(M[i]) == 1 and M[i][0][0] == M[i][0][1]:
            a = M[i][0][0]
            discovered_m = a * modinv(s[0], rsa.n) % rsa.n
            break

        i += 1

    assert discovered_m == m
    logger.info(f'original m:  {hex(m)}')
    logger.info(f'dicovered m: {hex(discovered_m)}')
예제 #5
0
#!/usr/bin/env python

from cryptopals_39 import modinv
from cryptopals_43 import DSA

if __name__ == '__main__':
    print('Challenge #45 - DSA parameter tampering')

    # When we sign a message with g=0
    dsa = DSA(g=0)
    msg = b'The oldest and strongest emotion of mankind is fear, and the oldest and strongest kind of fear is fear of the unknown'

    # Infinitely loops, because 0 to any positive power is 0 (r = ), failing the
    # non-zero requirements for r and s
    # r, s = dsa.sign(msg)

    # Try g=p+1
    dsa = DSA(g=DSA.DEFAULT_P + 1)

    r1, s1 = dsa.sign(b'Hello, world')
    r2, s2 = dsa.sign(b'Goodbye, world')

    # Build magic signature
    z = 14
    r = (dsa.y**12 % dsa.p) % dsa.q
    s = (r * modinv(z, dsa.q)) % dsa.q

    assert dsa.verify(b'Hello, world', r, s)
    assert dsa.verify(b'Goodbye, world', r, s)
예제 #6
0
    rsa_1 = RSA()
    rsa_2 = RSA()
    assert len(set([rsa_0.n, rsa_1.n, rsa_2.n])) == 3
    
    # Given some random input number
    inp = randint(1, 10000)

    c_0 = rsa_0.encrypt(inp) % rsa_0.n
    c_1 = rsa_1.encrypt(inp) % rsa_1.n
    c_2 = rsa_2.encrypt(inp) % rsa_2.n

    # m_s_n (for n in 0, 1, 2) are the product of the moduli EXCEPT n_n ---
    # ie, m_s_1 is n_0 * n_2
    m_s_0 = rsa_1.n * rsa_2.n
    m_s_1 = rsa_0.n * rsa_2.n
    m_s_2 = rsa_0.n * rsa_1.n

    N_012 = rsa_0.n * rsa_1.n * rsa_2.n

    # Chinese Remainder Theorem
    result = (
        c_0 * m_s_0 * modinv(m_s_0, rsa_0.n) + 
        c_1 * m_s_1 * modinv(m_s_1, rsa_1.n) + 
        c_2 * m_s_2 * modinv(m_s_2, rsa_2.n)
    ) % N_012

    # Take the cube root, round and convert to an integer
    decrypted = int(round(result ** (1 / 3), 0))

    assert inp == decrypted
예제 #7
0
    for signatures in ks.values():
        # Need multiple messages signed using the same k
        if len(signatures) == 1:
            continue
        
        msg1, s1, r1, m1 = signatures[0]
        msg2, s2, r2, m2 = signatures[1]

        # Convert to bytes for consistency
        msg1 = bytes(msg1.encode('UTF-8'))
        msg2 = bytes(msg2.encode('UTF-8'))

        # TODO: Unable to determine the modular multiplicative inverse for two
        #       of these pairs of messages, need to look into this
        try:
            k = (((m1 - m2) % dsa.q) * modinv(s1 - s2, dsa.q)) % dsa.q
        except Exception as e:
            print(e)
            continue

        print(f'K: {k}')

        # Now, back to #43, can determine x from k
        x = dsa_recover_x(msg1, k, dsa.q, r1, s1)
        print(f'X: {x}')

        # When we sign a message again, using the x and k we found, the (r, s)
        # signature should be identical
        dsa = DSA(x=x, y=y)
        test_r1, test_s1 = dsa.sign(msg1, k=k)