Encrypt file with PHP OpenSSL - php

Usually, I use openssl_encrypt to encrypt simple string with AES in PHP, and it works pretty well.
Now I need to encrypt files with AES-256-CTR mode, but the only way to do this is to file_get_contents the entire content of the file and then send it to the openssl_encrypt function to encrypt the actual file data. The problem is this method is very "poor" because of the critical waste of memory.
1) Is there a way to work with chunked data with PHP OpenSSL ?
For example:
<?php
// ...
$f = fopen('large.iso','r');
while(feof($f)){
$chunk = fread($f,16);
$cipher = openssl_encrypt(...$chunk...);
// ... code ...
}
// ... more code ...
?>
2) openssl_encrypt official documentation is not published yet. Does someone could clarify the meaning of the parameters of the function for use with AES-CTR mode? Does the counter is handled automatically? Is it necessary to apply a manual XOR the data returned by the function?
Note: It is a professional project so I don't want to use phpseclib or others' "anonymous" libraries, nor do I don't want to use the command line as well.

Looks like for php it's not possible to use aes-256-ctr without temporary file.
But for next chiper types:
OPENSSL_CIPHER_RC2_40
OPENSSL_CIPHER_RC2_128
OPENSSL_CIPHER_RC2_64
OPENSSL_CIPHER_DES
OPENSSL_CIPHER_3DES
OPENSSL_CIPHER_AES_128_CBC
OPENSSL_CIPHER_AES_192_CBC
OPENSSL_CIPHER_AES_256_CBC
you can use generating key on the fly:
$res = openssl_pkey_new('chiper args here');
openssl_pkey_export($res, $private_key);
$public_key = openssl_pkey_get_details($res);
$public_key = $public_key["key"];
Then encrypt:
$crypted_text = openssl_get_privatekey($private_key,'your data');
And decrypt:
openssl_public_decrypt($crypted_text,$decrypted_text,$public_key);
So if you don't want to use files, may be switching to OPENSSL_CIPHER_AES_256_CBC will help you?

1) It should be something like this:
function strtohex($x) {
$s = '';
foreach (str_split($x) as $c){
$s.=sprintf("%02X", ord($c));
}
return($s);
}
$method = "aes-256-ctr"; //aes-256-cbc
echo "Selected method: ".$method."<br /><br />";
$textToEncrypt = "My chunk of data";
$iv = "1234567890123456";
$pass = 'some_pass';
$dec_iv = strtohex($iv);
$key = strtohex($pass);
$enc_data = openssl_encrypt($textToEncrypt, $method, $pass, true, $iv);
echo "Encrypted message (openssl): ".$enc_data."<br />";
$dec_data = openssl_decrypt($enc_data, $method, $pass, OPENSSL_RAW_DATA, $iv);
echo "Decrypted message (openssl): ".$dec_data."<br />";
For CTR $iv should be unique for each chunk or your data can be broken.
2) I know only abot difference betwen CBC and CTR:
For CBC, the IV must be random, but not unique. It also must not be known.
For CTR, the IV must be unique and not known, but does not need to be random.

Related

Sending encrypted message from php to a C++ App and decrypting then with CryptoPP

