Encrypt a string in PHP where the output is URL safe - php

I have a requirement where I need to move a string from one place to another via GET. e.g.
example.com?string=ENCRYPTED_STRING
Is there a algorithm or some other method to encrypt the string so it is URL safe?
By that I mean it will not have characters like = or & ...
I have tried openssl with AES-256-CBC but no luck.
The data is not overly very sensitive but I would prefer to obfuscate it in someway.

Oh hey, I've actually done this in one of my applications. My code looks a lot different (because of my custom tools, it's a one-liner), but works basically like this (uses defuse/php-encryption):
use \Defuse\Crypto\Crypto;
$url = "/my/endpoint?".http_build_query([
'something' => base64_encode(
Crypto::encrypt('my_secret_info', CRYPTO_SECRET_KEY)
)
]);
// Then you can either use $url in header('Location: '.$url) or in an HTML link safely.
Further reading:
base64_encode()
http_build_query()
urlencode() (if you don't want to use http_build_query())
Why you want authenticated encryption (which defuse/php-encryption provides) rather than just encryption (which OpenSSL's AES-CBC provides)
Footnote: If you (or anyone else) want a short encrypted URL parameter, read this answer instead. (I know what's not what you were asking for, but just in case someone finds this question years down the line...)

The code below allow you to encrypt (alpha/num) and decrypt a string. But you need Mcrypt php module installed to make it run.
static public function encrypt($text){
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "useasuperkey";
return (bin2hex(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB, $iv)));
}
static public function decrypt($text){
$len = strlen($text);
$text = pack("H" . $len, $text);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "useasuperkey";
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB, $iv));
}

I had to do exactly same thing.
My solution was encrypting string with openssl_encrypt($str, "AES-128-CBC", $key).
Then sending the URL using url_encode($str).
Destination page decodes data with openssl_decrypt($str, "AES-128-CBC", $key)

Related

PHP Encrypt and Decrypt Parameter URL in URL

I'm trying to pass a download URL from page 1 to page 2 in a GET request.
Page 1 gets the raw URL through the database, then encrypts the URL and makes it available on the site. When it's passed through the URL, page 2 decrypts the URL and downloads the file.
The URL looks like this currently:
https://example.com/download.php?dl=x6%1A%D8j%C4%D2%9Cx%8FA%8B%29%23Y%D9%D6%B4%DE8%18%2C%7B%F4%86l%B0%0A+%D3%B1%01I%CFo%FF%BA%9C%22%A1%08%11%DB%12%282%DEi%B5%CA%14K%FF%21%CB%F3%9D%3C9f%3C%09%FA9%BB%BD%C9%B2%275%F0%06%A2%80%08h%A7f%8C%87%28%A4%A5%99%A9%A9%FA%D6f%C5%CA%9B%81.%92%CD%89%FA3%5C%0C%F0%ED%F6%D9%1E%B9%D0%B1%CFSA%F4%95k%1EZ%D1%3A%D4H%1D%93%40%087%92%88%C3%A5p%C7WH%FA%CF%9D%BAKd%A0%9A%D7a6%80%5Ex%A5%87%07AK%D7%5BQ%10%98%07%7E%82%9A%BA9%25%D5%EA%03%FD%C2%9A%22%8FBW%94k%D8T%93%F5%E3%D7-
It contains a lot of %%% because it's urlencoded, is there a way to change this to make the URL less long and make it look less messy, but keep it safe as it is now?
Hope someone can help me out.
This is the encryption and decryption script:
define("ENCRYPTION_KEY", "ducksandpizza");
function encrypt($pure_string, $encryption_key) {
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
return urlencode($encrypted_string);
}
function decrypt($encrypted_string, $encryption_key) {
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$decrypted_string = urldecode($encrypted_string);
$decrypted_string = mcrypt_decrypt(MCRYPT_BLOWFISH, $encryption_key, $encrypted_string, MCRYPT_MODE_ECB, $iv);
return $decrypted_string;
}
//$encrypted = encrypt($_GET['dl'], ENCRYPTION_KEY);
$decrypted = decrypt($_GET['dl'], ENCRYPTION_KEY);
//echo 'encrypted: ' . $encrypted . '<br>';
echo 'decrypted: ' . $decrypted . '<br>';
Use some type of compression on the unencrypted data, like gzcompress() and then pass that to your encryption method, and the output of that to base64_encode. Base64 encoding will still increase the overall size, but not as much as url encode does.
While using base64_encode() isn't necessarily a bad idea, no one has mentioned that stock base64 encoding is not URL-safe as it uses the characters significant in URL syntax.
However, there's a variant that is safe that's used for encoding JWT tokens:
function base64url_encode($bin) {
return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($bin));
}
function base64url_decode($str) {
return base64_decode(str_replace(['-', '_'], ['+', '/'], $str));
}
You should also bear in mind the GET requests are subject to length restrictions which vary between HTTP server implementations and languages. You'll probably want to use something like gzcompress() as suggested in the comments, but more likely you should be passing this data in a POST instead.

