Python des-ede-cbc equivalent - php

I currently have an encrypt and decrypt for 3DES (des-ede-cbc) in PHP as follows:
php > $key = '0000000000000000';
php > $iv = '00000000';
php > $plaintext = '1234567812345678';
php > $ciphertext = openssl_encrypt($plaintext, 'des-ede-cbc', $key, 0, $iv);
php > echo $ciphertext;
LEvEJf9CI+5VTVNeIjARNamKH+PNTx2P
php > $plaintext = openssl_decrypt($ciphertext, 'des-ede-cbc', $key, 0, $iv);
php > echo $plaintext;
1234567812345678
I need to be able to take the ciphertext and decrypt it in python. The closest I've found is pycrypto: https://gist.github.com/komuw/83ddf9b4ae8f995f15af
My attempt:
>>> key = '0000000000000000'
>>> iv = '00000000'
>>> cipher_decrypt = DES3.new(key, DES3.MODE_CBC, iv)
>>> plaintext = cipher_decrypt.decrypt('LEvEJf9CI+5VTVNeIjARNamKH+PNTx2P')
>>> plaintext
b']v\xdf\xa7\xf7\xc0()\x08\xdf\xcb`4\xa7\x10\x9e\xaf\x8c\xb6\x00+_\xb3?2\x1d\\\x08\x01\xfa\xf2\x99'
I'm not sure what it's doing differently. It's 3DES with mode CBC. I'm not exactly sure what the ede part means, but I can't seem to find anything to emulate that exact openssl mode.
Version info:
Python 3.6.5
PHP 7.1.3

The string you get from PHP is base64 encoded.
from Crypto.Cipher import DES3
from base64 import decodebytes
key = b'0000000000000000'
iv = b'00000000'
cipher_decrypt = DES3.new(key, DES3.MODE_CBC, iv)
plaintext = cipher_decrypt.decrypt(decodebytes(b'LEvEJf9CI+5VTVNeIjARNamKH+PNTx2P'))
print(plaintext.decode("utf-8"))
>>>1234567812345678

Related

Encryption in Angular Crypto-JS and Decryption in PHP & Vice Versa

I am trying to implement the encryption and decryption in angular 11 crypto-js(browser level) and PHP(server level).
Randomly Generated Key and Iv.
Used this key and iv in both angular and php for doing the encryption and decryption.
Key - 46d7093c56d9079406754989716a402d
Iv - df9fa46af13e5921
Angular CryptoJS Encryption
let msg = "Testing";
let configuration = {
keySize: 128 / 8,
iv: CryptoJS.enc.Utf8.parse(iv),
mode: CryptoJS.mode.CBC
};
let encrypted = CryptoJS.AES.encrypt(msg, key, configuration).toString(); //U2FsdGVkX1+A5bM0Y4epRBtB/A2KYdupCgZXmSSu3hQ=
Angular CryptoJS Decryption
let encrypted = "U2FsdGVkX1+A5bM0Y4epRBtB/A2KYdupCgZXmSSu3hQ=";
let configuration = {
keySize: 128 / 8,
iv: CryptoJS.enc.Utf8.parse(iv),
mode: CryptoJS.mode.CBC
};
let decrypted = CryptoJS.AES.decrypt(encrypted, key, configuration).toString(CryptoJS.enc.Utf8);
PHP Encryption for CryptoJS
$Message = "Testing";
$encrypted = openssl_encrypt($Message, 'AES-128-CBC', $Key, 0, $Iv); #CC06me/4GIHVnoxdYgGTAQ==
$encrypted = openssl_encrypt($Message, 'AES-256-CBC', $Key, 0, $Iv); #cgWrkf8HfdDJg0VybavncQ==
PHP Decryption for CryptoJS
$Key = "46d7093c56d9079406754989716a402d";
$Iv = "df9fa46af13e5921";
$Encrypted = "CC06me/4GIHVnoxdYgGTAQ==";
$encrypted = openssl_decrypt($Encrypted, 'AES-128-CBC', $Key, 0, $Iv);
$Encrypted = "cgWrkf8HfdDJg0VybavncQ==";
$encrypted = openssl_decrypt($Message, 'AES-256-CBC', $Key, 0, $Iv);
The encryption which is made by angular cryptojs is able to decrypt by angular cryptojs, but not in php. I tried multiple module to make the decryption in PHP, but I am unable to decrypt the same.
Can anyone please suggest what I am missing in this method of decryption.
Thanks in advance.

Decode encoded data in PHP 7.2

