1

We're moving away from pycryptodome to cryptography due to security considerations. When encoding the same plain-text string with pycryptodome I get a different cypher text than cryptography, consider the following code:

Pycryptodome:

 def aes_encrypt(self, plain_text): try: plain_text_with_padding = self._aes_pad(plain_text).encode("utf-8") cipher = AES.new(self.aes_secret_key, AES.MODE_CBC, self.aes_iv) msg = cipher.encrypt(plain_text_with_padding) return msg.encode("hex") except Exception as e: raise AesError(e.message) 

Cryptography:

 def aes_encrypt(self, plain_text): try: plain_text_with_padding = self._aes_pad(plain_text) encryptor = Cipher( algorithm=algorithms.AES(self.aes_secret_key), mode=modes.CBC(self.aes_iv), backend=default_backend(), ).encryptor() msg = encryptor.update(plain_text_with_padding) + encryptor.finalize() return msg.encode("hex") except Exception as e: raise AesError(e.message) @staticmethod def _aes_pad(s): padding_length = AES.block_size - (len(s) % AES.block_size) return s + padding_length * chr(padding_length) 

The test code:

 def setUp(self): secret_manager = Mock() secret_manager.get_secret.return_value = { "hmac_secret_key": "secret", "aes_secret_key": "fbc1f4bf4c826fc41d27905bc3eb8cbb", "aes_iv": "J3wmcjV0Vzd9Jw==" } self.crypto_utils = CryptoUtils(secret_manager) def test_aes_encrypt(self): asset_id = "123456" encrypted_asset_id = self.crypto_utils.aes_encrypt(asset_id) self.assertEqual( "926fbb0584c6e357157709e723b0e0d2", encrypted_asset_id ) 

The same test code pass using pycryptodome but generate much longer cipher text when using cryptography.

Any help on this matter is appreciated.

5
  • msg = encryptor.update(plain_text_with_padding) + encryptor.finalize() should be msg = encryptor.finalize(). Commented Aug 6, 2019 at 14:11
  • I can't reproduce the problem, both libs produce the expected result, using the parts of code you provided. Make sure that you use the same values for both methods, and that those values are not modified by other class methods. Commented Aug 6, 2019 at 15:08
  • @t.m.adam I'm currently working on mac os with Python 2.7.16 in virtualenv. When running the same code on a Windows machine available to me I get the expected correct results, thanks for that. However - it doesn't explain why I get incorrect results on my Mac. Additionally, when this code is executed as part of our CI/CD pipeline (CircleCI) it produces the same (incorrect) results. Commented Aug 6, 2019 at 15:46
  • That's interesting. Your code works correctly on my local machine - Windows with Python 2.7 (and Python 3.7 with some minor adjustments) and on Repl.it - Linux2 with Python 2.7 (link) So it seems the problem is specific to Cryptography on MAC. Maybe you've found a bug? Commented Aug 6, 2019 at 16:12
  • Just posted an issue in the project GitHub page github.com/pyca/cryptography/issues/4964 Commented Aug 6, 2019 at 17:07

1 Answer 1

1

The issue seemed to be the AES block size - in the previous implementation (Pycryptodome) it’s given in bytes while in the new lib (cryptography) it’s given in bits.

When running the same code with the following changes using cryptography it produces the expected results:

 @staticmethod def _aes_pad(s): block_size_bytes = AES.block_size / 8 padding_length = block_size_bytes - (len(s) % block_size_bytes) return s + padding_length * chr(padding_length) 
Sign up to request clarification or add additional context in comments.

1 Comment

Please add this as the selected answer

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.