AssertionError – Creating my own python library and I am getting an assertion error

Question:

I am coding an encryption library that allows you generate either symmetric or asymmetric key/key pair and use it within Either of these 4 classes: TextEncA, TextEncS, ImageEncA and ImageEncS. The code looks to be syntactically correct however while testing the code I am getting an error with the testing of the TextEncS class using unittest – namely an assertion error.

Here is the code for testing the TextEncS class:

class TestTextEncS(unittest.TestCase):
    def setUp(self):
        self.message = b"This is a test message"
        self.key = tienc.generate_key_s()
        self.text_enc = tienc.TextEncS(self.key)

    def test_encrypt_decrypt(self):
        ciphertext, tag = self.text_enc.encrypt(self.message)
        result = self.text_enc.decrypt(ciphertext, tag)
        self.assertEqual(self.message, result)

    def test_decrypt_failure(self):
        wrong_key = os.urandom(32)
        ciphertext, tag = self.text_enc.encrypt(self.message)
        self.assertRaises(Exception, self.text_enc.decrypt, ciphertext, tag, wrong_key)

Here is the code for the TextEncS class itself:

class TextEncS:
    """ symmetric text encryption """

    def __init__(self, key):
        self.key = key

    def encrypt(self, plaintext):
        cipher = AES.new(self.key, AES.MODE_EAX)
        ciphertext, tag = cipher.encrypt_and_digest(plaintext)
        return ciphertext, tag

    def decrypt(self, ciphertext, tag):
        cipher = AES.new(self.key, AES.MODE_EAX, tag)
        return cipher.decrypt(ciphertext)

The key for the symmetric keys are generated as follows:

def generate_key_s():
    key = os.urandom(32)
    return key

And the error as seen in the terminal is presented like this:

======================================================================
FAIL: test_encrypt_decrypt (Test_TIENC.TestTextEncS)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:Users*****DesktoptienctestsTest_TIENC.py", line 38, in test_encrypt_decrypt
    self.assertEqual(self.message, result)
AssertionError: b'This is a test message' != b'x1cx83x8cJxa7x1bx02gxfetxf1XOPx9cxa6xa8x99kxabCx01'

----------------------------------------------------------------------

How would I go about solving this issue and what should I try?

I have tried changing the code about have read up on the documentation however nothing I have tried seems to have worked.

Asked By: Vey

||

Answers:

Modifications to your class TextEncS

You have to modify your production code as below:

from Cryptodome.Cipher import AES

class TextEncS:
    """ symmetric text encryption """

    def __init__(self, key):
        self.key = key

    def encrypt(self, plaintext):
        cipher = AES.new(self.key, AES.MODE_EAX)
        ciphertext, tag = cipher.encrypt_and_digest(plaintext)
        return ciphertext, tag, cipher.nonce

    def decrypt(self, ciphertext, tag, nonce):
        cipher = AES.new(self.key, AES.MODE_EAX, nonce)
        data = cipher.decrypt_and_verify(ciphertext, tag)
        return data

The modification are:

  1. encrypt() that return 3 values (I have add chiper.nonce)
  2. decrypt() that has 3 arguments (I have add once); furthermore the body of decrypt() is a bit different from your code

In your question you have not include the import. In my code the import is:

from Cryptodome.Cipher import AES

Modifications to your test code

The test code is modified accordly (see the comments inside the code):

class TestTextEncS(unittest.TestCase):
    def setUp(self):
        self.message = b"This is a test message"
        self.key = tienc.generate_key_s()
        self.text_enc = tienc.TextEncS(self.key)
    
    def test_encrypt_decrypt(self):
        # encrypt() return ---> ciphertext, tag, nonce
        ciphertext, tag, nonce = self.text_enc.encrypt(self.message)
        # pass 3 arguments to decrypt()
        result = self.text_enc.decrypt(ciphertext, tag, nonce)
        self.assertEqual(self.message, result)

    def test_decrypt_failure(self):
        # encrypt() return ---> ciphertext, tag, nonce
        ciphertext, tag, nonce = self.text_enc.encrypt(self.message)
        wrong_key = os.urandom(32)
        # create a new instance the class TextEncS with the wrong key
        self.text_enc = tienc.TextEncS(wrong_key)
        # change a bit the test
        with self.assertRaises(Exception):
            self.text_enc.decrypt(ciphertext, tag, nonce)

Useful links

For details about Encrypt data with AES see this documentations.

To know why I have use Cryptodome instead Crypto module see this link.

Answered By: frankfalse