Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ValueError: MAC check failed

I am doing a super small and simple program, where it seeks to understand this module a little more, but something very strange happens.

The code below returns:

Traceback (most recent call last):
File ".\crypto.py", line 100, in <module> init = Emisor()
File ".\crypto.py", line 15, in __init__ self.encrypt()
File ".\crypto.py", line 71, in encrypt Receptor(cipher_text,tag_mac,self.key)
File ".\crypto.py", line 84, in __init__ self.decrypt(self.cipher_text,self.tag_mac,self.key)
File ".\crypto.py", line 93, in decrypt plain_text = cipher.decrypt_and_verify(cipher_text,tag_mac)
File "C:\Users\EQUIPO\AppData\Local\Programs\Python\Python37-32\lib\site-packages\Crypto\Cipher\_mode_gcm.py", line 569, in decrypt_and_verify self.verify(received_mac_tag)
File "C:\Users\EQUIPO\AppData\Local\Programs\Python\Python37-32\lib\site-packages\Crypto\Cipher\_mode_gcm.py", line 510, in verify raise ValueError("MAC check failed")
ValueError: MAC check failed

I have already read many pdfs, documentation, videos, blogs, etc. But I can't find the solution.

PDTA: that is "nonce" and that is that of the "header", there is a method called update() and that is where I should put the header, I am a bit lost with that and the nonce.

from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes

class Transmitter():

    def __init__(self):

        self.random_password = None
        self.message_plain = True
        self.key = None

        self.password_option()
        self.text_option()
        self.encrypt()



    def password_option(self):

        while ( self.random_password == None ):

            random = input("\nDo you want to generate a random symmetric key? (y/n)\n\n>>> ").strip().lower()

            if random == "y":
                self.random_password = True
                self.random()

            elif random == "n":
                self.random_password = False
                self.random()

            else:
                pass

    def text_option(self):

        if self.message_plain:

            question = input("\nHow will you enter your message?\n\n[1] file\n\n[2] directly in the program\n\n>>> ").strip()

            if question == "1":
                path = input(r"\nEnter the file path\n\n>>> ").strip()
                name = path.split("\\")[-1]
                self.message_plain = open(name,mode = "rb")

            elif question == "2":
                self.message_plain = input("\nEnter your message\n\n>>> ").strip()
                self.message_plain = self.message_plain.encode("utf-8")


    def random(self):

        if self.random_password:
            self.key = get_random_bytes(16)

        else:
            self.key = input("\nEnter your password\n\n>>> ").strip()


    def encrypt(self):

        cipher = AES.new(self.key,AES.MODE_GCM)

        cipher.update(b"header")

        cipher_text,tag_mac = cipher.encrypt_and_digest(self.message_plain)

        Receiver(cipher_text,tag_mac,self.key)



class Receiver():

    def __init__(self,cipher_text,tag_mac,key):

        self.cipher_text = cipher_text
        self.tag_mac = tag_mac
        self.key = key

        self.decrypt(self.cipher_text,self.tag_mac,self.key)

    def decrypt(self,cipher_text,tag_mac,key):

        #try:

        # nonce = aes_cipher.nonce
        cipher = AES.new(key,AES.MODE_GCM)
        cipher.update(b"header")
        plain_text = cipher.decrypt_and_verify(cipher_text,tag_mac)

        #except ValueError:
        #   print("\nAn error has occurred.")

if __name__ == '__main__':

    init = Transmitter()
like image 649
Carlos Bello Avatar asked Oct 20 '25 12:10

Carlos Bello


1 Answers

You have forgotten to transfer the nonce. The nonce can be transferred in plain and doesn't need to be in the AAD either, as the nonce is automatically verified for AEAD ciphers such as GCM.

From the documentation:

nonce (bytes) – the value of the fixed nonce. It must be unique for the combination message/key. If not present, the library creates a random nonce (16 bytes long for AES).

So you need to retrieve and transmit the nonce if you want to use the default random generated 16 byte one.

However, as GCM is more secure and more performant for a 12 byte nonce, I'd rather generate a (secure random) 12 byte nonce yourself, and use / transmit that. The library seems to default on a random nonce of 16 bytes as that is the block size of AES. That's usually a good idea, but not for GCM.

Of course, you should not simply send the key, the secret key should be established beforehand.

like image 138
Maarten Bodewes Avatar answered Oct 23 '25 01:10

Maarten Bodewes