Beispiel #1
0
def test_hmac(password, salt, u, client_public_key, secret_key, base, real_hmac, prime = NIST_PRIME):
        """
        Takes in all variables used by the server in simple SRP and calculates 
        the hmac. Tests if the calculated hmac matches the true hmac.
        Args: 
            password (bytes): user password
            salt (int): salt used in SRP. Should be random
            u (int): u used in SRP. Should be random
            client_public_key (int): clients public key
            secret_key (int): servers secret key
            base (int): base used in diffie hellman
        returns:
            bool: True if simple srp claculation matches hmac given, false otherwise
        """
        salt = bso.int_to_bytes(salt)
        x = int(sha256(salt + password).hexdigest(), 16)
        v = modexp(base, x, prime)

        S = modexp(client_public_key * modexp(v, u, prime), secret_key, prime)
        
        hmac_key = sha256(bso.int_to_bytes(S)).digest()
        
        calc_hmac = hmac(hmac_key, salt, lambda val:sha256(val).digest(), 64, 32)
        
        if real_hmac == calc_hmac:
            return True
        return False
Beispiel #2
0
    def verify_hmac(self, recv_hmac):
        """
        Final SRP verification. Computes the hmac which depends depends on the
        salt and password but also on a Diffie Hellmen shared key. Equates with
        the hamc submitted by the client
    

        Args:
            recv_hmac (bytes): hmac computed byt he client
        Returns:
            string, int: 'OK', 200 if the verification is successful
                        'Nope', 400 if the verification is unsuccessful
        """

        S = modexp(self.client_public_key * modexp(self.v, self.u, self.prime),
                   self.secret_key, self.prime)

        hmac_key = sha256(bso.int_to_bytes(S)).digest()

        salt_bytes = bso.int_to_bytes(self.salt)

        calc_hmac = hmac(hmac_key, salt_bytes,
                         lambda val: sha256(val).digest(), 64, 32)

        if recv_hmac == calc_hmac:
            return 'OK', 200
        return 'Nope', 400
Beispiel #3
0
    def calculate_hmac(self):
        """Calculates the hmac and returns it. If the password is correct, it
        it should match the hmac calculated byt the server.
        
        returns:
            bytes: hmac depending on password, salt and server and client keys
        
        """
        u = sha256(
            bso.int_to_bytes(self.public_key) +
            bso.int_to_bytes(self.server_public_key)).hexdigest()
        u = int(u, 16)

        #conver salt to bytes for hashing
        salt_bytes = bso.int_to_bytes(self.salt)

        password_exp = sha256(salt_bytes + self.user_password).hexdigest()
        password_exp = int(password_exp, 16)

        #Calculating the key for hmac
        S_base = (self.server_public_key - self.k *
                  modexp(self.base, password_exp, self.prime)) % self.prime
        S_exponent = (self.secret_key + u * password_exp) % self.prime
        S = modexp(S_base, S_exponent, self.prime)

        hmac_key = sha256(bso.int_to_bytes(S)).digest()

        calc_hmac = hmac(hmac_key, salt_bytes,
                         lambda val: sha256(val).digest(), 64, 32)

        return calc_hmac
Beispiel #4
0
    def verify(self, message, public_key, r, s):

        s_inv = nt.invmod(s, self.q)

        msg_hash = int(self.hash(message).hexdigest(), 16)
        exp1 = msg_hash * s_inv % self.q

        exp2 = r * s_inv % self.q

        v = ((nt.modexp(self.g, exp1, self.p) *
              nt.modexp(public_key, exp2, self.p)) % self.p) % self.q

        return v == r
