kojiro
kojiro

Reputation: 77167

How can I write a unit test for encryption?

I've written some abstractions for Crypto.Cipher.AES.encrypt/decrypt, and I want to write unit tests for it. Writing a unit test for decrypt was easy enough, but is there any reasonable approach to testing that the encryption itself took place? For example, is there some way to look at a bytestring and know yes, that is a chunk of AES encrypted data? If not (maybe that gives away too much information), what are my options for testing that my encrypt function has reasonable output?

def encrypt(plaintext):
    """Return 'plaintext' AES encrypted."""
    initialization_vector = Random.new().read(AES.block_size)
    cipher = AES.new(settings.secret, AES.MODE_CFB, initialization_vector)
    return initialization_vector + cipher.encrypt(bytes(plaintext.encode('utf-8')))

def decrypt(crypt):
    """Return 'crypt' AES decrypted."""
    initialization_vector, crypt = crypt[:AES.block_size], crypt[AES.block_size:]
    cipher = AES.new(settings.secret, AES.MODE_CFB, initialization_vector)
    return cipher.decrypt(crypt)

# … this is a method of a unittest.TestCase subclass:
def test_decrypt(self):
    """Test that a message can be decrypted."""
    crypt = utils.encrypt("abcdefg")
    decrypt = utils.decrypt(crypt)
    self.assertEqual("abcdefg", decrypt)

def test_encrypt(self):
    """Test that a message can be encrypted. … if you can"""
    crypt = utils.encrypt("abcdefg")
    self.assertSomethingmumblemumble(crypt)

Upvotes: 3

Views: 7026

Answers (2)

piotrek
piotrek

Reputation: 14550

don't test the results. mock your cipher and random providers and test if they are called with correct parameters and if intermediate results are passed correctly between them

Upvotes: 0

Maarten Bodewes
Maarten Bodewes

Reputation: 94058

The whole idea of a Pseudo Random Permutation - and block ciphers are just that - is that it looks random. You could run tests for checking randomness, but I'm pretty sure that is a bit too much for a JUnit test. So I would go with the suggestion of sr2222 and simply test by decrypting.

You may be able to test the mode and the padding by decrypting using raw blocks and testing whats there. You could also test if things are equal after encryption (block encryption itself has a 1:1 relation for the plain text and ciphertext) or if the encryption is different. You could probably also test if the size of the encrypted data is correct.

However, the encryption self cannot be tested without decryption, that's kind of the idea behind it in the first place: you cannot get information about the plaintext or the key - anything that does not look random would go against these notions.

[edit] probably the best way to test encryption is to test it against official test vectors, and if these are not enough or not available, test it against (output of) known good implementations (e.g. validated ones like openssl) or reference implementations.

Upvotes: 7

Related Questions