I was using "mcrypt-*" for decoding the response in previous PHP 5.6 version but now in PHP 7.2 version as it is deprecated I am using openSSL method. But it is not working properly hopefully I am missing something.
$value="###lllljG5ZOibDGtlL gcQLAtTQUnCJ/bE2glWsL1WKVPdC22c9GtGe/Npx9Uv9IYaszOAVXB4T9s7Hsss/2XpZ9oisx5M4jeV7RK2S/JrBt2E4GEcDGwuJs6NhkKV8hdOcU tmkJLxO3OJ OgVbqrT6a4v5RE7w eP zvQwZyAR5cYCKUYomou9mL/pvfLbe RrBe5ZnMQmUrD6cwUxEE/inikMvIb4K7HI fVPid N B3iPnIYQna6/v9W5A0kslBj6BBDjVXJabwmCSDVxbArm0GDNseWoQAEa4BMxYitqP6cVTxL5Kri8xbAKCW5/unnYnudkHQjNJWW7LuiwDxsBqwQv8D/R/Ff/joFW6q0 muI16/CfIoFnYAyAJWNlKCX9";
$value = urldecode($value);
$value = str_replace(" ", "+", $value);
$abc = triple_decrypt($value);
print_r($abc);
PHP 5.6 working fine
function triple_decrypt($input){
$key = "thisis87658748639testkey";
$input = base64_decode($input);
$td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_ECB, "");
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size ($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$pwd = trim(mdecrypt_generic($td, $input), "\x00..\x0F");
mcrypt_generic_end($td);
return $pwd;
}
PHP 7.2
function triple_decrypt($input){
$key = "thisis87658748639testkey";
$cipher = "des-ede3";
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$pwd = openssl_decrypt($input, $cipher, $key, $options=0, $iv);
return $pwd;
}
openssl uses PKCS7-padding and mcrypt Zero-padding [0][1][2]. To decrypt the ciphertext with openssl, openssl's padding must be disabled and mcrypt's Zero-padding bytes must be removed:
function triple_decrypt($input){
$key = "thisis87658748639testkey";
$cipher = "des-ede3";
$decrypted = openssl_decrypt($input, $cipher, $key, $options=OPENSSL_ZERO_PADDING); // Disable openssl's PKCS7-padding
$unpadded = trim($decrypted, "\x00..\x0F"); // Remove mcrypt's Zero-padding bytes
return $unpadded;
}
However, note the following with regard to a reimplementation of encryption and decryption: ECB is an insecure mode [3]. Instead, CBC or even better GCM should be used [4][5]. Instead of Triple-DES the modern and faster todays standard AES is recommended [6]. Zero-padding is unreliable, PKCS7-padding should be applied instead.
Furthermore, the mcrypt code is to some extent inconsistent:
The ECB mode doesn't use an IV (this is also the reason why openssl_cipher_iv_length returns 0 in the openssl code [7]). mcrypt_generic_init ignores the IV in case of the ECB mode [8], so it's not used in the mcrypt code and therefore not needed in the openssl code.
And if a mode would be used that requires an IV, then the following would have to be considered: The IV is always needed for encryption and decryption. Therefore, a random IV is generated (and used) during encryption and then passed on to the recipient together with the ciphertext, where it's used for decryption. Since the IV isn't secret, it's usually prefixed to the ciphertext. The generation of a random IV during decryption therefore makes no sense.
You can do using openssl()
function encryptIt($q) {
$cryptKey = 'YourProjectname'; //any string
$encryptionMethod = "AES-256-CBC";
$secretHash = "25c6c7rr35b9979b151f0205cd13b0vv"; // any hash
//To encrypt
$qEncoded = openssl_encrypt($q, $encryptionMethod, $secretHash);
return $qEncoded;
}
function decryptIt($q) {
$cryptKey = 'YourProjectname'; //any string
$encryptionMethod = "AES-256-CBC";
$secretHash = "25c6c7rr35b9979b151f0205cd13b0vv"; // any hash
//To Decrypt
$qDecoded = openssl_decrypt($q, $encryptionMethod, $secretHash);
return $qDecoded;
}
$encryptedstring = encryptIt('TEST');
echo "<br/>";
echo decryptIt($encryptedstring);

PHP openssl AES in Python

