{"id":293,"date":"2011-08-28T11:53:28","date_gmt":"2011-08-28T10:53:28","guid":{"rendered":"http:\/\/www.floyd.ch\/?p=293"},"modified":"2017-05-08T07:27:04","modified_gmt":"2017-05-08T06:27:04","slug":"aes-encryptiondecryption-in-python","status":"publish","type":"post","link":"https:\/\/www.floyd.ch\/?p=293","title":{"rendered":"AES encryption\/decryption in python"},"content":{"rendered":"<p>Sometimes I just need some encryption, so I wrote a script that fits some cases. The functions use the python Crypto library.<\/p>\n<p>The security of the used encryption is ok, I wrote a PBKDF2-like Key Derivation Function, that hashes the password before truncating and using it as the AES key. The encryption function does not add random padding. This means an attacker can guess how long the plaintext was. Additionally, CBC is a non-authenticated mode, therefore if somebody flips a bit in your ciphertext the decryption routine won&#8217;t notice. This usually means an attacker can flip one bit, but the remaining blocks will be corrupted. So flipping a bit in the last block is easy. Moreover 13&#8217;370 derivation rounds might be too much or not enough for you.<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\ndef AESencrypt(password, plaintext, base64=False):\r\n    import hashlib, os\r\n    from Crypto.Cipher import AES\r\n    SALT_LENGTH = 32\r\n    DERIVATION_ROUNDS=13370\r\n    BLOCK_SIZE = 16\r\n    KEY_SIZE = 32\r\n    MODE = AES.MODE_CBC\r\n    \r\n    salt = os.urandom(SALT_LENGTH)\r\n    iv = os.urandom(BLOCK_SIZE)\r\n    \r\n    paddingLength = 16 - (len(plaintext) % 16)\r\n    paddedPlaintext = plaintext+chr(paddingLength)*paddingLength\r\n    derivedKey = password\r\n    for i in range(0,DERIVATION_ROUNDS):\r\n        derivedKey = hashlib.sha256(derivedKey+salt).digest()\r\n    derivedKey = derivedKey&#x5B;:KEY_SIZE]\r\n    cipherSpec = AES.new(derivedKey, MODE, iv)\r\n    ciphertext = cipherSpec.encrypt(paddedPlaintext)\r\n    ciphertext = ciphertext + iv + salt\r\n    if base64:\r\n        import base64\r\n        return base64.b64encode(ciphertext)\r\n    else:\r\n        return ciphertext.encode(&quot;hex&quot;)\r\n\r\ndef AESdecrypt(password, ciphertext, base64=False):\r\n    import hashlib\r\n    from Crypto.Cipher import AES\r\n    SALT_LENGTH = 32\r\n    DERIVATION_ROUNDS=13370\r\n    BLOCK_SIZE = 16\r\n    KEY_SIZE = 32\r\n    MODE = AES.MODE_CBC\r\n    \r\n    if base64:\r\n        import base64\r\n        decodedCiphertext = base64.b64decode(ciphertext)\r\n    else:\r\n        decodedCiphertext = ciphertext.decode(&quot;hex&quot;)\r\n    startIv = len(decodedCiphertext)-BLOCK_SIZE-SALT_LENGTH\r\n    startSalt = len(decodedCiphertext)-SALT_LENGTH\r\n    data, iv, salt = decodedCiphertext&#x5B;:startIv], decodedCiphertext&#x5B;startIv:startSalt], decodedCiphertext&#x5B;startSalt:]\r\n    derivedKey = password\r\n    for i in range(0, DERIVATION_ROUNDS):\r\n        derivedKey = hashlib.sha256(derivedKey+salt).digest()\r\n    derivedKey = derivedKey&#x5B;:KEY_SIZE]\r\n    cipherSpec = AES.new(derivedKey, MODE, iv)\r\n    plaintextWithPadding = cipherSpec.decrypt(data)\r\n    paddingLength = ord(plaintextWithPadding&#x5B;-1])\r\n    plaintext = plaintextWithPadding&#x5B;:-paddingLength]\r\n    return plaintext\r\n    \r\na = AESencrypt(&quot;password&quot;, &quot;ABC&quot;)\r\nprint AESdecrypt(&quot;password&quot;, a)\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Sometimes I just need some encryption, so I wrote a script that fits some cases. The functions use the python Crypto library. The security of the used encryption is ok, I wrote a PBKDF2-like Key Derivation Function, that hashes the &hellip; <a href=\"https:\/\/www.floyd.ch\/?p=293\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[18,19],"tags":[25,24,20],"class_list":["post-293","post","type-post","status-publish","format-standard","hentry","category-coding","category-useful-scripts","tag-aes","tag-encryption","tag-python"],"_links":{"self":[{"href":"https:\/\/www.floyd.ch\/index.php?rest_route=\/wp\/v2\/posts\/293","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.floyd.ch\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.floyd.ch\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.floyd.ch\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.floyd.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=293"}],"version-history":[{"count":7,"href":"https:\/\/www.floyd.ch\/index.php?rest_route=\/wp\/v2\/posts\/293\/revisions"}],"predecessor-version":[{"id":979,"href":"https:\/\/www.floyd.ch\/index.php?rest_route=\/wp\/v2\/posts\/293\/revisions\/979"}],"wp:attachment":[{"href":"https:\/\/www.floyd.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=293"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.floyd.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=293"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.floyd.ch\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=293"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}