encrypt and decrypt with diacrits

I have these code for encrypt and decrypt.
It works good for text (for example: "This is a text"), which is withnout diacritics (that means without : ěščřžýáíéúů).
But I need encrypt and decrypt text with this special letters (with : ěščřžýáíéúů).
Can somebody help me, please?
Thank so much for every answer and help.
Have a nice day. M.
define ("ENCRYPTION_KEY", "QaY7e4d1c");
$string= "This is a text"; // -> this work alright
//$string= "áýžřčšě"; I NEED THIS TEXT ENCRYPT AND DECRTYPT
echo $encrypted = encrypt($string, ENCRYPTION_KEY);
echo "<br />";
echo $decrypted = decrypt($encrypted, ENCRYPTION_KEY);
function encrypt ($pure_string,$encryption_key)
{
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH,MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size,MCRYPT_RAND);
$encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH,$encryption_key,utf8_encode($pure_string),MCRYPT_MODE_ECB,$iv);
return $encrypted_string;
}
function decrypt ($encrypted_string,$encryption_key)
{
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH,MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size,MCRYPT_RAND);
$decrypted_string = mcrypt_decrypt(MCRYPT_BLOWFISH,$encryption_key,$encrypted_string,MCRYPT_MODE_ECB ,$iv);
return $decrypted_string;
}
You're calling utf8_encode in your encryption function, but not calling utf8_decode when you decrypt, so your functions as they stand don't complement each other.
I'd recommend removing the call to utf8_encode entirely. mcrypt_encrypt doesn't care what encoding your string uses, so whatever you pass in will be what you get back out. Your script works fine for me if I remove it:
$encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, $pure_string, MCRYPT_MODE_ECB, $iv);
I'd also suggest reading this: https://paragonie.com/blog/2015/05/if-you-re-typing-word-mcrypt-into-your-code-you-re-doing-it-wrong

mcrypt_encrypt garbled text

First, excuse the question, it might be a simple problem, but I have troubles understanding the encryption methods..
I'm using the following functions to encrypt / decrypt:
private function encodemc($value,$skey){
if(!$value){return false;}
$skey = substr($skey, 2, 4);
$text = $value;
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $skey, $text, MCRYPT_MODE_ECB, $iv);
return trim($this->safe_encode($crypttext)); // safe_encode adds another encoding using `base64_encode`
}
private function decodemc($value,$skey){
if(!$value){return false;}
$skey = substr($skey, 2, 4);
$crypttext = $this->safe_decode($value);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$decrypttext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $skey, $crypttext, MCRYPT_MODE_ECB, $iv);
return trim($decrypttext);
}
The $key looks like this: 570c45546dwq45gjk191.
I pass the value to be encrypted to the first function, then I save it to the db, and then I retrieve it from the db, I decrypt it and show it as html text.
The problem is that some text does not get decrypted/encrypted right, and it displays in the html page as if it was in the wrong text encoding.
The weird part is that out of 10 items, only 2 or 3 are garbled, depending on the key.
In addition, sometimes only a portion of the string is garbled.
I've found out that what causes the garbling are some random letters. For instance, when using the above key the letter S breaks the code and the text gets garbled.
So then I've applied substr($skey, 2, 4); to the key to see if anything changed. Turns out that if I change the key the characters that break the code are different.
But even with a key of lenght == 1 the problem persists.
Any idea on what's the problem?
EDIT:
Here the rest of the code.
private function safe_encode($string) {
$data = base64_encode($string);
$data = str_replace(array('+','/','='),array('-','_',''),$data);
return $data;
}
private function safe_decode($string) {
$data = str_replace(array('-','_'),array('+','/'),$string);
$mod4 = strlen($data) % 4;
if ($mod4) {
$data .= substr('====', $mod4);
}
return stripslashes(base64_decode($data));
}
That seems like a very weird issue.
I do not have a definite answer for you, but here are a couple of things you can try.
Encrypt/Decrypt without going to the database. If the issues goes away, then there is a problem with the database handling the characters output though the encryption function.
Trim the value before you encrypt it. If the issues goes away, then the trim after encryption is wrong.
Remove the safe_encode and safe_decode code. If the issue goes away, then these functions are adding/removing important things.
It is important that you do all the above in one go, as there might be multiple issues. If the above steps remove the issues, then reintroduce them one at a time to identify which is causing the problem.