I am working on a project where PHP is used for decrypt AES-256-CBC messages
<?php
class CryptService{
private static $encryptMethod = 'AES-256-CBC';
private $key;
private $iv;
public function __construct(){
$this->key = hash('sha256', 'c7b35827805788e77e41c50df44441491098be42');
$this->iv = substr(hash('sha256', 'c09f6a9e157d253d0b2f0bcd81d338298950f246'), 0, 16);
}
public function decrypt($string){
$string = base64_decode($string);
return openssl_decrypt($string, self::$encryptMethod, $this->key, 0, $this->iv);
}
public function encrypt($string){
$output = openssl_encrypt($string, self::$encryptMethod, $this->key, 0, $this->iv);
$output = base64_encode($output);
return $output;
}
}
$a = new CryptService;
echo $a->encrypt('secret');
echo "\n";
echo $a->decrypt('S1NaeUFaUHdqc20rQWM1L2ZVMDJudz09');
echo "\n";
ouutput
>>> S1NaeUFaUHdqc20rQWM1L2ZVMDJudz09
>>> secret
Now I have to write Python 3 code for encrypting data.
I've tried use PyCrypto but without success. My code:
import base64
import hashlib
from Crypto.Cipher import AES
class AESCipher:
def __init__(self, key, iv):
self.key = hashlib.sha256(key.encode('utf-8')).digest()
self.iv = hashlib.sha256(iv.encode('utf-8')).digest()[:16]
__pad = lambda self,s: s + (AES.block_size - len(s) % AES.block_size) * chr(AES.block_size - len(s) % AES.block_size)
__unpad = lambda self,s: s[0:-ord(s[-1])]
def encrypt( self, raw ):
raw = self.__pad(raw)
cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
return base64.b64encode(cipher.encrypt(raw))
def decrypt( self, enc ):
enc = base64.b64decode(enc)
cipher = AES.new(self.key, AES.MODE_CBC, self.iv )
return self.__unpad(cipher.decrypt(enc).decode("utf-8"))
cipher = AESCipher('c7b35827805788e77e41c50df44441491098be42', 'c09f6a9e157d253d0b2f0bcd81d338298950f246')
enc_str = cipher.encrypt("secret")
print(enc_str)
output
>>> b'tnF87LsVAkzkvs+gwpCRMg=='
But I need output S1NaeUFaUHdqc20rQWM1L2ZVMDJudz09 which will PHP decrypt to secret. How to modify Python code to get expected output?
PHP's hash outputs a Hex-encoded string by default, but Python's .digest() returns bytes. You probably wanted to use .hexdigest():
def __init__(self, key, iv):
self.key = hashlib.sha256(key.encode('utf-8')).hexdigest()[:32].encode("utf-8")
self.iv = hashlib.sha256(iv.encode('utf-8')).hexdigest()[:16].encode("utf-8")
The idea of the initialization vector (IV) is to provide randomization for the encryption with the same key. If you use the same IV, an attacker may be able to deduce that you send the same message twice. This can be considered as a broken protocol.
The IV is not supposed to be secret, so you can simply send it along with the ciphertext. It is common to prepend it to the ciphertext during encryption and slice it off before decryption.

Is there any difference between Ruby 'AES-128-CBC' and PHP 'rijndael-128' encryption?

