Your nonce is still hardcoded. Line 9.
Line 11: change this to self.level = level, so that the alteration of the level changes.
I'm not sure what your doing in generate(), with the following lines of code:
requiredlength=range(len(data), len(data)+16, 16)[-1]
Also, hashing the key does not ensure that the user can pass in arbitrary key lengths. The hash may be too large for the cipher your using, for example. SHA-256 is good but still...
AES allows keys up to 128, 192, and 256 bits, which is 16, 24, and 32 bytes. I'm not sure how hashing the key is any more secure than just passing the key as plaintext.
Also, don't delete the nonce. The nonce is a number used once. Its supposed to be public. People are supposed to know about it. The key is the one you want deleted. Even so, Python offers no safe way to zero memory, so this library still leaks data, and would even if you had patched every security vulnerability it had purely because its not written in C/C++.
Second, lines 91-98: searching for the nonce like this isn't the wisest idea since you don't know if pycryptodome has already added the nonce or not. It could, though this level most likely doesn't. You also risk getting odd data in there. Generally how I do it is I write the nonce in the file first, then append the encrypted data to the end of the nonce. So this is how it works for decryption:
* Read() call: read the first 24 bytes into memory; this is the nonce. (The encryption library I use uses a 24-byte nonce.)
* read() call: read the next 32 bytes into memory; this is the encrypted key. (This is optional but recommended if you can figure out a solution for secure storage.)
* Send the encrypted key (base-64 encoded, possibly) to a remote service for decryption and get back the plaintext.
* Initialize the cryptographic context with the retrieved nonce and key. Immediately zero-out the key.
* Begin reading the file in 'blocks', with each 'block' being 8,192 bytes in length. Decrypt each chunk and do with it what you like.
* Repeatedly read until no more data is available. Stop just before the last 16 bytes end of the file.
* Read these 16 bytes. This is your message authentication code (MAC). Verify it. Generally you do this by reading that 16-byte stream into a buffer and passing that buffer to the context finalization function.
And this is how it works for encryption:
* Set up an AWS KMS client and provide AWS credentials. (Replace this with a service you trust, I'd go with AWS since their well-known for their integrity and security.)
* Send two remote requests to AWS. Verify that each one completes. The first is called a generate data key request. The request contains the following elements:
- the Key ARN, which is in the form arn:aws:kms:region:account_id:key/key_id, where region is a region like us-east-1, us-east-1a, etc., account_id is the ID for your account, and key_id is a GUID identifying your key.
- The length of the data key, which is usually 32-bytes for AES-256.
You will get back:
- The encrypted key. Keep this around for now in secure memory.
- The plaintext copy of the key. Again, keep this around in secure memory; you'll need it soon.
The second request is called a generate random request. This will get you your nonce. This only has one required field, the number of bytes. Set this to 24. Get back your nonce, and get the plaintext from the buffer. Now is probably a good time to add run-time assertions that your plaintext key is, in fact, 32 bytes, and that your nonce is, in fact, 24 bytes.
* Set up your buffers. One is your input, one is your output, and one is your MAC.
* Set up a cryptographic context and initialize it with your nonce and key. Just as with decryption, immediately wipe the key from RAM. (The context will manage its own safe deallocation, but you need to manage yours too.)
* Open your input file and attempt to read from it. Verify that this is indeed possible.
* Write your nonce, then your encrypted key, to the output file. Don't use any deliminator.
* Then, begin reading and encrypting the file in chunks. If writing to disk, immediately write to the output buffer (which should be a file output stream) the encrypted data -- you won't be able to after the next steps.
* Verify that your not at the end of the input stream. If the stream is bad, finalize the crypto stream, clean up and terminate; this means an error occurred. Do not write the MAC!
* No matter whether your done or not, immediately zero out the input buffer so you don't keep using up RAM.
* One your done reading the input, finalize the context, write the MAC, and close the input and output streams. Then clean up AWS and all that.
You don't have to do it this way. But this is a very safe way of storing data that may be potentially sensitive.
That's all I can recommend; I think Cartertemm might have more advice. Perhaps I've gotten some details wrong, perhaps my method is incorrect. Feel free to educate me too -- just telling you how I generally do things!
"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question." — Charles Babbage.