Reputation: 33
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
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