This is the code that is used on the Android to encrypt a .zip file.
function encryptString($RAWDATA) {
$key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
// encrypt string, use rijndael-128 also for 256bit key, this is obvious
$td = mcrypt_module_open('rijndael-128', '', 'ecb', '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$encrypted_string = mcrypt_generic($td, strlen($RAWDATA) . '|' .
$RAWDATA);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
// base-64 encode
return base64_encode($encrypted_string);
}
This is the code for the PHP to decrypt that same .zip file once it is sent to my server.
function decryptString($ENCRYPTEDDATA) {
$key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
// base-64 decode
$encrypted_string = base64_decode($ENCRYPTEDDATA);
// decrypt string
$td = mcrypt_module_open('rijndael-256', '', 'ecb', '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$returned_string = mdecrypt_generic($td, $encrypted_string);
unset($encrypted_string);
list($length, $original_string) = explode('|', $returned_string, 2);
unset($returned_string);
$original_string = substr($original_string, 0, $length);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $original_string;
It doesn't seem to work. It will encrypt the .zip file just fine on the Android, but when I call the function in PHP
$zip_file = $path . $strFileName;
decryptString($zip_file);
it doesn't decrypt the .zip file. When I open up the .txt files within the .zip file they are still encrypted.
This is the 2nd encryption code that I have tried since my first attempt didn't work. Any help would be greatly apprecaited, or if you know of encrypt/decrypt code that works for Android to PHP.
Thanks!!
This does nothing:
$zip_file = $path . $strFileName;
decryptString($zip_file);
You need to send in the actual file contents into decryptString, not the filename. Then you need to catch the return value from the function and write it back to the file. Try something like this:
$zip_file = $path . $strFileName;
$decrypted = decryptString(file_get_contents($zip_file));
file_put_contents($zip_file, $decrypted);
Related
I have a PHP page that loops through a CSV file and encrypts the 'email' column using the following function:
function my_encrypt($data, $key)
{
// Remove the base64 encoding from our key
$encryption_key = base64_decode($key);
// Generate an initialization vector
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
// Encrypt the data using AES 256 encryption in CBC mode using our encryption key and initialization vector.
$encrypted = openssl_encrypt($data, 'aes-256-cbc', $encryption_key, 0, $iv);
// The $iv is just as important as the key for decrypting, so save it with our encrypted data using a unique separator (::)
return base64_encode($encrypted . '::' . $iv);
}
In another part of the app, I decrypt the returned value using:
function my_decrypt($data, $key)
{
// Remove the base64 encoding from our key
$encryption_key = base64_decode($key);
// To decrypt, split the encrypted data from our IV - our unique separator used was "::"
list($encrypted_data, $iv) = explode('::', base64_decode($data), 2);
return openssl_decrypt($encrypted_data, 'aes-256-cbc', $encryption_key, 0, $iv);
}
This all works smoothly for the most part, but every now and then, the decrypted value comes back with a few weird characters in it.
For example: rsmi3�6CTΣ%mecompany.com was returned instead of rsmith#somecompany.com.
I'm not sure if it's the input or the output that is bad, but I'm guessing it has something to do with the uploaded CSV file... encoding issue? What do those characters mean and under what conditions are they produced?
UPDATE
Here's the code I'm using to add the encrypted value to the CSV:
$file = fopen(get_stylesheet_directory() . "/emma_members.csv", "r"); //Open the old file for reading
$newFile = fopen(get_stylesheet_directory() . "/emma_members_new.csv", "w"); //Create a new file for writing
if (!$file) error_log('ERROR opening file');
if (!$newFile) error_log('ERROR creating file');
$columns = ['email', 'member_id', 'member_since', 'plaintext_preferred', 'bounce_count', 'status_name', 'last_modified_at', 'city', 'first_name', 'last_name', 'request-demo', 'job-function', 'title', 'country', 'current-ams', 'opt-in', 'address-2', 'unique-identifier', 'state', 'postal_code', 'web-address', 'address', 'phone-number', 'company', 'area-of-specialization', 'work-phone'];
while (($data = fgetcsv($file)) !== FALSE) {
$row = array_combine($columns, $data);
$email = "{$row['email']}";
$uid = my_encrypt($email, ENCRYPT_KEY_1);
$row['unique-identifier'] = $uid;
$ret = fputcsv($newFile, array_values($row));
}
UPDATE 2
So after much testing with thousands of emails, it seems the my_encrypt function returns some bad values, depending on the input of course. It didn't happen with EVERY email address, but even 1 is too many for my use case.
I even tried getting rid of the :: between the data and the iv, but that didn't work either (although it's possible I did it wrong).
Anyway, I ended up using the following function in its place, and all is well:
function encrypt_decrypt($action, $string) {
$output = false;
$encrypt_method = "AES-256-CBC";
$secret_key = PHRASE_1;
$secret_iv = PHRASE_2;
// hash
$key = hash('sha256', $secret_key);
// iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
$iv = substr(hash('sha256', $secret_iv), 0, 16);
if ( $action == 'encrypt' ) {
$output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
$output = base64_encode($output);
} else if( $action == 'decrypt' ) {
$output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
}
return $output;
}
I tested your encrypt and decrypt functions and they are working as expected, so the reason for the behaviour seems to be a different file encoding on your device.
Especially when reading a CSV-file sometimes a (windows) device changes the encoding and you get some curious characters like those you have shown. My recommendation is to read the files with another encoding as the default one (ISO...).
I setup a live example that "proves" the correctness on a simple string en- and decryption: https://paiza.io/projects/e/Y-1gy9Y3b-VAlXAMG4odng
The result is simple:
plaintext: rsmith#somecompany.com
ciphertext: Y0RrMWRwR1pWeGtGbFdic3dIVmFzVmp4VUFYemJGdUhzMStRSll6akIwWT06Orf+twLGopVa4083RckEw44=
decryptedtext: rsmith#somecompany.com
Here is the code:
<?php
function my_encrypt($data, $key)
{
// Remove the base64 encoding from our key
$encryption_key = base64_decode($key);
// Generate an initialization vector
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
// Encrypt the data using AES 256 encryption in CBC mode using our encryption key and initialization vector.
$encrypted = openssl_encrypt($data, 'aes-256-cbc', $encryption_key, 0, $iv);
// The $iv is just as important as the key for decrypting, so save it with our encrypted data using a unique separator (::)
return base64_encode($encrypted . '::' . $iv);
}
function my_decrypt($data, $key)
{
// Remove the base64 encoding from our key
$encryption_key = base64_decode($key);
// To decrypt, split the encrypted data from our IV - our unique separator used was "::"
list($encrypted_data, $iv) = explode('::', base64_decode($data), 2);
return openssl_decrypt($encrypted_data, 'aes-256-cbc', $encryption_key, 0, $iv);
}
$plaintext = 'rsmith#somecompany.com';
echo 'plaintext: ' . $plaintext . PHP_EOL;
$encryptionKey = base64_encode(32);
$ciphertext = my_encrypt($plaintext, $encryptionKey);
echo 'ciphertext: ' . $ciphertext . PHP_EOL;
$decryptedtext = my_decrypt($ciphertext, $encryptionKey);
echo 'decryptedtext: ' . $decryptedtext . PHP_EOL;
?>
So my goal is to demonstrate an online version of the enigma machine. I'm using PHP to do this and using mcrypt as it seems to be the only way to use the enigma algorithm without writing it out myself.
Trouble is there is no information out there currently on how to set up mcrypt's enigma.
I am also using stream as nothing else seems to work before anyone asks.
I really would be greatful for any help regarding this.
This is my current setup.
$td = mcrypt_module_open('enigma', '', 'stream', '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_DEV_RANDOM);
$ks = mcrypt_enc_get_key_size($td);
$key = substr(md5('very secret key'), 0, $ks);
mcrypt_generic_init($td, $key, $iv);
$encrypted = mcrypt_generic($td, 'This is very important data');
mcrypt_generic_deinit($td);
mcrypt_generic_init($td, $key, $iv);
$decrypted = mdecrypt_generic($td, $encrypted);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
echo trim($decrypted) . "\n";
How do I get it encrypt in the enigma way then display it in ciphertext aswell as the ordinary text?
When running you're code I'm getting this warning:
Warning: mcrypt_create_iv(): Cannot create an IV with a size of less than 1 or greater than 2147483647
The error occurs because
mcrypt_enc_get_iv_size($td)
gives an value of '0':
$ivSize = mcrypt_enc_get_iv_size($td);
echo "ivSize: " . $ivSize;
ivSize: 0
The solution is to use a blank IV:
$iv = "";
and everything works like expected:
echo trim($decrypted) . "\n";
This is very important data
I'm trying to encrypt all files being uploaded to the server, and my method of doing it works; but I've noticed DECRYPTING files over 100kb just returns null, and I'm confused why encrypting works on these files, but decrypting doesn't. Is there something wrong with my code, or is there another approach to this? There is nothing wrong with the allowed upload sizes in php.ini, the upload.php page works perfectly fine, and uploads the files to the server. The only issue is with files over 100kb. I have a feeling it has something to do with the max variable length in PHP, but I'm not sure.
// Encrypt Function
public static function mc_encrypt($encrypt, $key)
{
$encrypt = serialize($encrypt);
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_DEV_URANDOM);
$key = pack('H*', $key);
$mac = hash_hmac('sha256', $encrypt, substr(bin2hex($key), -32));
$passcrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $encrypt.$mac, MCRYPT_MODE_CBC, $iv);
$encoded = base64_encode($passcrypt).'|'.base64_encode($iv);
return $encoded;
}
// Decrypt Function
public static function mc_decrypt($decrypt, $key)
{
$decrypt = explode('|', $decrypt.'|');
$decoded = base64_decode($decrypt[0]);
$iv = base64_decode($decrypt[1]);
if(strlen($iv)!==mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC)){ return false; }
$key = pack('H*', $key);
$decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $decoded, MCRYPT_MODE_CBC, $iv));
$mac = substr($decrypted, -64);
$decrypted = substr($decrypted, 0, -64);
$calcmac = hash_hmac('sha256', $decrypted, substr(bin2hex($key), -32));
if($calcmac!==$mac){ return false; }
$decrypted = unserialize($decrypted);
return $decrypted;
}
Where it should be decrypted:
try
{
$server = $db->prepare("SELECT * FROM `servers` WHERE `ServerIP` = :ip LIMIT 1");
$server->execute([ ":ip" => $ip ]);
$server = $server->fetch();
$sftp = new SFTPConnection($server['ServerIP'], intval($server['ServerPort']));
$sftp->login($server['ServerUser'], $server['ServerPassword']);
$fileData = $sftp->receiveFile($path);
//print $fileData;
header('Content-type: text/plain');
$fileName = $file['FileName'];
header("Content-Disposition: attachment; filename=$fileName");
//print $fileData; (returns the encrypted version)
$fileData = Encryption::mc_decrypt($fileData, $file['EncryptionKey']);
print $fileData; // (returns null on larger files)
}
catch (Exception $e)
{
echo $e->getMessage() . "\n";
}
I'm not sure what the issue is, but I do know a solution. First of all, you probably want to read in the file in chucks. You don't want to store e.g. an entire movie in RAM. So what you can do is to treat the SFTP connection as stream:
According to the sample code here:
$connection = ssh2_connect('shell.example.com', 22);
ssh2_auth_password($connection, 'username', 'password');
$sftp = ssh2_sftp($connection);
$stream = fopen("ssh2.sftp://$sftp/path/to/file", 'rb');
Note that I used 'rb' to force binary mode.
So now you can read in chunks from the stream, the only thing you need to do is to encrypt/decrypt the stream. Mcrypt does actually provide this functionality using a filter implementation.
As for the HMAC, you can stream that as well. You may want to create a filter for it - I could not find one.
So now that you can stream everything, go ahead and implement it.
Security notes:
mcrypt is an old library that should not be used anymore;
use MCRYPT_RIJNDAEL_128 instead of using MCRYPT_RIJNDAEL_256 if you want to use AES (the 256 is the block size, not the key size, the key size is determined by - wait for it - the size of the provided key);
HMAC is secure, but it should be performed over the ciphertext and the IV;
this is not a full transport protocol - but that doesn't matter much if you send the file over sftp.
I am trying to encrypt/decrypt files in PHP. So far I am successful with .txt files but when it comes to .pdf and .doc or .docx my code fails, i.e. it gives absurd results. Can anyone suggest modification/alternative in my code? Thanks in advance!
Here's the encryption function
function encryptData($value)
{
$key = "Mary has one cat";
$text = $value;
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_ECB, $iv);
return $crypttext;
}
Here's the decryption function
function decryptData($value)
{
$key = "Mary has one cat";
$crypttext = $value;
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$decrypttext = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $crypttext, MCRYPT_MODE_ECB, $iv);
return trim($decrypttext);
}
I used this blog to help me encrypt/decrypt pdf files on my local machine using openssl_encrypt because mcrypt is deprecated in php7.
First, you get the file contents of the pdf:
$msg = file_get_contents('example.pdf');
Then I called the encryption function written in the blog post:
$msg_encrypted = my_encrypt($msg, $key);
Then I open the file I want to write to and write the new encrypted msg:
$file = fopen('example.pdf', 'wb');
fwrite($file, $msg_encrypted);
fclose($file);
For reference, in case that blog goes down, here are the encryption and decryption functions from the blog:
$key = 'bRuD5WYw5wd0rdHR9yLlM6wt2vteuiniQBqE70nAuhU=';
function my_encrypt($data, $key) {
// Remove the base64 encoding from our key
$encryption_key = base64_decode($key);
// Generate an initialization vector
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
// Encrypt the data using AES 256 encryption in CBC mode using our encryption key and initialization vector.
$encrypted = openssl_encrypt($data, 'aes-256-cbc', $encryption_key, 0, $iv);
// The $iv is just as important as the key for decrypting, so save it with our encrypted data using a unique separator (::)
return base64_encode($encrypted . '::' . $iv);
}
function my_decrypt($data, $key) {
// Remove the base64 encoding from our key
$encryption_key = base64_decode($key);
// To decrypt, split the encrypted data from our IV - our unique separator used was "::"
list($encrypted_data, $iv) = explode('::', base64_decode($data), 2);
return openssl_decrypt($encrypted_data, 'aes-256-cbc', $encryption_key, 0, $iv);
}
I'm having a problem when writing and parsing some DATA out of stored cookies.
Here are my crypt and decrypt functions (which I have found in another topic here).
function decrypt($crypttext){
$crypttext = base64_decode($crypttext);
$plaintext = '';
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_256, '', MCRYPT_MODE_CBC, '');
$ivsize = mcrypt_enc_get_iv_size($td);
$iv = substr($crypttext, 0, $ivsize);
$crypttext = substr($crypttext, $ivsize);
if ($iv)
{
mcrypt_generic_init($td, CRYPTKEY, $iv);
$plaintext = mdecrypt_generic($td, $crypttext);
}
return trim($plaintext);
}
function encrypt($plaintext){
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_256, '', MCRYPT_MODE_CBC, '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, CRYPTKEY, $iv);
$crypttext = mcrypt_generic($td, $plaintext);
mcrypt_generic_deinit($td);
return base64_encode($iv.$crypttext);
}
My usage is fairly simple:
//read, split if neccesarry, check if already in it, if not-> add, crypt, write
if(isset($_COOKIE['DATA'])){
$data = decrypt($_COOKIE['DATA']);
$search = explode('#',$data);
if(!in_array($lnk, $search)){
$data.= "#".$lnk; // $lnk = additional data
$err = setrawcookie("DATA", encrypt($data));
}
$err = true;
}
In most tries, it doesn't work adding a $lnk. The decryption of the cookie after I've wrote it, is wrong. undefined junk. (so something doesn't work well).
I haven't been able to find any errors in the code at all. My best guess is that the problem is caused by :
$ivsize = mcrypt_enc_get_iv_size($td);
$iv = substr($crypttext, 0, $ivsize);
Specifically, that $ciphertext is smaller than $ivsize?
Any other ideas?
// to prevent questions about it:
the data which i store, are just php uniqueID()'s separeted by '#'. so maybe in future there will be 10 IDs stored (encrypted) in the cookie...i didin't know the max size of a cookie and the factor AES blow this up, but i thought a cookie should get it.
(if there is a easier synchronus way to encrypt (this should not be high security, but mostly safe) please feel free to tell me.
Try using bin2hex instead of base64_encode(). I previously answered a similar question on SO.