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.
Related
I have this function to encrypt strings:
public function encriptar($string) {
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC),
MCRYPT_DEV_URANDOM);
$encrypted = base64_encode($iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_128,
hash('sha256', getKey(), true),
$string, MCRYPT_MODE_CBC, $iv));
return $encrypted;
}
The problem is that I always return a different value even adding the same string.
Example:
I introduce: StackOverflow
Result: InT3g0AUXXTrmCAxrlht5ZVe8GBmlgGDMotXuVu11hI =
If I rerun the script:
I introduce: StackOverflow
Result: ImhWn5vPA / A2NY2wpUwg7VLWAiGBls80Z84fGU303Ws =
If I re-run the script:
I introduce: StackOverflow
Result: FqvxSsblSwz5riaDnnq7h20PzZTPdk / K + dikLHbLHTY =
How can I make it always the same value?
You are creating a different $iv using MCRYPT_DEV_URANDOM as the pseudo-random-number-generator, use the same $iv, and the result will be the same.
You can either store it in you database, in the class instance, or store it as a prefix/suffix of the final hash.
Albeit you shouldn't be reusing the $iv for security purposes...
A more insightful topic of the security implications of reusing the key, or even the IV can be found here: https://crypto.stackexchange.com/questions/10505/reusing-keys-with-aes-cbc
The result is dependent on the $iv variable which you keep regenerating. You need to generate it only once, save it in the database and then re-use it.
function getIv($database) {
// fictive database abstraction layer
$iv = $database->fetchIv();
if (!$iv) {
$iv = mcrypt_create_iv(
mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC),
MCRYPT_DEV_URANDOM
);
$database->saveIv($iv);
}
return $iv;
}
// in your class
public function encriptar($string) {
$encrypted = base64_encode($iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_128,
hash('sha256', getKey(), true),
$string, MCRYPT_MODE_CBC, getIv()));
return $encrypted;
}
However, for best practices, this should be kept in a configuration file.
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
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)
Here is my encode url param aKVXt4_P78X64w5ApVAZJ0fSNpV_GGFWxBs0aE_xw_24ghq1C5awAAPPKYbZSi0rGJUmyPlohVsP0fE4-jHQnN
When Encryption class decode it the result is ±�ыП^ґрьI§эЁ¶шЪ™МkVЃ°(ѓ7m‰e+и *“V«;Ё#ЧB§Z{Ћ‹JЈи_ЈWfUѕe
I don't understand the reason of such issue, it happens rather rarely but brings some trouble.
To uncode/decode links i use such class.
class Encryption {
// config local ENCRIPTION_KEY
var $skey = ENCRIPTION_KEY;
private function safe_b64encode($string) {
$data = base64_encode($string);
$data = str_replace(array('+','/','='),array('-','_',''),$data);
return $data;
}
private function safe_b64decode($string) {
$data = str_replace(array('-','_'),array('+','/'),$string);
$mod4 = strlen($data) % 4;
if ($mod4) {
$data .= substr('====', $mod4);
}
return base64_decode($data);
}
public function encode($value){
if(!$value){return false;}
$text = $value;
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$crypttext = trim(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->skey, trim($text), MCRYPT_MODE_ECB, $iv));
return trim($this->safe_b64encode($crypttext));
}
public function decode($value){
if(!$value){return false;}
$crypttext = $this->safe_b64decode($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, $this->skey, $crypttext, MCRYPT_MODE_ECB, $iv);
return trim($decrypttext);
}
}
I believe the problem you are having is that you are encrypting using a random IV and then trying to decrypt using a completely different random IV. It is important to have a random IV, but you need the same IV to decrypt. The IV does not need to be secret as long as the constant KEY is hidden.
Also #Daniel was correct when saying that ECB doesn't use an IV. It will ignore it, so the last paragraph is now mute. However, you should consider switching from ECB to CBC as it is more secure (simply because it does use an IV).
I wrote a small class to encrypt/decrypt using MCRYPT in CBC mode (allowing any supported encryption algorithm e.g., BLOWFISH, TWOFISH, RIJNDAEL, etc). When encrypting it creates a random IV then prepends it to the encrypted string before returning the whole lot in hex. Then when it needs to decrypt the same string it will convert back to bin, determine the iv size of the encryption algorithm, remove the IV from the encrypted string and use it to return the decrypted string. If you think it might help, you can check it out. Hope it helps.
I have a class that takes a string in this format:
000067000000000012620060324b38e2cab3353
, encrypts the string then appends it as a get variable in a URL.
The class that does the encryption has a function that looks like this:
private function _code_encryption($enc_type,$a_string){
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
if($enc_type == self::ENCRYPT_STRING){
//encrypt then return base64 encoded
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, self::AUTH_ENCRYPTION_KEY, $a_string, MCRYPT_MODE_CBC, $iv);
return base64_encode($encrypted);
}elseif($enc_type == self::DECRYPT_STRING){
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, self::AUTH_ENCRYPTION_KEY, base64_decode($a_string), MCRYPT_MODE_CBC, $iv);
return trim($decrypted);
}
}
When the string is encrypted I urlencode the value and add it to the url like the url looks like "https://secure.mysite.com/index.php?action=someaction&transfer_code=XXXXX where XXXX is the urlencoded encrypted string.
Now, when the url is parsed and processed the value of $_GET['transfer_code'] is getting passed into the above _code_encryption function but is not returning the correctly decrypted value and instead returns garbled characters my browser doesn't render. Is there a requirement for the length of the key I use for encryption/decryption? I tried something like
$key = hash('sha256',self::AUTH_ENCRYPTION_KEY,true);
but that didn't work either...
Also, I am not urldecoding the $_GET['transfer_code'] variable because the php man pages state that get vars are already urlencoded...
Should I be UTF-8 encoding the alphanumeric string BEFORE encryption/base64_encoding, or will that even make any difference?
You use a random IV to encrypt, and the a different random IV to decrypt. The decrypted string will never ever match the original. To properly decrypt the original string you must use the same IV that was used during encryption. Usually this is achieved by prepending the IV used to the encrypted string. At decryption time you must first extract the IV from the value, initialize the key with this value, then decrypt the rest usign the properly initialized key.
I don't have a parser to validate this but it should be something like:
private function _code_encryption($enc_type,$a_string){
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
if($enc_type == self::ENCRYPT_STRING){
//encrypt then return base64 encoded
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, self::AUTH_ENCRYPTION_KEY, $a_string, MCRYPT_MODE_CBC, $iv);
return base64_encode($iv.$encrypted);
} elseif ($enc_type == self::DECRYPT_STRING){
$decoded = base64_decode($a_string);
$iv = substr($decoded,0,$iv_size);
$cipher = substr($decoded,$iv_size);
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, self::AUTH_ENCRYPTION_KEY, $cipher, MCRYPT_MODE_CBC, $iv);
return trim($decrypted);
}
}