i am trying to send an encrypted message with AES-256-CRT that need to be encoded with a base16 hex cause CryptoPP HexDecoder does it in that way, but i can't decrypt the encrypted text in my C++ application how i can solve this?
PS: I am using libcurl to make the requests from c++.
Here is the code's:
PHP File:
<?php
function EncryptThis($ClearTextData)
{
$ENCRYPTION_KEY = '7D9BB722DA2DC8674E08C3D44AAE976F';
$ENCRYPTION_IV = '37C6D22FADE22B2D924598BEE2455EFC';
return openssl_encrypt($ClearTextData, "AES-256-CTR", $ENCRYPTION_KEY, OPENSSL_RAW_DATA, $ENCRYPTION_IV);
}
$code = 'test';
$encryptedBytes = EncryptThis($code);
echo($encryptedBytes);
PHP echo Output: `]$Q
This is fixed right now, and the answer is the above code. (At least for my problem). I have been trying with a CBC mode but it doens't worked so i tried CRT.
I changed the file reading method and added a decryption function just to check that encryption is working properly.
Please keep in mind that this method of reading is not good for large file encryption (it reads the complete file into memory) - in this situation you may need another solution.
This is a very basic example that does not do any vanity checks...
<?php
$ENCRYPTION_KEY = 'ThisIsNotMine';
$ENCRYPTION_ALGORITHM = 'AES-256-CBC';
function EncryptThis($ClearTextData)
{
// This function encrypts the data passed into it and returns the cipher data with the IV embedded within it.
// The initialization vector (IV) is appended to the cipher data with
// the use of two colons serve to delimited between the two.
global $ENCRYPTION_KEY;
global $ENCRYPTION_ALGORITHM;
$EncryptionKey = base64_decode($ENCRYPTION_KEY);
$InitializationVector = openssl_random_pseudo_bytes(openssl_cipher_iv_length($ENCRYPTION_ALGORITHM));
$EncryptedText = openssl_encrypt($ClearTextData, $ENCRYPTION_ALGORITHM, $EncryptionKey, 0, $InitializationVector);
return base64_encode($EncryptedText . '::' . $InitializationVector);
}
function DecryptThis($CryptedTextData)
{
// This function decrypts the data passed into it and returns the clear data
// The initialization vector (IV) is appended to the cipher data with
// the use of two colons serve to delimited between the two.
global $ENCRYPTION_KEY;
global $ENCRYPTION_ALGORITHM;
$EncryptionKey = base64_decode($ENCRYPTION_KEY);
list($EncryptedTextData, $InitializationVector) = explode('::', base64_decode($CryptedTextData), 2);
$DecryptedText = openssl_decrypt($EncryptedTextData, $ENCRYPTION_ALGORITHM, $EncryptionKey, 0, $InitializationVector);
return ($DecryptedText);
}
$path = 'file.txt';//file to send can be .exe, .dll, .txt whatever i am just trying with it.
if (file_exists($path)) {
$code = file_get_contents($path); //Get the code to be encypted.
$encryptedBytes = EncryptThis($code);
echo 'encryptedBytes:' . ($encryptedBytes) . '<br>';//send the encrypted bytes to my client.
// decryption for a simple check
$decryptedData = DecryptThis($encryptedBytes);
echo 'decryptedData:' . $decryptedData . '<br>';
}
?>

Decrypt Access token using PHP for C# Encryption

I have an API URL with specific access token which was encrypted with C#(Below Code) and I want to Decrypt it using PHP post request by passing access token to parameters. Can anyone help me out to solve this problem.
Thanks in Advance!!
C# Code for Encryption:
private String AES_encrypt(String Input)
{
var aes = new RijndaelManaged();
aes.KeySize = 256;
aes.BlockSize = 256;
aes.Padding = PaddingMode.PKCS7;
aes.Key =Convert.FromBase64String("QdZx1B0ZIcLK7DPNRK09wc/rjP4WnxtE");
aes.IV = Convert.FromBase64String("hBSE4tn6e/5c3YVKFZ54Iisi4MiDyCO0HJO+WZBeXoY=");
var encrypt = aes.CreateEncryptor(aes.Key, aes.IV);
byte[] xBuff = null;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write))
{
byte[] xXml = Encoding.UTF8.GetBytes(Input);
cs.Write(xXml, 0, xXml.Length);
}
xBuff = ms.ToArray();
}
String Output = Convert.ToBase64String(xBuff);
return Output;
}
So far I tried to decrypt it with the below code
function strippadding($string)
{
$slast = ord(substr($string, -1));
$slastc = chr($slast);
$pcheck = substr($string, -$slast);
if(preg_match("/$slastc{".$slast."}/", $string)){
$string = substr($string, 0, strlen($string)-$slast);
return $string;
} else {
return false;
}
}
function decrypt($string)
{
$key = base64_decode("DZR");
$iv = base64_decode("Shravan");
$string = base64_decode($string);
return strippadding(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $string, MCRYPT_MODE_CBC, $iv));
}
Fill out the items below:
Use this key and iv that are below.
key = QdZx1B0ZIcLK7DPNRK09wc/rjP4WnxtE
iv= hBSE4tn6e/5c3YVKFZ54Iisi4MiDyCO0HJO+WZBeXoY=
Run some text through your AES_encrypt() function and whatever comes out paste on the next line.
encrypted text = put your encrypted text here.
$xXml = openssl_decrypt(
$Output, #openssl_decrypt works with base64 encoded data
'AES-256-CBC',
base64_decode("QdZx1B0ZIcLK7DPNRK09wc/rjP4WnxtE"), #key
OPENSSL_RAW_DATA,
base64_decode("hBSE4tn6e/5c3YVKFZ54Iisi4MiDyCO0HJO+WZBeXoY=") #IV
);
Now $xXml is the binary form of the input string in UTF-8 encoded.
And make sure openssl is included in your PHP build.
You have not provided me with any encrypted text to be able to test this with.
Here is what I think you need to do:
In your C# code you need to change the block size to 128 bits:
aes.BlockSize = 128;
In your C# code your IV needs to be 128 bits or 16 bytes long. It needs to equal your selected block size.
So for now this needs to be your IV:
IV = HWeR102dxMjRHZlxTqL2aA==
Your key is set for 256 bits: So here is a 256 bit key:
Key = aZUEBKSsYRKA6CGQbwFwvIS8rUnW7YA2hVMNHnnf844=
C# has functions that will automatically generate a cryptographically strong string for you of a certain length. I suggest you find these functions and learn how to use them so you can generate your own keys and IVs.
Now for the PHP portion.
You should use the OpenSSL library instead of the Mcrypt library. Mcrypt is deprecated and is no longer supported. So here is an OpenSSL solution.
Since the block size is now 128 bits and the key size is 256 bits it will now be compatible with the openssl library's AES-256-CBC function.
$key = 'aZUEBKSsYRKA6CGQbwFwvIS8rUnW7YA2hVMNHnnf844='; //256 bit key.
$iv = 'HWeR102dxMjRHZlxTqL2aA=='; //128 bit IV length. The same as the block size that is set in the C#.
function decrypt($string, $key, $iv){
$cipherText = base64_decode($string); //We are going to use raw data.
return openssl_decrypt($cipherText, 'AES-256-CBC', base64_decode($key), OPENSSL_RAW_DATA, base64_decode($iv));
//Note that I did not specify no padding in the function. By default it is PKCS#7 which is what is set in the C# code.
}
The best I can tell this should work for you. This assumption is predicated on the fact that your AES_encrypt() is working correctly and that you have OpenSSL on your machine. Which you probably do.
Hope it helps!

Encryption with AES-128-CTR giving different results on PHP (openssl_encrypt) vs Node.js (crypto)

I have an API that requires me to encode data that I send to it through an AES-cipher.
However, the only example code I have been given is Node.js code.
I thought, how hard can it be to reimplement it in PHP as well ?
Pretty hard apparently.
Below you can see both approaches, yet you can also see different results.
Anyone an idea what might be going wrong ?
NODE.js version
var crypto = require('crypto');
var algorithm = 'aes-128-ctr';
function encrypt(text, password) {
const key = Buffer.from(password, "hex").slice(0, 16);
const ivBuffer = Buffer.alloc(16);
const cipher = crypto.createCipheriv(algorithm, key, ivBuffer);
let crypted = cipher.update(text, "utf8", 'hex');
crypted += cipher.final('hex');
console.log(crypted);
}
encrypt('test','ed8f68b144f94c30b8add43276f0fa14');
RESULT : 3522ca23
PHP version
function encrypt($text, $password) {
$iv = "0000000000000000";
$encrypted = openssl_encrypt($text, 'aes-128-ctr', $password, OPENSSL_RAW_DATA, $iv);
return bin2hex($encrypted);
}
echo encrypt('test', 'ed8f68b144f94c30b8add43276f0fa14');
RESULT: 8faa39d2
While browsing the related section (after my post) I came across this one:
C# and PHP have different AES encryption results
As mentioned by t-m-adam above as well, apparently I need to align the iv and password in both examples. In PHP my iv and password were 'regular' strings, where they should have been binary strings of the same length as the cipher’s block size. My iv should (in my case) be 16 zero bytes instead of 16x the 0 character. You can see the difference by doing an echo of the code below:
$iv = "00000000000000000000000000000000";
echo $iv;
echo strlen($iv);
$iv = pack("H*", "00000000000000000000000000000000");
echo $iv;
echo strlen($iv);
Both $iv variables are of length 16 (as requested by AES) , yet the second version is composed of 0-bytes, effectively unprintable.
Without further ado, the end result, working in PHP:
function encrypt($text, $password) {
$iv = pack("H*", "00000000000000000000000000000000");
$password = pack("H*", $password);
$encrypted = openssl_encrypt($text, 'aes-128-ctr', $inputKey, OPENSSL_RAW_DATA, $iv);
return bin2hex($encrypted);
}
echo encrypt('test', 'ed8f68b144f94c30b8add43276f0fa14');
RESULT: 3522ca23
Success !!

openssl_decrypt () function not working, returning null

i used openssl_encrypt and openssl_decrypt function but the decrypt part is not returning any value, whereas using the same key Encrypt is working fine.
here is the function which i used. the variable $decrypted always return a null .
every small help will be appreciated
function deCryption($value)
{
$methods = openssl_get_cipher_methods();
$clefSecrete = "flight";
echo '<pre>';
foreach ($methods as $method) {
//$encrypted = openssl_encrypt($texteACrypter, $method, $clefSecrete); ----this was used for encryption
$decrypted = openssl_decrypt($value, $method, $clefSecrete);
echo "value=".$decrypted;
echo $method . ' : '. $decrypted . "\n";
break;
}
echo '</pre>';
return $decrypted;
}
I had exactly the same problem, I then googled my question and ended up here, on the same question that I had asked. So I had to search elsewhere.
I found this article useful in explaining the shortcoming of the official php documentation. Another article with similar content is here.
In the end it boils down to the key/password. What the openssl_encrypt library expects is a key NOT A PASSWORD. And the size of key must be the size of cipher’s intrinsic key size. The first article says if you provide a longer key, the excess is discarded and a key shorter than expected is padded with zero, i.e. \x00 bytes. I have not tested this fact.
I have edited your code to read as below.
The idea I have used is that the size of the initial vector that a cipher expects is also the size of the key it expects. So here, I am passing a key not a password as you were doing. Simply find a way turning your password into a key.
In your code, you did not pass options and the iv (initialization vector).
The iv is a string the cipher 'mixes' with the plaintext before encryption. So what the cipher encrypts is this 'mixture'. Is this important? Yes! Without this 'mixing', a pair of identical plaintexts would result into a pair of identical ciphertexts, which can lead to an attack; if two identical plaintext-ciphertext pairs are not from the same user, these two users are using the same key! A unique iv for each plaintext therefore ensures that no two plaintexts result into identical ciphertexts. In other words, the iv is a salt.
$plaintext = 'Testing OpenSSL Functions';
$methods = openssl_get_cipher_methods();
//$clefSecrete = 'flight';
echo '<pre>';
foreach ($methods as $method) {
$ivlen = openssl_cipher_iv_length($method);
$clefSecrete = openssl_random_pseudo_bytes($ivlen);
$iv = openssl_random_pseudo_bytes($ivlen);
$encrypted = openssl_encrypt($plaintext, $method, $clefSecrete, OPENSSL_RAW_DATA, $iv);
$decrypted = openssl_decrypt($encrypted, $method, $clefSecrete, OPENSSL_RAW_DATA, $iv);
echo 'plaintext='.$plaintext. "\n";
echo 'cipher='.$method. "\n";
echo 'encrypted to: '.$encrypted. "\n";
echo 'decrypted to: '.$decrypted. "\n\n";
}
echo '</pre>';

How to decrypt using Blowfish algorithm in php?

I am supposed to write a PHP script to decrypt Blowfish encrypted data.
The data I am receiving for decryption is encrypted by another application (I have no access to it).
The data decrypts fine when am check it using a javascript script (blowfish.js).
How can I decrypt the data in php?
I have tried the mcrypt function in PHP. The code works fine if I encrypt and decrypt using the same code. If I decrypt an encrypted code (in another app) it gives junk.
No idea about what mode to set.
Can anyone suggest on the code below or any PHP BlowFish code without using mcrypt?
<?php
class Encryption
{
static $cypher = 'blowfish';
static $mode = 'cfb';
static $key = '12345678';
public function encrypt($plaintext)
{
$td = mcrypt_module_open(self::$cypher, '', self::$mode, '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, self::$key, $iv);
$crypttext = mcrypt_generic($td, $plaintext);
mcrypt_generic_deinit($td);
return $iv.$crypttext;
}
public function decrypt($crypttext)
{
$plaintext = "";
$td = mcrypt_module_open(self::$cypher, '', self::$mode, '');
$ivsize = mcrypt_enc_get_iv_size($td);
$iv = substr($crypttext, 0, $ivsize);
$crypttext = substr($crypttext, $ivsize);
if ($iv)
{
mcrypt_generic_init($td, self::$key, $iv);
$plaintext = mdecrypt_generic($td, $crypttext);
}
return $plaintext;
}
}
$encrypted_text = Encryption::encrypt('this text is unencrypted');
echo "ENCRY=".$encrypted_text;echo "<br/>";
////I am using this part(decryption) coz data already encryption
// Encrypted text from app
$encrypted_text = '29636E7ADA7081E7F5D73121C45E20D5';
// Decrypt text
$decrypted_text = Encryption::decrypt($encrypted_text);
echo "ENCRY=".$decrypted_text;echo "<br/>";
?>
The $iv you use when decrypting must be the same as the Initialization Vector used when encrypting the data. Your own functions transfer this information by prepending the IV to the ciphertext (return $iv.$crypttext;), but the other application might not do so.
You need to find out what IV the other app uses, and pass that to your own code. Since the decrypt function reads the IV from the beginning of the ciphertext you can simply prepend it.
Also, you can test a bit by encrypting the same text with your encrypt function and with the other application. If the outputs do not have the same length (your own is larger), then the app is not including the IV inside the ciphertext and you must obtain this information in another manner.
And of course the cipher mode used (CFB) must be the same between your code and the other app.
There's a nice, easy to implement solution here:
www.codewalkers.com: Encrypt and Decrypt using Blowfish
There is a PEAR Library for creating blowfish encyptions that allow you to choose weather to use MCRYPT Libs, or purely native PHP:
you may view the Library here: Crypt_Blowfish 1.1.0RC2
Select the PHP.php file will show you the source code to do this hard coded in native PHP.

Categories