Ruby code is
require 'base64'
require 'openssl'
def ruby_dec iv, key, encrypted
decipher = OpenSSL::Cipher::AES.new(128, :CBC)
#decipher.padding = 0
decipher.decrypt
decipher.key = key
decipher.iv = iv
ciphertext = Base64.decode64 encrypted
decipher.update(ciphertext) + decipher.final
end
def ruby_enc iv, key, plaintext
enc = OpenSSL::Cipher.new 'aes-128-cbc'
enc.encrypt
enc.key = key
enc.iv = iv
Base64.encode64(enc.update(plaintext) + enc.final)
end
iv = Base64.decode64("TOB+9YNdXSbkSYIU7D/IpQ==")
key = Base64.decode64("7DxoShENB0D+8xrwOwSbi1TPQBiIaFq2yveoUkutCpM=")
plaintext = "testtesttest"
encrypted = ruby_enc iv, key, plaintext
puts "encrypted is #{encrypted}"
ruby_dec iv, key, encrypted
puts "plaintext is #{plaintext}"
then
$ ruby enc_dec.rb #the above code
encrypted is LXJmnM7t+HGKi2iI51ethA==
plaintext is testtesttest
Now PHP code is
function php_dec($iv, $key, $encrypted) {
$cipher_algorithm = 'rijndael-128';
$cipher_mode = 'cbc';
$key = base64_decode($key);
$iv = base64_decode($iv);
$ciphertext = base64_decode($enctypted);
return $ciphertext;
}
function php_enc($iv, $key, $plaintext){
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
$mcrypt_key = base64_decode($key);
$iv = base64_decode($iv);
mcrypt_generic_init($td, $mcrypt_key, $iv);
$ciphertext = mcrypt_generic($td, $plaintext);
retun base64_encode($ciphertext);
}
$iv = base64_decode("TOB+9YNdXSbkSYIU7D/IpQ==");
$key = base64_decode("7DxoShENB0D+8xrwOwSbi1TPQBiIaFq2yveoUkutCpM=");
$plaintext = "testtesttest";
$encrypted = php_enc($iv, $key, $plaintext);
echo "encrypted is ".$encrypted."\n";
php_dec($iv, $key, $encrypted);
echo "plaintext is ".$plaintext."\n";
$ruby_encrypted = base64_encode("LXJmnM7t+HGKi2iI51ethA==");
php_dec($iv, $key, $ruby_encrypted);
echo "plaintext is ".$plaintext."\n";
then I get
$ php enc_dec.php
encrypted is SUR33tXu32JjR9JAKIGL7w==
plaintext is testtesttest
plaintext is testtesttest
the ciphertext is different from the ruby one.
Now I try to decrypt ruby with cipher text made by PHP.
$ pry
[1] pry(main)> load 'enc_dec.rb'
[2] pry(main)> iv = Base64.decode64("TOB+9YNdXSbkSYIU7D/IpQ==")
=> "L\xE0~\xF5\x83]]&\xE4I\x82\x14\xEC?\xC8\xA5"
[3] pry(main)> key = Base64.decode64("7DxoShENB0D+8xrwOwSbi1TPQBiIaFq2yveoUkutCpM=")
=> "\xEC<hJ\x11\r\a#\xFE\xF3\x1A\xF0;\x04\x9B\x8BT\xCF#\x18\x88hZ\xB6\xCA\xF7\xA8RK\xAD\n\x93"
[4] pry(main)> ruby_dec iv, key, Base64.decode64("SUR33tXu32JjR9JAKIGL7w==")
OpenSSL::Cipher::CipherError: data not multiple of block length
from enc_dec.rb:12:in `final'
[5] pry(main)>
Is there any difference between Ruby 'AES-128-CBC' and PHP 'rijndael-128' encryption?
and how can i decrypt with ruby?
There is a difference between AES and Rijndael in the meaning of 128, in AES the 128 is the keysize, in Rijndael it is the blocksize.
The key you used is larger than 128 bits I believe.
See this article:
http://www.leaseweblabs.com/2014/02/aes-php-mcrypt-key-padding/

Encrypt data with python, decrypt in php

I am looking for two fitting code snippets to encode some text with python, which is to be decoded in php. I am looking for something "easy" and compatible, and I have not much encryption experience myself.
If someone could give a working example that would be great!
python encrypt
from Crypto.Cipher import AES
import base64
import os
# the block size for the cipher object; must be 16, 24, or 32 for AES
BLOCK_SIZE = 32
BLOCK_SZ = 14
# the character used for padding--with a block cipher such as AES, the value
# you encrypt must be a multiple of BLOCK_SIZE in length. This character is
# used to ensure that your value is always a multiple of BLOCK_SIZE
PADDING = '{'
# one-liner to sufficiently pad the text to be encrypted
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
# one-liners to encrypt/encode and decrypt/decode a string
# encrypt with AES, encode with base64
EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)
secret = "332SECRETabc1234"
iv = "HELLOWORLD123456"
cipher=AES.new(key=secret,mode=AES.MODE_CBC,IV=iv)
my_text_to_encode = "password"
encoded = EncodeAES(cipher, my_text_to_encode)
print 'Encrypted string:', encoded
php decrypt (note the encoded text is just copy/pasted from python print above)
<?php
$enc = "x3OZjCAL944N/awRHSrmRBy9P4VLTptbkFdEl2Ao8gk=";
$secret = "332SECRETabc1234"; // same secret as python
$iv="HELLOWORLD123456"; // same iv as python
$padding = "{"; //same padding as python
function decrypt_data($data, $iv, $key) {
$cypher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
if(is_null($iv)) {
$ivlen = mcrypt_enc_get_iv_size($cypher);
$iv = substr($data, 0, $ivlen);
$data = substr($data, $ivlen);
}
// initialize encryption handle
if (mcrypt_generic_init($cypher, $key, $iv) != -1) {
// decrypt
$decrypted = mdecrypt_generic($cypher, $data);
// clean up
mcrypt_generic_deinit($cypher);
mcrypt_module_close($cypher);
return $decrypted;
}
return false;
}
$res = decrypt_data(base64_decode($enc), $iv, $secret);
print rtrim($res,$padding);
?>
You can use python-mcrypt for python. In php you have a corresponding decrypting function to mcrypt. I hope thedocumentation in php is clear enough to show how to decrypt for mcrypt. Good luck.

Categories