def parity_oracle_attack(ciphertext, e, modulus, parity_oracle):
    """Cracks an rsa ciphertext using a parity oracle

    Args:
        cipehertext (int): encrypted plaintext for decryption
        e (int): public exponent used in rsa
        moduls (int): Modulus used by rsa encryption
        parity_oracle (function): fucntion which decrypts the ciphertext and
            returns true if the ciphertext is even, false otherwise
    returns:
        int: decrypted ciphertext
    """
    lower_bound = 0
    upper_bound = modulus

    while lower_bound != upper_bound:

        ciphertext = (nt.modexp(2, e, modulus) * ciphertext)
        difference = upper_bound - lower_bound

        if difference % 2 == 1:
            difference += 1

        if parity_oracle(ciphertext):
            upper_bound = upper_bound - difference // 2

        else:
            lower_bound = lower_bound + difference // 2

        #Uncomment for hollywood style hacking
        #print(upper_bound)

    return upper_bound
    def step2c(self):

        a, b = self.M[0]

        r = ceil_division(2 * (b * self.s - 2 * self.B), self.mod)

        for _ in range(0, 1000):
            #We expect to find a value every 3 iterations of r. 1000 should be
            #overkill

            test_s = ceil_division(2 * self.B + r * self.mod, b)
            upper_bound = ceil_division(3 * self.B + r * self.mod, a)

            while test_s < upper_bound:

                if self.oracle(
                    (self.c * nt.modexp(test_s, self.e, self.mod)) % self.mod):

                    self.s = test_s
                    return

                test_s += 1

            r += 1
        raise Exception('Error, r,s pair not found in step 2c')
 def gen_public_key(self):
     if self.secret_key == None:
         raise Exception(
             'Need to set secret key before calculating public key')
     self.public_key = numbers.modexp(self.base, self.secret_key,
                                      self.prime)
     return self.public_key
 def gen_shared_key(self, public_key):
     if self.secret_key == None:
         raise Exception(
             'Need to set secret key before calculating shared key')
     self.shared_key = numbers.modexp(public_key, self.secret_key,
                                      self.prime)
     return self.shared_key
Beispiel #9
0
 def send_dh_public_key(self):
     """Calculates and returns the SRP public key and user email
     
     Returns:
         bytes, int: a tuple of user email (bytes) and the clients secret key (int)
     """
     self.public_key = modexp(self.base, self.secret_key, self.prime)
     return self.user_email, self.public_key
    def step2b(self):

        s_start = self.s + 1

        while not self.oracle(
            (self.c * nt.modexp(s_start, self.e, self.mod)) % self.mod):
            s_start += 1

        self.s = s_start
Beispiel #11
0
    def decrypt_to_bytes_and_check_padding(self, ciphertext):

        #Decrypt a la RSA
        plaintext = nt.modexp(ciphertext, self.d, self.n)

        plaintext = plaintext.to_bytes(bso.byte_len(self.n), 'big')

        #Check the padding before returning the decryption
        if self.check_padding_from_bytes(plaintext):
            return plaintext
        else:
            raise Exception('Invalid padding')
    def send_dh_public_key(self):
        """Calculates and returns the SRP public key
        
        Returns:
            salt (int): random integer below the agreed upon prime
            public_key (int): public key generated by the server for SRP
        """

        #key calculaton
        self.public_key = (self.k * self.v + modexp(self.base, self.secret_key,
                                                    self.prime)) % self.prime

        return self.salt, self.public_key
Beispiel #13
0
    def send_dh_public_key(self):
        """Calculates and returns the SRP public key
        
        Returns:
            salt (int): random integer below the agreed upon prime
            public_key (int): public key generated by the server for SRP
            int: used in SRP calculation
        """

        #key calculaton
        self.public_key = modexp(self.base, self.secret_key, self.prime)
        self.u = secrets.randbelow(2**129)

        return self.salt, self.public_key, self.u
Beispiel #14
0
    def sign_message(self, message):

        r = s = 0

        k = secrets.randbelow(self.q)

        r = nt.modexp(self.g, k, self.p) % self.q

        k_inv = nt.invmod(k, self.q)

        msg_hash = int(self.hash(message).hexdigest(), 16)
        s = (k_inv * (msg_hash + self.secret_key * r)) % self.q

        return self.public_key, r, s
