示例#1
0
def sha1_mac(message):
    keys = []
    with open("/usr/share/dict/words", "r") as fd:
        for line in fd:
            keys.append(line.rstrip())

    key = random.choice(keys).encode()
    signature = hash.sha1(key + message)

    return signature, key
def verify_signature(signature: tuple, msg: str, pub_key: tuple) -> bool:
    p, alpha, beta = pub_key

    hashed = int(hash.sha1(msg), 16)

    r, s = signature
    if 0 >= r or r >= p or 0 >= s or s >= p - 1:
        return False

    return pow(alpha, hashed, p) == (pow(beta, r, p) * pow(r, s, p)) % p
示例#3
0
def do_work(filename, list_data, pkgname_parent="", flag_delete=False):
    logger_do_work = logging.getLogger("do_work")
    l = []

    for sub_filename in walk_dir(filename):

        if os.path.islink(sub_filename):
            os.unlink(sub_filename)
            logger_do_work.debug('unlink %s' % sub_filename)
            continue
        #FIXME: 判断解压临时存储位置是否能放得下
        #TODO: 考虑分片读取数据降低内存压力
        file_bindata = open(sub_filename, 'rb').read()
        d_md5 = hash.md5(file_bindata)
        d_sha1 = hash.sha1(file_bindata)
        d_sha256 = hash.sha256(file_bindata)
        filesize = os.stat(sub_filename).st_size

        cmd = 'file "%s" | cut -c %s-' % (sub_filename, len(sub_filename) + 3)
        logger_do_work.debug(cmd)
        filetype = os.popen(cmd).read().strip()
        if os.path.isfile(filename):
            t_filename = sub_filename[sub_filename.index(pkgname_parent) +
                                      len(pkgname_parent):]
        else:
            t_filename = sub_filename.partition(filename)[2]

        if is_pack(sub_filename):
            dir_temp = o_unpack.unpack(sub_filename)
            pkg_info = (t_filename, pkgname_parent, d_md5, d_sha1, d_sha256,
                        filesize, filetype)
            logger_do_work.debug("recursive do_work start: %s", t_filename)
            ll = do_work(dir_temp, list_data, t_filename, flag_delete=True)
            logger_do_work.debug("recursive do_work end: %s", t_filename)
            d = {}
            d[pkg_info] = ll
            l.append(d)
        else:
            l.append((t_filename, pkgname_parent, d_md5, d_sha1, d_sha256,
                      filesize, filetype))
            if flag_delete:
                removefiles(sub_filename)
    else:
        if flag_delete:
            removefiles(filename)
    return l
def sign(msg: str, priv_key: tuple, pub_key: tuple) -> tuple:
    p, a = priv_key
    alpha = pub_key[1]

    hashed = int(hash.sha1(msg), 16)

    s = 0
    r = 0
    while s == 0:
        k = 1
        while k < 2 or gcd(k, p - 1) != 1:
            k = secrets.randbelow(p - 1)

        r = pow(alpha, k, p)
        s = ((hashed - a * r) * pow(k, -1, p - 1)) % (p - 1)

    return (r, s)
示例#5
0
def extendSha1MacedMessage(message, authentication, extension, verifier):
	h4 = authentication & (2**32-1)
	h3 = authentication>>32 & (2**32-1)
	h2 = authentication>>64 & (2**32-1)
	h1 = authentication>>96 & (2**32-1)
	h0 = authentication>>128 & (2**32-1)

	
	guessedKeyLen = 0

	while True:
		#Measured in bytes, not bits
		extraLength = ((len(message)+guessedKeyLen+64)/64)*64
		newMac = hash.sha1(extension, h0, h1, h2, h3, h4, extraLength)
		newMessage = padMessageForKeyLength(message, guessedKeyLen)+extension
		if verifier(newMessage, newMac):
			return (newMessage, newMac)
		guessedKeyLen += 1
