encrypt aes-256-ctr on Python and decrypt on PHP - python

I try to encrypt data, for example, "qwerty" on Python
encryption_key = Random.new().read(32)
bs = AES.block_size
iv = Random.new().read(AES.block_size)
# Convert the IV to a Python integer.
iv_int = int(binascii.hexlify(iv), 16)
countf = Counter.new(AES.block_size*8, initial_value=iv_int)
cipher = AES.new(encryption_key, AES.MODE_CTR, counter=countf)
encrypted = cipher.encrypt(data)
return b64encode(iv), b64encode(encryption_key), b64encode(encrypted)
and try to decrypt on PHP:
$result = openssl_decrypt(base64_decode($data['text']), "aes-256-ctr", base64_decode($data['key']), 0, base64_decode($data['iv']));
and it didn't work... in $result empty string.
encryption is clearly not my talent :(
I need to make changes in python so that php can decode in this way.

Related

How to successfully pass an IV from Python to Java (Encryption)?

I'm trying to figure out the best way to encrypt and decrypt some JSON data that I'm passing from my client (Python) to server (Java). I keep running into a few errors. Originally I had a set IV that I had hardcoded into both client and server and it was working great, it would encrypt and decrypt as I needed. However, that's obviously a bad idea, I set a random IV that I would then slice with my server and that sorta worked. It would decrpyt most of the data, except for the first 50 bytes or so. They would just be random chars (�6OC�Ղ�{�9��aJ, "number": 1243.2,...etc) and I couldn't parse the JSON.
Then when I try to slice OFF the IV (16 chars) from the decoded bytes I get an error saying that the data needs to be in multiples of 16, but I'm not sure why that isn't working.
Any ideas on how to get this working? Thanks!
Python Client
jsonString = json.dumps(data.__dict__, default=str)
key = 'sixteenssixteens'
text = jsonString
plaintext = self.pad(text)
iv = os.urandom(16)
cipher = AES.new(key, AES.MODE_CBC, iv)
encrpyt_btye = cipher.encrypt(plaintext)
encrpyt_text = base64.urlsafe_b64encode(encrpyt_btye).decode("UTF-8")
requests.post('server', data=encrpy_text)
def pad(self, text):
numberBytestoPad = block_size - len(text) % block_size
ascii_string = chr(numberBytestoPad)
padding_str = numberBytestoPad * ascii_string
padded_text = text + padding_str
return padded_text
Java Server
requestBody = exchange.getRequestBody();
String requestData = readString(requestBody);
System.out.println(requestData);
String key = "sixteenssixteens";
String initVector = requestData.substring(0, 16);
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
try {
//Tried to remove the IV from the start of the string
// String removeIV = requestData.substring(16);
Cipher cipherd = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipherd.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipherd.doFinal(Base64.getUrlDecoder().decode(requestData));
String decryptedResult = new String(original);
System.out.println("Decrypted string: " + decryptedResult);
try {
data = gson.fromJson(decryptedResult, Data.class);
} catch (Exception ex){
ex.printStackTrace();
return;
}

Data Encryption static encrypt

My hexidigit is changing on day by day basis. How can I change it back to static
Code
from Crypto.Cipher import AES
import pandas as pd
import mysql.connector
myconn = mysql.connector.connect(host="######", user="##", password="######", database="#######")
query = """SELECT * from table """
df = pd.read_sql(query, myconn) #getting hexidigit back from the SQL server after dumping the ecrypted data into the database
def resize_length(string):
#resizes the String to a size divisible by 16 (needed for this Cipher)
return string.rjust((len(string) // 16 + 1) * 16)
def encrypt(url, cipher):
# Converts the string to bytes and encodes them with your Cipher
cipherstring = cipher.encrypt(resize_length(url).encode())
cipherstring = "".join("{:02x}".format(c) for c in cipherstring)
return cipherstring
def decrypt(text, cipher):
# Converts the string to bytes and decodes them with your Cipher
text = bytes.fromhex(text)
original_url = cipher.decrypt(text).decode().lstrip()
return original_url
# It is important to use 2 ciphers with the same information, else the system breaks
# Define the Cipher with your data (Encryption Key and IV)
cipher1 = AES.new('This is a key123', AES.MODE_CBC, 'This is an IV456')
cipher2 = AES.new('This is a key123', AES.MODE_CBC, 'This is an IV456')
message = df['values'][4]
eypt = encrypt(message, cipher1)
print(decrypt(eypt, cipher2))
I'm able to decrypt the string after calling from database but on the next day the encrypted string changes which fails my code. How can I freeze this? Keeping a constant string everyday?
I got the solution by encrypting the key using bytes()
Use the byte method to store the key in secured config file or database and encrypt the byte string to get the key. After that use any cipher method with suitable algorithm to encrypt the data and mask it.

Decrypt a ciphertext with Python that was encrypted using PHP

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.

How to write the equivalent Python encryption/decryption functions as the C# ones so that Python/C# could decrypt each other encrypted string?

Have two programs, one is developed in C#.NET, having the below C# encryption/decryption functions:
public static string Encrypt(string plainText, string keyString)
{
byte[] cipherData;
Aes aes = Aes.Create();
aes.Key = Encoding.UTF8.GetBytes(keyString);
aes.GenerateIV();
aes.Mode = CipherMode.CBC;
ICryptoTransform cipher = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, cipher, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(plainText);
}
}
cipherData = ms.ToArray();
}
byte[] combinedData = new byte[aes.IV.Length + cipherData.Length];
Array.Copy(aes.IV, 0, combinedData, 0, aes.IV.Length);
Array.Copy(cipherData, 0, combinedData, aes.IV.Length, cipherData.Length);
return Convert.ToBase64String(combinedData);
}
public static string Decrypt(string combinedString, string keyString)
{
string plainText;
byte[] combinedData = Convert.FromBase64String(combinedString);
Aes aes = Aes.Create();
aes.Key = Encoding.UTF8.GetBytes(keyString);
byte[] iv = new byte[aes.BlockSize / 8];
byte[] cipherText = new byte[combinedData.Length - iv.Length];
Array.Copy(combinedData, iv, iv.Length);
Array.Copy(combinedData, iv.Length, cipherText, 0, cipherText.Length);
aes.IV = iv;
aes.Mode = CipherMode.CBC;
ICryptoTransform decipher = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream ms = new MemoryStream(cipherText))
{
using (CryptoStream cs = new CryptoStream(ms, decipher, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
{
plainText = sr.ReadToEnd();
}
}
return plainText;
}
}
Another program is using Python, need to decrypt the encrypted string from the C# program.
What are the Python encryption/decryption functions so that Python's decryption function could decrypt the encrypted string by the above C# encryption function, also C#'s decryption function could decrypt the encrypted string by Python's encryption function?
The below are the Python functions worked for me:
import Crypto.Random
from Crypto.Cipher import AES
import base64
from Crypto.Util.Padding import unpad, pad
def encrypt(plain_text, key_string):
raw = pad(plain_text.encode(), AES.block_size)
iv = Crypto.Random.get_random_bytes(AES.block_size)
cipher = AES.new(key_string, AES.MODE_CBC, iv)
return base64.b64encode(iv + cipher.encrypt(raw))
def decrypt(combined_string, key_string):
enc = base64.b64decode(combined_string)
iv = enc[:AES.block_size]
cipher = AES.new(key_string, AES.MODE_CBC, iv)
msg = unpad(cipher.decrypt(enc[AES.block_size:]), AES.block_size)
return msg.decode()

AES Decryption using Pycrypto(python) not working. Getting correct decrypted code in crypto(Nodejs).

In node i am using the following code to get proper decrypted message:
//npm install --save-dev crypto-js
var CryptoJS = require("crypto-js");
var esp8266_msg = 'IqszviDrXw5juapvVrQ2Eh/H3TqBsPkSOYY25hOQzJck+ZWIg2QsgBqYQv6lWHcdOclvVLOSOouk3PmGfIXv//cURM8UBJkKF83fPawwuxg=';
var esp8266_iv = 'Cqkbb7OxPGoXhk70DjGYjw==';
// The AES encryption/decryption key to be used.
var AESKey = '2B7E151628AED2A6ABF7158809CF4F3C';
var plain_iv = new Buffer( esp8266_iv , 'base64').toString('hex');
var iv = CryptoJS.enc.Hex.parse( plain_iv );
var key= CryptoJS.enc.Hex.parse( AESKey );
console.log("Let's ");
// Decrypt
var bytes = CryptoJS.AES.decrypt( esp8266_msg, key , { iv: iv} );
var plaintext = bytes.toString(CryptoJS.enc.Base64);
var decoded_b64msg = new Buffer(plaintext , 'base64').toString('ascii');
var decoded_msg = new Buffer( decoded_b64msg , 'base64').toString('ascii');
console.log("Decryptedage: ", decoded_msg);
But when i try to decrypt it in python i am not getting the proper decoded message.
esp8266_msg = 'IqszviDrXw5juapvVrQ2Eh/H3TqBsPkSOYY25hOQzJck+ZWIg2QsgBqYQv6lWHcdOclvVLOSOouk3PmGfIXv//cURM8UBJkKF83fPawwuxg='
esp8266_iv = 'Cqkbb7OxPGoXhk70DjGYjw=='
key = '2B7E151628AED2A6ABF7158809CF4F3C'
iv = base64.b64decode(esp8266_iv)
message = base64.b64decode(esp8266_msg)
dec = AES.new(key=key, mode=AES.MODE_CBC, IV=iv)
value = dec.decrypt(message)
print(value)
I am getting the decoded message:
"ルᄊ+#ÊZûᆪᄃn*ÿÒá×G1ᄄᄋì;$-#f゚ãᄚk-ìØܳã-トȒ~ヌ8ヘヘ_ᄂ ン?ᄂÑ:ÇäYムü'hユô<`
So i hope someone can show how it is done in python.
You forgot to decode the key from Hex and remove the padding.
Full code:
from Crypto.Cipher import AES
import base64
unpad = lambda s : s[:-ord(s[len(s)-1:])]
esp8266_msg = 'IqszviDrXw5juapvVrQ2Eh/H3TqBsPkSOYY25hOQzJck+ZWIg2QsgBqYQv6lWHcdOclvVLOSOouk3PmGfIXv//cURM8UBJkKF83fPawwuxg='
esp8266_iv = 'Cqkbb7OxPGoXhk70DjGYjw=='
key = '2B7E151628AED2A6ABF7158809CF4F3C'
iv = base64.b64decode(esp8266_iv)
message = base64.b64decode(esp8266_msg)
key = key.decode("hex")
dec = AES.new(key=key, mode=AES.MODE_CBC, IV=iv)
value = unpad(dec.decrypt(message))
print(value)
if len(value) % 4 is not 0:
value += (4 - len(value) % 4) * "="
value = base64.b64decode(value)
print(value)
Output:
eyJkYXRhIjp7InZhbHVlIjozMDB9LCAiU0VRTiI6NzAwICwgIm1zZyI6IklUIFdPUktTISEiIH0
'{"data":{"value":300}, "SEQN":700 , "msg":"IT WORKS!!" }'
Security considerations
The IV must be unpredictable (read: random). Don't use a static IV, because that makes the cipher deterministic and therefore not semantically secure. An attacker who observes ciphertexts can determine when the same message prefix was sent before. The IV is not secret, so you can send it along with the ciphertext. Usually, it is simply prepended to the ciphertext and sliced off before decryption.
It is better to authenticate your ciphertexts so that attacks like a padding oracle attack are not possible. This can be done with authenticated modes like GCM or EAX, or with an encrypt-then-MAC scheme.

Categories

Resources