DES encryption in PHP

I am coding a Drupal payment method module and within this I need to generate a hash to send to a bank. Bank asks me to code certain strings into the DES/ECB hash. They also provide test environment and here comes my problem. With the string B7DC02D5D6F2689E and key 7465737465703031 I should get result hash 3627C7356B25922B (after bin2hex, of course). This is by the bank test page and I have also checked this on this page: http://www.riscure.com/tech-corner/online-crypto-tools/des.html (encryption java applet).
My problem is that whatever I do I cant get my PHP code to provide the correct result. This is a simple function I am trying to use:
function encrypt($hash, $key)
{
$hash = strtoupper(substr(sha1($hash), 0, 16));
$key = strtoupper(bin2hex($key));
$block = mcrypt_get_block_size('des', 'ecb');
if (($pad = $block - (strlen($hash) % $block)) < $block) {
$hash .= str_repeat(chr($pad), $pad);
}
$sig = strtoupper(bin2hex(mcrypt_encrypt(MCRYPT_DES, $key, $hash, MCRYPT_MODE_ECB)));
return $sig;
}
and I have been trying sth like this as well:
function encrypt( $value, $key) {
$hash = strtoupper(substr(sha1($value), 0, 16));
$key = strtoupper(substr(bin2hex($key), 0, 16));
// encrypt hash with key
if (function_exists('mcrypt_module_open')) { // We have mcrypt 2.4.x
$td = mcrypt_module_open(MCRYPT_DES, "", MCRYPT_MODE_ECB, "");
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size ($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$signature = strtoupper(bin2hex(mcrypt_generic ($td, $hash)));
mcrypt_generic_end ($td);
}
else
{ // We have 2.2.x only
$signature = strtoupper(bin2hex(mcrypt_ecb (MCRYPT_3DES, $key, $hash, MCRYPT_ENCRYPT)));
}
return $signature;
}
None of these gave the correct signature. Any idea what's wrong? For now I am dealing with this issue more than 3 hrs, so I appreciate any help. I am not very familiar with this encryption stuff. Thanks a lot.
Btw.: Those $hash and $key mentioned above are after the strtoupper, substr and bin2hex functions at the beginning of my code snippets.
Simple solution:
function encrypt($hash, $key) {
return mcrypt_encrypt("des", pack("H*", $key), pack("H*", $hash), "ecb");
}
print bin2hex(encrypt("B7DC02D5D6F2689E", "7465737465703031"));
This prints 3627c7356b25922b for me, so it looks like that's working.
You were on the right track with bin2hex(), but that was converting in the wrong direction. (There's unfortunately no hex2bin() function, so you have to use pack() instead.)
You also don't need an IV for a single-block encryption like this.
You plaintext, B7DC02D5D6F2689E, is 8 bytes = 64 bits. This is an exact block for DES so you don't need any padding in ECB mode. I suggest that you remove the padding code entirely. All DEC-ECB needs in this case is the block to encrypt and the key; no padding and no IV.

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