示例#6
0
def do_work(filename, list_data, pkgname_parent="", flag_delete=False):
    logger_do_work = logging.getLogger("do_work")
    l = []
        
    for sub_filename in walk_dir(filename):
        
        if os.path.islink(sub_filename):
            os.unlink(sub_filename)
            logger_do_work.debug('unlink %s' % sub_filename)
            continue
        #FIXME: 判断解压临时存储位置是否能放得下
        #TODO: 考虑分片读取数据降低内存压力
        file_bindata = open(sub_filename, 'rb').read()
        d_md5 = hash.md5(file_bindata)
        d_sha1 = hash.sha1(file_bindata)
        d_sha256 = hash.sha256(file_bindata)
        filesize = os.stat(sub_filename).st_size
        
        cmd= 'file "%s" | cut -c %s-' % (sub_filename, len(sub_filename)+3)
        logger_do_work.debug(cmd)
        filetype =os.popen(cmd).read().strip() 
        if os.path.isfile(filename):
            t_filename = sub_filename[sub_filename.index(pkgname_parent)+len(pkgname_parent):]
        else:
            t_filename = sub_filename.partition(filename)[2]
        
        if is_pack(sub_filename):
            dir_temp = o_unpack.unpack(sub_filename)
            pkg_info = (t_filename, pkgname_parent, d_md5, d_sha1, d_sha256, filesize, filetype)
            logger_do_work.debug("recursive do_work start: %s", t_filename)
            ll = do_work(dir_temp,list_data, t_filename, flag_delete=True)
            logger_do_work.debug("recursive do_work end: %s", t_filename)
            d = {}
            d[pkg_info] = ll
            l.append(d)
        else:
            l.append((t_filename, pkgname_parent, d_md5, d_sha1, d_sha256, filesize, filetype))
            if flag_delete:
                removefiles(sub_filename)
    else:
        if flag_delete:
            removefiles(filename)
    return l
示例#7
0
def main():
    """ Test the algorithm """

    # create original signature
    msg = b"comment1=cooking%20MCs;userdata=foo;comment2=%20like%20a%20pound%20of%20bacon"
    sign_orig, key = sha1_mac(msg)

    # create a forged signature ending with exploit
    exploit = b";admin=true"

    forgery = []
    # we don't know the key length, so the padding size must be bruteforced
    for key_len in range(1, 0x20):
        dummy_key = b"A" * key_len
        pad1 = mdpadding(dummy_key + msg)
        pad2 = mdpadding(dummy_key + msg + pad1 + exploit)
        assert (len(exploit + pad2) == 64)

        # send message to server with exploit
        message = msg + pad1 + exploit

        # now find the hash of our exploit to ensure it's valid
        new_h = sha1_states(sign_orig)
        state = hash._process_chunk(exploit + pad2, *new_h)
        signature = '%08x%08x%08x%08x%08x' % state
        forgery.append((signature, message))

    # send forgeries to 'server'. Check signature is correct
    for signature, message in forgery:
        validation = hash.sha1(key + message)

        if validation == signature:
            print("Valid Sha1 Mac: ", message)
            print("Signature", signature)
            sys.exit()

    print("No successful forgeries created.")
示例#8
0
			message = int(splitLine[1], 16)
			signedMessages.append((message, signature))

	#Find a pair of messages with matching r - indicates same k
	firstMessage = None
	secondMessage = None
	for message1 in signedMessages:
		for message2 in signedMessages:
			if message1 != message2:
				#If identical r
				if message1[1][0] == message2[1][0]:
					firstMessage = message1
					secondMessage = message2
					break
		if firstMessage is not None:
			break

	sharedK = extractK(firstMessage[0], firstMessage[1], secondMessage[0], secondMessage[1], pubKey)

	privKey = recoverKey(sharedK, firstMessage[1], firstMessage[0], pubKey)

	expectedKeyHash = 0xca8f6f7c66fa362d40760d135b763eb8527d3d52

	keyHash = hash.sha1(hex(privKey)[2:-1])

	print keyHash == expectedKeyHash




