I have a ciphertext that was encrypted using PHP which I need to decrypt using Python.
I have the below PHP code that decrypts the ciphertext perfectly.
$cryptText = "ciphertext";
$iv = "some iv"
$cipher = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CFB);
$password = "some password";
$salt = "some salt";
$cipher->setPassword($password, 'pbkdf2', 'sha512', $salt, 1000, 256 / 8);
$cipher->setIV($iv);
$plaintext = $cipher->decrypt(base64_decode($cryptText));
Now to decrypt it using Python I used 2 approaches
Using pyaes
from base64 import b64encode, b64decode
import hashlib
import pyaes
import os
ciphertext = 'ciphertext'
ciphertext = b64decode(ciphertext)
password = b'some password'
salt = b'some salt'
iv=b'some iv'
key = hashlib.pbkdf2_hmac('sha512', password, salt, 1000, 32)
aes = pyaes.AESModeOfOperationCFB(key, iv = iv)
decryptedData = aes.decrypt(ciphertext)
PyCryptodome (Crypto.Cipher.AES)
import base64
import hashlib
from Crypto import Random
from Crypto.Cipher import AES
import hashlib
ciphertext = 'ciphertext'
ciphertext = b64decode(ciphertext)
password = b'some password'
salt = b'some salt'
iv=b'some iv'
key = hashlib.pbkdf2_hmac('sha512', password, salt, 1000, 32)
cipher = AES.new(key, AES.MODE_CFB, iv)
decryptedData = cipher.decrypt(ciphertext)
The result from 1 and 2 is same but not matching the one from PHP
The PHP code uses a different segment size1) than the two Python codes: The phpseclib v1 specifies with CRYPT_RIJNDAEL_MODE_CFB the CFB mode with a segment size of 128 bits (full-block CFB), while PyCryptodome and pyaes use a segment size of 8 bits by default.
Therefore, a ciphertext that can be decrypted with the PHP code cannot be decrypted with either Python code. For this to be possible, the segment size must be explicitly set to 128 bits in the Python codes,
for PyCryptodome:
cipher = AES.new(key, AES.MODE_CFB, iv=iv, segment_size=128)
for pyaes:
cipher = pyaes.AESModeOfOperationCFB(key, iv=iv, segment_size=16)
Note that for pyaes the segment size is specified in bytes and not in bits. Furthermore, pyaes requires that the plaintext must be an integer multiple of the segment size, i.e. for full-block CFB an integer multiple of 16 bytes.
1) The segment size of the CFB mode corresponds to the bits encrypted per encryption step, see CFB.
Related
I am given this code that encrypts a string "flag".
from Crypto.Util.number import getPrime
from Crypto.Util.Padding import pad, unpad
from Crypto.Cipher import AES
import hashlib
prime = getPrime(1024)
privkey = random.randint(2, prime - 1)
key = pow(2, privkey, prime)
sk = pow(key, privkey, prime)
aes_key = hashlib.md5(str(sk).encode()).digest()
cipher = AES.new(aes_key, AES.MODE_ECB)
pt = cipher.encrypt(pad(flag, 16)).hex()
print(f"[+] This encrypted flag : {pt}")
And I am told to decrypt the encrypted string to get the original string. I am given the values for the encrypted flag and key plus the values for prime and private key (privkey) in hexadecimal. I tried to use those values to decrypt the flag like so:
flag = "8fceb2a29cc2d7abd8ecfc8da5dc1eea6f67f7a0b047749d66ef8886bb33c720dfc5dd4e508bd1e4a811c62b83f98e65"
prime = int("0xf9aecd571c9afadaceae0004000c64fceb6720f717756dab1f12b2ed7fd211a13024735efeb80a8f7982a0787d4a2eb866b18b8e7d62f2b92f6bd0d7ca52b2cd18e7b508d1af3c69eee907ab9bde2cca7f6cea613954d98a3f8e0c52761937636afb2b6776ac7f4ac02af12e72f4f4905dbeac3e4e856c8542bbda24106161d9", 16)
privkey = int("0x3e1591ea4e4eef19c99626ab1d15d442becbbd2b7d7a4150ee8f1af3f0adf9df47a53823ddfe83c6a7fa4b1b5dfa319021b26dec15c385d3869c7a7ce039b8519318563602d846ea242550bbac73dfc20a27c19b119820e45589cc6f54e9bafc50befbe222aa2738a35f5fca17ca7eec71ce24449ed21fd46b92ca11080001", 16)
key= 101752188851588702786663864886064578902654651951985866839003796634186954471878272123772894282171928731095228234190527287304860559135921159182420718259970442394992811637314757293507073993913485850566751318782466533493182193918336800513466736844109978537994535285068729297204514757610248021028835645897421370304
sk = pow(key, privkey, prime)
aes_key = hashlib.md5(str(sk).encode()).digest()
cipher = AES.new(aes_key, AES.MODE_ECB)
ct = unpad(cipher.decrypt(bytes.fromhex(flag)), 16)
print(f"[+] This decrypted flag : {ct}")
But this doesn't seem to work since I keep getting
ValueError: Padding is incorrect.
Which part am I doing incorrectly?
Edit: Description of privkey:
The problem is not the decryption code, but an incomplete key privkey.
The description of the key in the screenshot as privkey leaked together with the two trailing underscores and the information that this is a challenge from a hackathon made me suspect that the key is incomplete, needs to be supplemented by two hex digits, and the full key is to be determined.
This assumption is confirmed if a byte is added to the end of the key whose value runs in a loop from 0 to 255, and PKCS#7 padding is used as criterion for a successful decryption. If this is done, the result is the plaintext:
CDDC22{D1ffi3_H3llm4n_k3y_3xch#ng3_D0ne!}
and the privkey:
3e1591ea4e4eef19c99626ab1d15d442becbbd2b7d7a4150ee8f1af3f0adf9df47a53823ddfe83c6a7fa4b1b5dfa319021b26dec15c385d3869c7a7ce039b8519318563602d846ea242550bbac73dfc20a27c19b119820e45589cc6f54e9bafc50befbe222aa2738a35f5fca17ca7eec71ce24449ed21fd46b92ca11080001d6
i.e. 0xd6 as final byte
Full code:
from Crypto.Util.Padding import unpad
from Crypto.Cipher import AES
import hashlib
prime = int("0xf9aecd571c9afadaceae0004000c64fceb6720f717756dab1f12b2ed7fd211a13024735efeb80a8f7982a0787d4a2eb866b18b8e7d62f2b92f6bd0d7ca52b2cd18e7b508d1af3c69eee907ab9bde2cca7f6cea613954d98a3f8e0c52761937636afb2b6776ac7f4ac02af12e72f4f4905dbeac3e4e856c8542bbda24106161d9", 16)
privkey = int("0x3e1591ea4e4eef19c99626ab1d15d442becbbd2b7d7a4150ee8f1af3f0adf9df47a53823ddfe83c6a7fa4b1b5dfa319021b26dec15c385d3869c7a7ce039b8519318563602d846ea242550bbac73dfc20a27c19b119820e45589cc6f54e9bafc50befbe222aa2738a35f5fca17ca7eec71ce24449ed21fd46b92ca1108000100", 16)
key= 101752188851588702786663864886064578902654651951985866839003796634186954471878272123772894282171928731095228234190527287304860559135921159182420718259970442394992811637314757293507073993913485850566751318782466533493182193918336800513466736844109978537994535285068729297204514757610248021028835645897421370304
ct = "8fceb2a29cc2d7abd8ecfc8da5dc1eea6f67f7a0b047749d66ef8886bb33c720dfc5dd4e508bd1e4a811c62b83f98e65"
for val in range(255):
sk = pow(key, privkey, prime)
aes_key = hashlib.md5(str(sk).encode()).digest()
cipher = AES.new(aes_key, AES.MODE_ECB)
try:
ptPadded = cipher.decrypt(bytes.fromhex(ct))
pt = unpad(ptPadded, 16)
print(f"[+] This decrypted flag (padded) : {ptPadded}")
print(f"[+] This decrypted flag (unpadded) : {pt}")
print(f"[+] This decrypted flag (UTF8 decoded): {pt.decode('utf8')}")
print(f"[+] privkey (hex) : {(privkey).to_bytes(128, byteorder='big').hex()}")
except:
pass
privkey += 1
Output:
[+] This decrypted flag (padded) : b'CDDC22{D1ffi3_H3llm4n_k3y_3xch#ng3_D0ne!}\n\x06\x06\x06\x06\x06\x06'
[+] This decrypted flag (unpadded) : b'CDDC22{D1ffi3_H3llm4n_k3y_3xch#ng3_D0ne!}\n'
[+] This decrypted flag (UTF8 decoded): CDDC22{D1ffi3_H3llm4n_k3y_3xch#ng3_D0ne!}
[+] privkey (hex) : 3e1591ea4e4eef19c99626ab1d15d442becbbd2b7d7a4150ee8f1af3f0adf9df47a53823ddfe83c6a7fa4b1b5dfa319021b26dec15c385d3869c7a7ce039b8519318563602d846ea242550bbac73dfc20a27c19b119820e45589cc6f54e9bafc50befbe222aa2738a35f5fca17ca7eec71ce24449ed21fd46b92ca11080001d6
I am trying to decrypt an AES encrypted data.
I am having the key and iv with me but I think key is also encoded.
Here is the code I have used:
import binascii
from Crypto.Cipher import AES
enckey = '5f35604280b44dd1073f7ee83e346d81'
key = binascii.unhexlify(enckey)
key32 = "{: <32}".format(key).encode("utf-8")
data='692fa1deafad8ad80b98cd6f077899e9be457ac5364c3822aae9457d4912e4829d71cb
8702bd10e1d54f7a0461edba193517b353835480bd174804f586776e623473022548ff098a95
45b608282bf498a36968dd6b858ad631f6eaa79ea1a87c984f4a8da5a9d1cee1b11b32d46c0d
2a670d4e634ecc47c7105387a0a38853c91e10747170de69ebf6f0e1a99f0134ddb0af0cec2c
fc70f53c9eab7227460cf1153ef686a5dc5014bd286fb0efdec571327f5a4874bec5fd5c65f0
9f0ed10e906e4199dd8c3cb8340aca1904f486a70b02554581f0e723d22854188e933ed9fce6
0172099bc675b89eba39651bbc0658ae264213217f14ff4f0824494585d8856dfd44e4ce9505
e43762a9f1ea48f9c736603e83c3e10c5740cdf279dc3a914e19eee089160ffa91180d1b4299
38ab1b6a4272d1779f7702f760cbac3f35fc35c16fcf21c7e00183f306e7a18f71ffb3b62b91
250dca7dd627876a6cedbfe83f0f18abbbb7c7650566a7f761844243fe1271cef22b1026a3f1
d37b8e7bd7c068331897680ec101e269ce66c3f129de33d3277c2cc120feb88f77f1bb851d41
b83468128366b7ed92ae07f37675cee07355ebcdfcba90a690e3d4817cd18123a0c9de175ea6
c5049c51170ee73facd5148f6525024116991b0601598a3501e770493dab0653e146981e91d2
ea9c50fbd1e6b8bb38407655c518f30852ce43ed62d1c578e642c4fa92f00bbf102c3418ed52
ed23138c86d327bbc4718ec44440f289e3af6c096c7ad69af5d941768b0f4b2e3decfad5dcfe
6dc491ce4f2f9d86d226b87f19dfb56dc44f6d66820773e6fcfa4fcd7958da2d639037627057
99a414baf93081242c2b594981c93b892f4f28883203875a4010ace9a5eafea51ee406'
cipher_text = binascii.unhexlify(data)
# Decryption
decryption_suite = AES.new('key32', AES.MODE_CBC, 'heF9BATUfWuISyO8')
plain_text = decryption_suite.decrypt(cipher_text)
print plain_text
And this is the error I am receiving :
UnicodeDecodeError: 'ascii' codec can't decode byte 0x80 in position 4:
ordinal not in range(128)
I am unable to figure out the problem with my key and data...
And please let me know if I have to make any changes to my code.
The following code works:
from Crypto.Cipher import AES
keyAscii = '5f35604280b44dd1073f7ee83e346d81'
keyBinary = bytes(keyAscii, 'ascii')
ciphertextHex='692fa1deafad8ad80b98cd6f077899e9be457ac5364c3822aae9457d4912e4829d71cb8702bd10e1d54f7a0461edba193517b353835480bd174804f586776e623473022548ff098a9545b608282bf498a36968dd6b858ad631f6eaa79ea1a87c984f4a8da5a9d1cee1b11b32d46c0d2a670d4e634ecc47c7105387a0a38853c91e10747170de69ebf6f0e1a99f0134ddb0af0cec2cfc70f53c9eab7227460cf1153ef686a5dc5014bd286fb0efdec571327f5a4874bec5fd5c65f09f0ed10e906e4199dd8c3cb8340aca1904f486a70b02554581f0e723d22854188e933ed9fce60172099bc675b89eba39651bbc0658ae264213217f14ff4f0824494585d8856dfd44e4ce9505e43762a9f1ea48f9c736603e83c3e10c5740cdf279dc3a914e19eee089160ffa91180d1b429938ab1b6a4272d1779f7702f760cbac3f35fc35c16fcf21c7e00183f306e7a18f71ffb3b62b91250dca7dd627876a6cedbfe83f0f18abbbb7c7650566a7f761844243fe1271cef22b1026a3f1d37b8e7bd7c068331897680ec101e269ce66c3f129de33d3277c2cc120feb88f77f1bb851d41b83468128366b7ed92ae07f37675cee07355ebcdfcba90a690e3d4817cd18123a0c9de175ea6c5049c51170ee73facd5148f6525024116991b0601598a3501e770493dab0653e146981e91d2ea9c50fbd1e6b8bb38407655c518f30852ce43ed62d1c578e642c4fa92f00bbf102c3418ed52ed23138c86d327bbc4718ec44440f289e3af6c096c7ad69af5d941768b0f4b2e3decfad5dcfe6dc491ce4f2f9d86d226b87f19dfb56dc44f6d66820773e6fcfa4fcd7958da2d63903762705799a414baf93081242c2b594981c93b892f4f28883203875a4010ace9a5eafea51ee406'
ciphertextBinary = bytes.fromhex(ciphertextHex)
ivAscii = 'heF9BATUfWuISyO8'
ivBinary = bytes(ivAscii, 'ascii')
# Decryption
decrypter = AES.new(keyBinary, AES.MODE_CBC, ivBinary)
plaintextBinary = decrypter.decrypt(ciphertextBinary)
plaintext = plaintextBinary.decode('utf-8')
print(plaintext)
and outputs
connection_type=wifi&android_id=863e87fea9a09533&app_name=AstroNest&app_version=53&app_version_name=2.7.1&device_brand=motorola&device_cpu_type=armv7l&device_model=XT1562&google_aid=ab95a01a-242b-4ac2-ad12-b6189e983a56&google_ad_tracking_disabled=0&insdate=1494826343&installer=com.android.vending&language=en&mac_address=02%3A00%3A00%3A00%3A00%3A00&mat_id=45c0a743-a948-434b-a20d-fe66e870d285&os_version=6.0.1&screen_density=3.0&screen_layout_size=1920x1080&sdk_version=3.11.4&conversion_user_agent=Dalvik%2F2.1.0+%28Linux%3B+U%3B+Android+6.0.1%3B+XT1562+Build%2FMPDS24.107-70-1-5%29¤cy_code=USD&revenue=0.0&system_date=1494826532
But it's cryptographically wrong in many ways:
The key looks like 32 character hex string (which would encode a 128-bit key), but you actually need to treat it as ASCII encoding a 32-byte key. That's wrong, since keys are supposed to be uniformly distributed binary string
Similarly an IV is supposed to be a uniform binary, but it's actually ASCII
The IV is fixed, but the whole point of an IV is to be different (unpredictably random for CBC mode) for each message.
CBC mode is vulnerable to padding oracle attacks, which allow an active attacker to recover the plaintext if they can execute a chosen ciphertext attack where they learn which ciphertext decrypt successfully.
You should use authenticated encryption with unique IVs instead.
this one may help you
import binascii
from Crypto.Cipher import AES
import re
enckey = '5f35604280b44dd1073f7ee83e346d81'
key32 = "{: <32}".format(enckey).encode("utf-8")
cipher = AES.new(key32, AES.MODE_ECB)
data='692fa1deafad8ad80b98cd6f077899e9be457ac5364c3822aae9457d4912e4829d71cb8702bd10e1d54f7a0461edba193517b353835480bd174804f586776e623473022548ff098a9545b608282bf498a36968dd6b858ad631f6eaa79ea1a87c984f4a8da5a9d1cee1b11b32d46c0d2a670d4e634ecc47c7105387a0a38853c91e10747170de69ebf6f0e1a99f0134ddb0af0cec2cfc70f53c9eab7227460cf1153ef686a5dc5014bd286fb0efdec571327f5a4874bec5fd5c65f09f0ed10e906e4199dd8c3cb8340aca1904f486a70b02554581f0e723d22854188e933ed9fce60172099bc675b89eba39651bbc0658ae264213217f14ff4f0824494585d8856dfd44e4ce9505e43762a9f1ea48f9c736603e83c3e10c5740cdf279dc3a914e19eee089160ffa91180d1b429938ab1b6a4272d1779f7702f760cbac3f35fc35c16fcf21c7e00183f306e7a18f71ffb3b62b91250dca7dd627876a6cedbfe83f0f18abbbb7c7650566a7f761844243fe1271cef22b1026a3f1d37b8e7bd7c068331897680ec101e269ce66c3f129de33d3277c2cc120feb88f77f1bb851d41b83468128366b7ed92ae07f37675cee07355ebcdfcba90a690e3d4817cd18123a0c9de175ea6c5049c51170ee73facd5148f6525024116991b0601598a3501e770493dab0653e146981e91d2ea9c50fbd1e6b8bb38407655c518f30852ce43ed62d1c578e642c4fa92f00bbf102c3418ed52ed23138c86d327bbc4718ec44440f289e3af6c096c7ad69af5d941768b0f4b2e3decfad5dcfe6dc491ce4f2f9d86d226b87f19dfb56dc44f6d66820773e6fcfa4fcd7958da2d63903762705799a414baf93081242c2b594981c93b892f4f28883203875a4010ace9a5eafea51ee406'
cipher_text = binascii.unhexlify(data)
# Decryption
plain_text = re.sub('\0*$','', cipher.decrypt( data[16:]))
print plain_text
or try this
import binascii
from Crypto.Cipher import AES
enckey = '5f35604280b44dd1073f7ee83e346d81'
key32 = "{: <32}".format(enckey).encode("utf-8")
cipher = AES.new(key32, AES.MODE_ECB)
data='692fa1deafad8ad80b98cd6f077899e9be457ac5364c3822aae9457d4912e4829d71cb8702bd10e1d54f7a0461edba193517b353835480bd174804f586776e623473022548ff098a9545b608282bf498a36968dd6b858ad631f6eaa79ea1a87c984f4a8da5a9d1cee1b11b32d46c0d2a670d4e634ecc47c7105387a0a38853c91e10747170de69ebf6f0e1a99f0134ddb0af0cec2cfc70f53c9eab7227460cf1153ef686a5dc5014bd286fb0efdec571327f5a4874bec5fd5c65f09f0ed10e906e4199dd8c3cb8340aca1904f486a70b02554581f0e723d22854188e933ed9fce60172099bc675b89eba39651bbc0658ae264213217f14ff4f0824494585d8856dfd44e4ce9505e43762a9f1ea48f9c736603e83c3e10c5740cdf279dc3a914e19eee089160ffa91180d1b429938ab1b6a4272d1779f7702f760cbac3f35fc35c16fcf21c7e00183f306e7a18f71ffb3b62b91250dca7dd627876a6cedbfe83f0f18abbbb7c7650566a7f761844243fe1271cef22b1026a3f1d37b8e7bd7c068331897680ec101e269ce66c3f129de33d3277c2cc120feb88f77f1bb851d41b83468128366b7ed92ae07f37675cee07355ebcdfcba90a690e3d4817cd18123a0c9de175ea6c5049c51170ee73facd5148f6525024116991b0601598a3501e770493dab0653e146981e91d2ea9c50fbd1e6b8bb38407655c518f30852ce43ed62d1c578e642c4fa92f00bbf102c3418ed52ed23138c86d327bbc4718ec44440f289e3af6c096c7ad69af5d941768b0f4b2e3decfad5dcfe6dc491ce4f2f9d86d226b87f19dfb56dc44f6d66820773e6fcfa4fcd7958da2d63903762705799a414baf93081242c2b594981c93b892f4f28883203875a4010ace9a5eafea51ee406'
cipher_text = binascii.unhexlify(data)
# Decryption
plain_text = cipher.decrypt(cipher_text)
print plain_text
I am using pycrypto module for AES encryption. And using documentation I have write down the below function but it al;ways gives error IV must be 16 bytes long but I am using 16 byte long IV.
def aes_encrypt(plaintext):
"""
"""
key = **my key comes here**
iv = binascii.hexlify(os.urandom(16)) # even used without binascii.hexlify)
aes_mode = AES.MODE_CBC
obj = AES.new(key, aes_mode, iv)
ciphertext = obj.encrypt(plaintext)
return ciphertext
Use this:
from Crypto.Cipher import AES
import binascii,os
def aes_encrypt(plaintext):
key = "00112233445566778899aabbccddeeff"
iv = os.urandom(16)
aes_mode = AES.MODE_CBC
obj = AES.new(key, aes_mode, iv)
ciphertext = obj.encrypt(plaintext)
return ciphertext
Works as below:
>>> aes_encrypt("TestTestTestTest")
'r_\x18\xaa\xac\x9c\xdb\x18n\xc1\xa4\x98\xa6sm\xd3'
>>>
That's the difference:
>>> iv = binascii.hexlify(os.urandom(16))
>>> iv
'9eae3db51f96e53f94dff9c699e9e849'
>>> len(iv)
32
>>> iv = os.urandom(16)
>>> iv
'\x16fdw\x9c\xe54]\xc2\x12!\x95\xd7zF\t'
>>> len(iv)
16
>>>
i have two script in python , one is encrypt data using Crypto
from Crypto.Cipher import AES
from Crypto import Random
IV = 'c782dc4c098c66cb'
secrect_key = 'c286696d887c9aa0'
cipher = AES.new(secrect_key, AES.MODE_CFB, IV)
data = 'This is a 48-byte message (exactly 3 AES blocks)'
print repr(cipher.encrypt(data))
and the other using M2Crypto
import M2Crypto.EVP as EVP
import cStringIO
ENCRYPT_OP = 1
DECRYPT_OP = 0
def aes_encrypt(iv, secret_key, plain_text):
cipher = EVP.Cipher(alg='aes_128_cfb',
key=secret_key,
iv=iv,
op=ENCRYPT_OP)
input_buffer = cStringIO.StringIO(plain_text)
cipher_data1 = cipher.update(input_buffer.read())
cipher_data2 = cipher.final()
input_buffer.close()
output_buffer = cStringIO.StringIO()
output_buffer.write(cipher_data1)
output_buffer.write(cipher_data2)
cipher_text = output_buffer.getvalue()
output_buffer.close()
return cipher_text
IV = 'c782dc4c098c66cb' # 16 bytes
secrect_key = 'c286696d887c9aa0' # 16 bytes
data = 'This is a 48-byte message (exactly 3 AES blocks)'
cipher_text = aes_encrypt(IV, secrect_key, data)
print(repr(cipher_text))
i have pass the same argument to module, but i cannot get the same result, i don't know why.
and, is one of the result is vulnerability?
Consider the two codes below (based on http://pythonhosted.org//pycrypto/):
1) DES.MODE_ECB
from Crypto.Cipher import DES
from Crypto import Random
key = b'Eight888'
cipher = DES.new(key, DES.MODE_ECB)
plaintext = b'sona si latine loqueris '
msg = cipher.encrypt(plaintext)
msgback= cipher.decrypt(msg)
2) DES.MODE_OFB
from Crypto.Cipher import DES
from Crypto import Random
key = b'Eight888'
iv = Random.new().read(DES.block_size)
cipher = DES.new(key, DES.MODE_OFB, iv)
plaintext = b'sona si latine loqueris '
msg = iv + cipher.encrypt(plaintext)
msgback= cipher.decrypt(msg)
Why is that code 1) recovers the original plaintext and 2) doesn't?
You have to slice off the IV before decrypting, because it is not part of the ciphertext.
decCipher = DES.new(key, DES.MODE_OFB, msg[:DES.block_size])
msgback = decCipher.decrypt(msg[DES.block_size:])
Unlike CBC where decrypting with the IV recovers at least a part of the plaintext, OFB is a streaming mode. If the alignment between actual ciphertext and generated stream (based in IV and key) is not perfect, the original plaintext cannot be recovered.