I've seen this asked a few times, but not exactly how I'm going to ask it here... Hopefully this is ok with you guys.
Basically I have this script that works fine and will print my result without a hitch:
$algorithm = MCRYPT_BLOWFISH;
$mode = MCRYPT_MODE_CFB;
$iv = mcrypt_create_iv(mcrypt_get_iv_size($algorithm, $mode), MCRYPT_DEV_URANDOM);
$key = 'Wassup';
$data = 'I am a guy';
$enc_data = rtrim(mcrypt_encrypt($algorithm,$key,$data,$mode,$iv));
$plain_text = base64_encode($enc_data);
echo $plain_text . "\n";
// OUTPUTS: 6m3D5qSrfz3w6pKuuybs
$enc_data = base64_decode($plain_text);
$decoded = mcrypt_decrypt($algorithm,$key,$enc_data,$mode,$iv);
echo $decoded;
// OUTPUTS: I am a guy
This is perfect. NOW... instead of just instantly outputting what I put in, I'm trying to store that info in my database to be decrypted later.
I can see the encrypted string fine in my table row: 6m3D5qSrfz3w6pKuuybs. So, I'm sure it's going IN just fine..
and when I query to get it out it looks just the same,
but now when I decode and decrypt I get something like: ÝÄ/$ÍñËt05883700
The table field is set up as a VARCHAR (255) utf8_general_ci. Is this where the problem is?
Are you sure you are using the same initialization vector (IV) on encryption and decryption?
Note that you need to save the IV as well and use it when you are decrypting. Also don't use rtrim() on the ciphertext.
That being said, you could use a BINARY (or VARBINARY) field to store your ciphertext (and the IV), so you don't need to base64 encode it. It will save you 33% of storage.
Related
I have the following PHP code:
require('/var/www/third_party_plugins/phpseclib/vendor/autoload.php');
use phpseclib3\Crypt\PublicKeyLoader;
use phpseclib3\Crypt\RSA;
use phpseclib3\Math\BigInteger;
use phpseclib3\Crypt\AES;
use phpseclib3\Crypt\Random;
$message = hex2bin('f5f905e8b2d8f0a72e179a169a59bc373021a75865e55c6797627bc43ddc6af0d9bd673bf94f5e8defc5af81019fd87c7d504a6aa758ba1e2f1f9858d0293b0b');
$key = hex2bin('d2ce45fd5f80c15db0a4ab26a7e27f42b507ed9469f0d63c1dbe4f89ed84c0c2');
$iv = hex2bin('db9d7e844b00282327221bb563639f96');
$cipher = new AES('cbc');
$cipher->setIV($iv);
$cipher->setKey($key);
//$cipher->disablePadding();
$Decrypted = bin2hex($cipher->decrypt($message));
print("\n" . $Decrypted . "\n");
When I run this code, I get the following result:
240dcbefc0f82fadc00ef8494488aaa81400000c2def01e79fec6c4d9a822358dd8a910cac606e8afcb607793cb442093a56b7b40b
Inside of this result, I can see the message I WANT, which is:
1400000c2def01e79fec6c4d9a822358
However, there are 16 bytes of data in the front of the message which make no sense to me, it seems like some kind of padding, but I dont want it in my result nor do I understand why it is there, because from what I understand the padding should be removed by phpseclib or openssl functions
240dcbef c0f82fad c00ef849 4488aaa8
I understand that there is a 20 byte MAC at the end, however, I notice ONE extra byte in front of the mac:
dd8a910cac606e8afcb607793cb442093a56b7b40b // THIS IS 21 BYTES, NOT 20...why?
I'm also having trouble re-encrypting the data and getting a valid response from the server, as I'm re-encrypting it with PHP, then sending the SAME data to my C# server, and it is unable to decrypt the message.
I'm using phplibsec to do some encryption operations. The library has a method to set the IV and I'm using it to generate a random initialization vector to use in encrypt operations. The problem is that I need to have the same IV to decrypt the data (I didn't know this aspect). Now after small code modification I want to prepend the generated IV to the encrypted data but I don't know how to proceed.
encrypt.php
use phpseclib\Crypt\AES;
use phpseclib\Crypt\Random;
$payload = [];
// new phpseclib AES instance
$cipher = new AES();
// set a password for the encrypt
$cipher->setPassword($password);
// IV creation
$iv = Random::string($cipher->getBlockLength() >> 3);
// this method of the library will make the forst part of my data unreadable without iv
$cipher->setIV($iv);
// encrypt data - here I want to prepend the iv to get it later on decrypt
$output = $cipher->encrypt("some data");
// push encrypted data into an array
array_push($payload, $output);
decrypt.php
use phpseclib\Crypt\AES;
use phpseclib\Crypt\Random;
$cipher = new AES();
$cipher->setPassword($password);
// here is my mistake - I'm creating a new IV but I need the same
$cipher->setIV(Random::string($cipher->getBlockLength() >> 3));
// opening the file that hold encrypted data
$payload = file_get_contents('myencrypted.file');
// I've used the : to separate each line of encrypted data with php implode()
$exploded = explode(' : ', $payload);
// iterating over the array that hold encrypted data to decrypt them then base64_encode before pass back to the client in json.
foreach( $exploded as $str ){
array_push($output, base64_encode($cipher->decrypt($str) ));
}
The decrypt operation will give me something similar (I'm encrypting images data uri)
XGG”)”>hÑÏÄr*‹base64,/9j/4AAQSkZJRgABAgAAAQABAAD…D8
I think that this part XGG”)”>hÑÏÄr*‹ of the decrypted data is the IV?
How I can prepend or append it to the encrypted data and then extrac it when the data needs to be decrypted?Can anyone help me please?
UPDATE
I've followed the suggestion of Topaco in comments and now I'm able to get back the data uri but it will have the iv attached so I need to remove it. At the moment after decrypt the data uri will have this structure:
¸ÈouFH#¬ÆÌ~k!Eâdata:image/jpeg;base64,/9j/4AAQSk
How I will remove the part before the data:image/jpeg;base64 ?
I've been toying with this for a minute and I can't seem to get this right. I've altered the collation and the varchar length multiple times, but all I'm getting are blank fields once I submit. Unencrypted, they populate the fields just fine. But the second I encrypt them - it's blank-o town.
I figured it's just using a different character encoding, but either I've totally missed the correct encoding, or it's something else.
This is basically what I'm doing as far as the encryption:
$cm = 'aes-256-cbc-hmac-sha256';
$ivlen = openssl_cipher_iv_length($cm);
$iv = openssl_random_pseudo_bytes($ivlen);
$accessToken = 'AA44FC23459DD9A9D009DABBAAABF';
// this is just to show what the iv and c_key end up looking like
$iv = ' ... �u0�du ... ';
$c_key = ' ... 8�!Ò��u0�du�2⮩e ... '; // ellipses are just a fill in
// then I go ahead and encrypt...
$SSLaccessToken = openssl_encrypt($pw, $cm, $c_key, $options=0, $iv);
But the second I try to stick it in the db, it donks on me.
So - what am I missing? It's gotta be the character set, right?
That's the only thing that makes sense to me - but how do I nail this down?
I use openssl to encrypt a text, then put this into a mysql database.
This works fine, however with long texts, the decrypted text becomes corrupted.
Personally I think this is due to the way mysql saves this text into the database, there are a lot of not alpha numeric characters in the encrypted text. But I am not sure about that.
Also I don't know which collation to use in mysql, right now I set it to *utf8_unicode_ci*, but still there is corruption of data.
A live example can be seen here: http://todolist.x10.mx
Username: example
Password: password
To view the corrupted data, click Download Backup.
Below the code, of course $encrypted is saved into the database. This code works fine without database.
<?php
$source = 'very long text';
$iv = "1234567812345678";
$pass = 'difficultpassphrase';
$method = 'aes-256-ofb';
$encrypted = openssl_encrypt ($source, $method, $pass, true, $iv);
echo $encrypted;
$decrypted = openssl_decrypt ($encrypted, $method, $pass, true, $iv);
echo $decrypted;
?>
Thank you in advance for your time and expertise.
To store encrypted content in binary form, you can't use a character type with encoding since it's very likely that the encoding "breaks" your data.
You should instead use BINARY or VARBINARY datatypes, they're made exactly for the purpose of storing binary data.
The alternative is to base64_encode the data before storing it in the character datatypes, and base64_decode the data when you've fetched it from the database. This will encode the data so that the encrypted data is possible to store in a varchar/char datatype (although it will make the data slightly longer, so beware of that)
My script uses openssl_private_decrypt() to decrypt a string encrypted with RSA in another program. Currently it writes to a file. But when I try to open it up in a text editor, it says it can't detect the encoding. If I try to echo it, nothing appears. If I output it's length, I get 256, instead of the correct 3.
I know the decryption is done right because using the cat terminal command on the output file gives the correct data.
$ cat decrypted.txt
It looks like this is a character encoding problem, a problem I hear can give a lot of pain in PHP. I even tried utf8_encode(). What might the problem be?
Here's the code:
$results = '';
openssl_private_decrypt(
base64_decode(
<<<EOS
QWlG+AZIt9GE0hw0wwcPRtUWueMLBxj3YWpa5zQBoz1ttnt7TvlxDtYWZcvaUL/qr2CJCADE2iTR
G72FhAwew2fhqlqmsxL7Nns3yegflTTMXyilVM3mPU4Cx94ylLfa+ZrqrNEepaRorNJ/js5iTq9i
avegO/kYOv4zhEsZirlk/Mj0vVv6irWo8WyZoCDC2SwfGWeSUI8F4pq4FUkRh9V/0zAUZ+3P0A7Z
SrA80dSa6U/J+poRcmE1vRLQXvM8dBtFRKmb0zfltLUBMcMhcglzAhcpemJ99OCZmUuynFRcRNkj
CkOLsO+lSHntcbmXqsKE+of78gnU3tp5hHSHIg==
EOS
),
$results,
openssl_pkey_get_private(
// load private key
),
OPENSSL_NO_PADDING
);
echo $results;
The fact that you're getting decrypted data exactly the length of a single block instead of the length of your expected data is really, really pointing towards a padding problem.
Make sure you're using the same padding flag on both sides.
I'm not familiar with openssl_private_decrypt, but it seems logical to me that you would provide base64_encode()'d data to openssl_private_encrypt().
In such case, you're mangling your data by running in the wrong order on decrypt.
Seems like you would want to decrypt the string first, then run base64_decode() on the unencrypted string.