示例#9
0
    def starthandshake(
        self
    ):  #encrypt username with atm public key, and send it back (deny connection if username doesnt exist)
        self.client, self.clientaddr = self.s.accept()

        clienthello = self.client.recv(1024)
        clienthello = clienthello.decode('utf-8').split('-')
        atmprefs = json.loads(clienthello[0])
        print("ATM has initiated handshake, hello to BANK server!")

        # Parse hello message to select which PKC to use
        atmprefs = [x.lower() for x in atmprefs]
        common = list(set(self.methods) & set(atmprefs))
        scheme = None
        if len(common) == 0:
            self.client.close()
            raise Exception("no common methods between atm/bank")
        else:
            scheme = common[0]
        print(
            f"Handshake info --> common encryption scheme set to use {scheme}")

        # Load correct keys for selected system
        keypairs = None
        if scheme == "rsa":
            keypairs = rsa.load_keys("local_storage/bank-rsa.txt", 4096)
        else:
            keypairs = elgamal.load_keys("local_storage/bank-elgamal.txt",
                                         1024)
        pubkey = keypairs[0]
        privkey = keypairs[1]
        # Tell atm which scheme to use
        self.client.send(scheme.encode('utf-8'))

        # Begin Diffie-Hellman
        print("Handshake info --> recieving client random")
        clirand = self.client.recv(4096).decode('utf-8')
        print(
            "Handshake info --> signing client random, server random, and DH parameters"
        )
        dhprivateaes = secrets.randbelow(((self.p - 1) // 2) + 1)
        dhprivatemac = secrets.randbelow(((self.p - 1) // 2) + 1)

        # Generate our DH values for both aes key and mac key. Send to client along with their values to ensure we received it properly
        clisign = str(clirand) + '-' + str(pow(
            2, dhprivateaes, self.p)) + '-' + str(pow(2, dhprivatemac, self.p))
        # Sign the message so atm knows it came from bank
        clie = None
        if scheme == 'rsa':
            clie = rsa.sign(clisign, privkey)
        else:
            clie = elgamal.sign(clisign, privkey, pubkey)

        self.client.send(str(clisign).encode('utf-8'))
        print(
            f"Handshake info --> client says {self.client.recv(4096).decode('utf-8')}"
        )
        self.client.send(str(clie).encode('utf-8'))
        print(
            f"Handshake info --> client says {self.client.recv(4096).decode('utf-8')}"
        )

        self.client.send("breaker".encode('utf-8'))  #formatting

        # Use the DH values sent from atm previously to calculate the keys
        cliplain = clirand.split('-')
        self.aeskey = pow(int(cliplain[0]), dhprivateaes, self.p) % pow(2, 256)
        self.mackey = pow(int(cliplain[1]), dhprivatemac, self.p) % pow(2, 256)
        self.aeskey = format(self.aeskey, '064x')
        self.mackey = format(self.mackey, '064x')
        print(
            "Handshake info --> bank calculated aes/mac keys from DH exchange")
        print(
            f"Handshake info --> Bank ready to go, atm replied {aes.decrypt(self.client.recv(1024).decode('utf-8'),self.aeskey)}"
        )

        # Tell client we have the keys
        self.client.send((aes.encrypt("finished",
                                      self.aeskey)).encode('utf-8'))

        # Challenge client to see if they're an ATM
        client_keyname = aes.decrypt(
            self.client.recv(1024).decode('utf-8'), self.aeskey)
        challenge = format(secrets.randbits(20 * 8), '040x')

        try:
            if scheme == 'rsa':
                client_pubkey = rsa.load_public_key(
                    f"local_storage/{client_keyname}-rsa.pub")
                challenge_encrypted = rsa.encrypt(challenge, client_pubkey)
            else:
                client_pubkey = elgamal.load_public_key(
                    f"local_storage/{client_keyname}-elgamal.pub")
                challenge_encrypted = elgamal.encrypt(challenge, client_pubkey)
        except:
            self.client.close()
            raise Exception('client identifier is invalid')

        self.client.send(
            aes.encrypt(str(challenge_encrypted), self.aeskey).encode('utf-8'))

        client_response = aes.decrypt(
            self.client.recv(1024).decode('utf-8'), self.aeskey)
        if client_response != hash.sha1(challenge + self.aeskey):
            self.client.close()
            raise Exception("client is not an atm")

        self.post_handshake()
import hash

block_a = hash.sha1("IV")
block_b = hash.sha1(a)
block_c = hash.sha1(b)
block_d = hash.sha1(c)
block_e = hash.sha1(d)

# Chain of block hashes

print(e)
示例#11
0
		x = recoverKey(k, signature, messageHash, pubKey)
		testSignature = dsa.signMessageWithK(k, messageHash, x, p, q, g)
		if testSignature == signature:
			return (p, q, g, x)
		k += 1


if __name__ == "__main__":
	message = '''For those that envy a MC it can be hazardous to your health
So be friendly, a matter of life and death, just like a etch-a-sketch'''
	pubKey, privKey = dsa.generateKeys()

	signature, k = dsa.signMessage(message, privKey, leakK = True)

	#Test of key recovery
	assert privKey[3]== recoverKey(k, signature, hash.sha1(message), pubKey)

	#Discover challenge key
	'''
	The provided digest for the message does not match the output of my SHA-1 function 
	or the library SHA-1 function. I have therefore concluded that this is not a problem
	with my implementation.
	'''
	messageHash = 0xd2d0714f014a9784047eaeccf956520045c45265
	signature = (548099063082341131477253921760299949438196259240, 857042759984254168557880549501802188789837994940)

	p, q, g = dsa.STANDARD_PARAMS
	pubKey =(p, q, g, 0x84ad4719d044495496a3201c8ff484feb45b962e7302e56a392aee4abab3e4bdebf2955b4736012f21a08084056b19bcd7fee56048e004e44984e2f411788efdc837a0d2e5abb7b555039fd243ac01f0fb2ed1dec568280ce678e931868d23eb095fde9d3779191b8c0299d6e07bbb283e6633451e535c45513b2d33c99ea17)

	privKey = bruteForceKey(messageHash, signature, pubKey)
示例#12
0
def getAESKeyFromSharedSecret(sharedSecret):
	return convert.intToByteString(hash.sha1(convert.intToByteString(sharedSecret)))[0:16]
示例#13
0
				continue
		print maxMessage
		return (returnMessage, returnIV)


if __name__ == "__main__":
	counterPart = DHEchoer()

	privateKey = dh.generatePrivateKey(dh.STANDARD_P)

	counterPart.sendGroupParameters(dh.STANDARD_P, dh.STANDARD_G)

	publicValue = counterPart.sendPublicDHValue(dh.generatePublicValue(privateKey, dh.STANDARD_G, dh.STANDARD_P))
	sharedSecret = dh.deriveSecret(publicValue, privateKey, dh.STANDARD_P)

	aesKey = convert.intToByteString(hash.sha1(convert.intToByteString(sharedSecret)))[0:16]
	aesIV = aes.generateRandomKey()

	returnMessage, returnIV = counterPart.sendAESMessage(aes.aesCBCEncrypt("Test Message", aesKey, aesIV), aesIV)
	print aes.aesCBCDecrypt(returnMessage, aesKey, returnIV)

	#Now for the MITM attack
	# g = 1

	newCounterpart = PAlteringDHMITM(counterPart, 1, [1])

	newCounterpart.sendGroupParameters(dh.STANDARD_P, dh.STANDARD_G)

	publicValue = newCounterpart.sendPublicDHValue(dh.generatePublicValue(privateKey, dh.STANDARD_G, dh.STANDARD_P))

	sharedSecret = dh.deriveSecret(publicValue, privateKey, dh.STANDARD_P)
示例#14
0
def sign(msg: str, priv_key: tuple) -> int:
    hashed = int(hash.sha1(msg), 16)

    return pow(hashed, priv_key[1], priv_key[0])
示例#15
0
    def post_handshake(
            self):  #takes in user input to interact with bank indefinitely
        # Generate random starting counter value and send it to the bank
        self.counter = secrets.randbelow(pow(2, 2048))
        sendstr = str(self.counter)
        sendstr = aes.encrypt(
            str(self.counter) + "-" + hash.hmac(sendstr, self.mackey),
            self.aeskey)
        self.s.send(sendstr.encode('utf-8'))

        # Ensure bank correctly received our counter
        bankret = self.s.recv(99999).decode('utf-8')
        bankret = aes.decrypt(bankret, self.aeskey)
        bankret = bankret.split('-')
        try:
            self.countercheck(bankret)
        except Exception as e:
            print(str(e))
            self.s.close()
            return

        chkhash = bankret[-1]
        bankret.remove(chkhash)
        againsthash = '-'.join(bankret)
        bankret = bankret[1:]

        # Check if bank return message was modified
        if hash.hmac(againsthash, self.mackey) != chkhash:
            print("bank return msg integrity compromised")
            self.s.close()
            return

        print(f"Counter set, bank replied with '{bankret[0]}'")
        print("ATM")

        # User does not start logged in, so get their sign in credentials
        username = ""
        password = ""
        while True:
            print("Please log in")
            # Get credentials from user
            username = input("username: "******"password: "******"-" + hash.hmac(sendstr, self.mackey), self.aeskey)
            self.s.send(sendstr.encode('utf-8'))

            bankret = self.s.recv(99999).decode('utf-8')  #parse this out
            bankret = aes.decrypt(bankret, self.aeskey)
            bankret = bankret.split('-')

            # Ensure not some sort of replay
            try:
                self.countercheck(bankret)
            except Exception as e:
                print(str(e))
                continue

            chkhash = bankret[-1]
            bankret.remove(chkhash)
            againsthash = '-'.join(bankret)
            bankret = bankret[1:]

            # Ensure message hasn't been tampered with
            if hash.hmac(againsthash, self.mackey) != chkhash:
                print("bank return msg integrity compromised")
                continue
            print(f"bank responded with '{bankret[2]}' to the login attempt")
            if bankret[2] == "login successful":
                break

        print("\nExample withdraw: 'withdraw [positive_int]'")
        print("Example deposit: 'deposit [positive_int]'")
        print("Example check: 'check balance'")
        print("To close ATM, type q")
        print("---------------------------------------------------")

        while True:
            inp = input("command: ")
            inp = inp.strip()
            if inp == 'q':
                break

            # Start packet with username
            sendstr = username + '-'
            inp = inp.split(' ')

            # All atm operations require 2 parameters, so check that first
            if len(inp) != 2:
                print("not a valid operation supported by bank")
                continue

            # Parse user input
            if inp[0].lower() == 'withdraw':
                sendstr += inp[0].lower()
            elif inp[0].lower() == 'deposit':
                sendstr += inp[0].lower()
            elif inp[0].lower() == 'check':
                sendstr += inp[0].lower()
            else:
                print("not a valid operation supported by bank")
                continue

            # Ensure number is positive, if it is a number
            if inp[1].isnumeric() and int(inp[1]) > 0:
                sendstr += '-' + inp[1]
            elif inp[0].lower() == 'check' and inp[1].lower() == 'balance':
                sendstr += '-' + inp[1]
            else:
                print("invalid money amount")
                continue

            sendstr = str(self.counter) + '-' + sendstr
            sendstr = aes.encrypt(
                sendstr + "-" + hash.hmac(sendstr, self.mackey), self.aeskey)
            self.s.send(sendstr.encode('utf-8'))

            # Get bank's response to our request
            bankret = self.s.recv(99999).decode('utf-8')  #parse this out
            bankret = aes.decrypt(bankret, self.aeskey)
            bankret = bankret.split('-')

            # Ensure not replay
            try:
                self.countercheck(bankret)
            except Exception as e:
                print(str(e))
                continue

            chkhash = bankret[-1]
            bankret.remove(chkhash)
            againsthash = '-'.join(bankret)
            bankret = bankret[1:]

            # Check if message tampered with
            if hash.hmac(againsthash, self.mackey) != chkhash:
                print("bank return msg integrity compromised")
                continue

            print(
                f"bank responded with '{bankret[2]}' to the request, money in account: {bankret[1]}"
            )

        self.s.close()
示例#16
0
    def starthandshake(self):
        # Send supported PKCs as a hello packet
        self.s.send((str(json.dumps(self.prefs))).encode('utf-8'))

        bankhello = self.s.recv(4096)
        scheme = bankhello.decode('utf-8')

        # Parse bank response to see which PKC to use
        if scheme == "rsa":
            keypairs = rsa.load_keys("local_storage/atm-rsa.txt", 4096)
            bankpubkey = rsa.load_public_key(
                "local_storage/bank-rsa.txt"
            )  # simulates the bank's public keys being hardcoded into the atm. This way if we chose to reset the bank key, we don't have to update this
        else:
            keypairs = elgamal.load_keys("local_storage/atm-elgamal.txt", 2048)
            bankpubkey = elgamal.load_public_key(
                "local_storage/bank-elgamal.txt")  # see above
        pubkey = keypairs[0]
        privkey = keypairs[1]

        # Begin Diffie-Hellman
        print("Handshake info --> sending client random")

        # Generate random numbers and send to bank
        dhprivateaes = secrets.randbelow(((self.p - 1) // 2) + 1)
        dhprivatemac = secrets.randbelow(((self.p - 1) // 2) + 1)
        dh_message = str(pow(2, dhprivateaes, self.p)) + '-' + str(
            pow(2, dhprivatemac, self.p))
        self.s.send(dh_message.encode('utf-8'))

        # Get the bank's response
        clirandplain = self.s.recv(99999).decode('utf-8')
        self.s.send("recieved plaintext signature".encode('utf-8'))
        # Get the bank's signature to prove it sent the previous response
        clirandsign = self.s.recv(4096).decode('utf-8')

        # Verify the signature to ensure bank sent the message
        if scheme == 'rsa':
            clirandsign = rsa.verify_signature(int(clirandsign), clirandplain,
                                               bankpubkey)
        else:
            clirandsign = clirandsign.strip("(").strip(")").split(",")
            clirandsign = [x.strip() for x in clirandsign
                           ]  #take away tuple space or wierd stuff
            clirandsign = (int(clirandsign[0]), int(clirandsign[1]))
            clirandsign = elgamal.verify_signature(clirandsign, clirandplain,
                                                   bankpubkey)

        clirandplain = clirandplain.split('-')

        # Make sure the signature verified, and ensure our DH numbers were received by the bank properly
        if clirandsign and (clirandplain[0] + '-' +
                            clirandplain[1]) == dh_message:
            self.s.send("signature verify success".encode('utf-8'))
        else:
            self.s.send("signature verify failed".encode('utf-8'))
            self.s.close()
            raise Exception("signature verify failed")

        self.s.recv(4096)  #formatting

        # The bank got our DH numbers correctly and sent its own, so calculate keys
        print(
            "Handshake info --> bank signature verified, DH parameters recieved"
        )
        self.aeskey = pow(int(clirandplain[-2]), dhprivateaes, self.p) % pow(
            2, 256)
        self.mackey = pow(int(clirandplain[-1]), dhprivatemac, self.p) % pow(
            2, 256)
        self.aeskey = format(self.aeskey, '064x')
        self.mackey = format(self.mackey, '064x')
        print(
            "Handshake info --> atm calculated aes/mac keys from DH exchange")

        # Tell bank that we have the keys and are ready to use AES
        self.s.send((aes.encrypt("finished", self.aeskey)).encode('utf-8'))
        print(
            f"Handshake info --> ATM ready to go, bank replied {aes.decrypt(self.s.recv(1024).decode('utf-8'),self.aeskey)}"
        )

        # Prove to bank that we're actually an ATM
        # Tell the atm what our keys should be saved as
        self.s.send(
            aes.encrypt(f'atm{self.id_num}', self.aeskey).encode('utf-8'))

        # Receive a random number from the bank that is encrypted to our public key
        bank_challenge = aes.decrypt(
            self.s.recv(4096).decode('utf-8'), self.aeskey)

        # Decrypt the random number
        if scheme == 'rsa':
            response = rsa.decrypt(int(bank_challenge), privkey)
        else:
            bank_challenge = bank_challenge.strip('(').strip(')').split(',')
            bank_challenge = [int(c) for c in bank_challenge]
            response = elgamal.decrypt(bank_challenge, privkey)

        # Send back the hash of the random number and our encryption key to prove that we are the atm we said we are
        response = hash.sha1(response + self.aeskey)
        self.s.send(aes.encrypt(response, self.aeskey).encode('utf-8'))

        self.post_handshake()
示例#17
0
	def sendPublicDHValue(self, A, p, g):
		self.sharedSecret = 0
		self.aesKey = convert.intToByteString(hash.sha1(convert.intToByteString(self.sharedSecret)))[0:16]
		self.realDestination.sendPublicDHValue(p, p, g)
		return p
示例#18
0
	def sendPublicDHValue(self, A, p, g):
		self.privateKey = dh.generatePrivateKey(p)
		self.sharedSecret = dh.deriveSecret(A, self.privateKey, p)
		self.aesKey = convert.intToByteString(hash.sha1(convert.intToByteString(self.sharedSecret)))[0:16]
		return dh.generatePublicValue(self.privateKey, g, p)
示例#19
0
def main():

    a = input()
    print(hash.sha1(a.encode('utf-8 ')))
    """ Attempt to break hash
示例#20
0
def verify_signature(signature: int, msg: str, pub_key: tuple) -> bool:
    hashed = int(hash.sha1(msg), 16)

    return hashed == pow(signature, pub_key[1], pub_key[0])