Beispiel #15
0
def main():

    oracle = RSAOracle()

    client = rsa.RSAClient()
    client.recv_public_key(*oracle.send_public_key())

    message = b'A secret message'

    #Client encrypts the message
    message_int = int(bso.bytes_to_hex(message), 16)
    ciphertext = client.encrypt(message_int)

    #Client sends ciphertext which gets decrypted

    assert message == bso.hex_to_bytes(hex(oracle.decrypt(ciphertext))[2:])

    #Attacker intercepts the ciphertext and tries to get the plaintext from
    #the oracle. This fails because the oracle only decrypts each plaintext once

    try:
        successfully_decrypted = message == bso.hex_to_bytes(
            hex(oracle.decrypt(ciphertext))[2:])
    except:
        successfully_decrypted = False

    assert successfully_decrypted == False

    #instead the attacker can get the decryption of an alternate ciphertext and
    # convert it to the original message. This attack uses the fat that exponentiation
    # is a homomorphism

    e, n = oracle.send_public_key()

    #S can be any value

    S = 2

    altered_ciphertext = nt.modexp(S, e, n) * ciphertext % n

    altered_message = oracle.decrypt(altered_ciphertext)

    #altered message = S * message

    new_message = altered_message * nt.invmod(S, n) % n
    assert message == bso.hex_to_bytes(hex(new_message)[2:])
Beispiel #16
0
def main():

    server = ChallengeDSAUser(SHA1)
    client = ChallengeDSAUser(SHA1)

    #malicious g parameter
    server.g = client.g = 0
    server.key_generation()
    client.key_generation()

    message = b'henlo'
    signature = server.sign_message(message)

    assert client.verify(message, *signature)
    assert signature[0] == 0
    assert signature[1] == 0

    #since g = 0, any signature will have r = 0 and secret key = 0
    #  but worse still, any signature with r = 0 will verify any message

    new_message = secrets.token_bytes(21)

    assert client.verify(new_message, *signature)

    #new malicious g value
    server.g = client.g = server.p + 1
    server.key_generation()
    client.key_generation()

    signature = server.sign_message(message)
    assert signature[0] == signature[1] == 1
    assert client.verify(message, *signature)

    #we can construct a magic signature for a given public key and any message
    #choose a random public key

    public_key = secrets.randbelow(server.p)

    z = 3  #a magic number (not actually magic in this case, any z will do)

    r = nt.modexp(public_key, z, server.p) % server.q

    s = (r * nt.invmod(z, server.q)) % server.q

    assert client.verify(new_message, public_key, r, s)
Beispiel #17
0
    def _password_computation(self, user_password):
        """Computes a hash of the users password for storing and later computations

        Args: 
            user_password (bytes): users password

        Returns:
            hashed version of the password which is used in SRP
        """

        #Salt needs to be converted to bytes for use in the hash
        salt_bytes = bso.int_to_bytes(self.salt)

        #password is padded with salt (a random int) and hased to be used as
        #an exponent. This same calculation is also done by the client.

        password_exponent = sha256(salt_bytes + user_password).hexdigest()
        password_exponent = int(password_exponent, 16)

        return modexp(self.base, password_exponent, self.prime)
    def test_nonce(self, nonce, message, r, s):
        """Tests is a nonce gives the desired signature for a message"""

        message_int = int(self.hash(message).hexdigest(), 16)

        test_r = nt.modexp(self.g, nonce, self.p) % self.q

            #Don't test s if r does not match
            
        if test_r == r:
            secret_key = self.secret_key_from_nonce(message, nonce, r, s)
        
            nonce_inv = nt.invmod(nonce, self.q)

            test_s = (nonce_inv * (message_int + secret_key * r)) % self.q
            
            if test_s == s:
                return secret_key
        
        return 0
Beispiel #19
0
 def key_generation(self):
     self.secret_key = secrets.randbelow(self.q)
     self.public_key = nt.modexp(self.g, self.secret_key, self.p)
Beispiel #20
0
 def decrypt(self, ciphertext):
     return nt.modexp(ciphertext, self.d, self.n)
Beispiel #21
0
 def encrypt(self, plaintext):
     return nt.modexp(plaintext, self.e, self.n)