Dejidestroyer666 Bob
Dejidestroyer666 Bob

Reputation: 33

AES GCM returning "ValueError: MAC check failed"

I'm trying to make a password manager and I am using a KDF to make the key and then use AES GCM to encrypt each row in the database. Each row has a different salt used in the key. I have followed the documentation on pycryptodome to encrypt and decrypt data using the example code, and everything works fine, except for the MAC check.

I have checked multiple times and everything is exactly the same between encryption and decryption, the nonce, salt, tag, ciphertext etc.

How can I fix this? (the code is below)

class Crypto(PasswordDatabase):
    def __init__(self):
        PasswordDatabase.__init__(self)
        self.db = None

    def encrypt_db(self):
        self.db = self.get_database()
        master_password = b'password'

        with open("passwords.txt", "w") as file:
            for i in range(len(self.db)):

                current_tuple = list(self.db[i])
                del current_tuple[0]
                current_tuple = tuple(current_tuple)
                plaintext = ",".join(current_tuple)

                salt = get_random_bytes(16)
                key = PBKDF2(master_password, salt, 16, count=1000000, hmac_hash_module=SHA512)
                file.write(f"salt={salt},")

                header = b"header"
                cipher = AES.new(key, AES.MODE_GCM)
                cipher.update(header)
                ciphertext, tag = cipher.encrypt_and_digest(plaintext.encode())

                json_k = [ 'nonce', 'header', 'ciphertext', 'tag' ]
                json_v = [b64encode(x).decode('utf-8') for x in (cipher.nonce, header, ciphertext, tag)]
                result = json.dumps(dict(zip(json_k, json_v)))

                print(result, "\n")
                file.write(result + "\n")

    def decrypt_db(self):
        with open("passwords.txt", "r") as file:
            master_password = b"password"

            for line in file:
                stripped_line = line.strip()
                ssalt = re.findall("salt=(b'.*'),", str(stripped_line))
                salt = ssalt[0]

                key = PBKDF2(master_password, salt, 16, count=1000000, hmac_hash_module=SHA512)

                json_input = re.findall("salt=b'.*',({.*})", str(stripped_line))
                b64 = json.loads(json_input[0])
                json_k = [ 'nonce', 'header', 'ciphertext', 'tag' ]
                jv = {k:b64decode(b64[k]) for k in json_k}

                cipher = AES.new(key, AES.MODE_GCM, nonce=jv['nonce'])
                cipher.update(jv['header'])
                plaintext = cipher.decrypt_and_verify(jv['ciphertext'], jv['tag'])
                print(plaintext)


if __name__ == "__main__":
    crypto = Crypto()
    crypto.encrypt_db()
    crypto.decrypt_db()

Upvotes: 1

Views: 1525

Answers (1)

Dejidestroyer666 Bob
Dejidestroyer666 Bob

Reputation: 33

The file reader was randomly adding extra \s to the salt, so I encoded the salt with base64 before it was written to the file, and then decoded it after it was read from the file to decrypt. The MAC check now doesn't fail.

Upvotes: 2

Related Questions