Link to home
Create AccountLog in
Avatar of UltraFlux
UltraFluxFlag for Canada

asked on

Encrypt/Decrypt using PHP with max length.

Good afternoon,

I have an encrypt / decrypt script in PHP which works. However, I am trying to utilize this online and reduce the number of characters allowed.

I'd like to know if anyone has seen or using something with these requirements.

$max-lenght = 12 (roughly 12, something between 10 - 20 is perfect)
$accepted-char = 'a-z,A-Z,0-9'

I'm fine using anything that will accomplish this as the data is not sensitive.

Thanks!
Avatar of DrDamnit
DrDamnit
Flag of United States of America image

I am not sure what you are asking...

Are you trying to limit what a year can enter?
If the data is not sensitive, then why are you encrypting/decrypting it?
And I agree with DrDamnit's question - we need more details on the limits.
Avatar of UltraFlux

ASKER

Ok, I thought that was pretty spec. I guess I was wrong.

I just want a basic encode to rename a file name.

class Encryption {
    var $skey = "yourSecretKey"; // you can change it

    public  function safe_b64encode($string) {
        $data = base64_encode($string);
        $data = str_replace(array('+','/','='),array('-','_',''),$data);
        return $data;
    }

    public 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_saferplus, MCRYPT_MODE_CFB);
        // $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        $crypttext = mcrypt_encrypt(MCRYPT_saferplus, $this->skey, $text, MCRYPT_MODE_CFB);
        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_DES, MCRYPT_MODE_CFB);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        $decrypttext = mcrypt_decrypt(MCRYPT_saferplus, $this->skey, $crypttext, MCRYPT_MODE_CFB);
        return trim($decrypttext);
    }
}

$str = "My-File-Name-For-Use-Online-Particularly-For-Embeding-Media";

Open in new window


iS6mpfDoQwhnI4z8ws0DylpocomiajxnxOMkV9Ey9Ksr5Z_5eLIEFlPDtzjh_TkSkee9pMBF77H0fb0
My-File-Name-For-Use-Online-Particularly-For-Embeding-Media

I would prefer the output is a lot shorter than the encoded string above.

Thanks
Additional Example:

I've seen a lot of examples like
/embed/jcfbekk5n73d
Methnks you're taking the long way around the barn. Typically, when I see examples like the one you've posted, they are using shortlinks not encryption.

The purpose being: .htaccess and mod_rewrite grab that string and use it to perform a DB lookup to serve media or content.
Yes I understand. I will keep hacking away, at some point I will figure it out.

Just want an easier to way obscure files and still be able to easily keep track of inventory.

Example:
File Name -> encode -> jcfbekk5n73d - decode -> File Name

I do not want to keep a database for the sole purpose of looking actual file names.

If the database is lost or something happens, I am stuck with thousands of obsured file names.

-G
Hi UltraFlux,

Okay, so I think you might be missing a part of this process. First and foremost, encryption is not compression.

Typical compression (like ZIP, RAR, etc...) works by having a dictionary. Imagine if you had a dictionary that had the following entries in it, like this:

0 = blue
1 = red
2 = green
3 = brown
4 = jumped
5 = stood
6 = rolled
7 = fox
8 = dog
9 = the


You could theoretically shorten "the quick brown fox jumped over the lazy dog" to "9 quick 3 7 4 over 9 lazy 8". This is sort of how compression works, except the dictionaries can be dynamic and more complex.

Encryption doesn't reduce data, it just changes it into something else, and often actually INCREASES size as part of the process because you are often applying math to certain values. An encryption routine might take every letter and turn it into 3 characters, like "t" = "aj8" (especially when you get into cryptography that uses blocks).

So when you look at a URL like "/embed/jak8767" and it results in a filename, it is usually because "jak8767" actually turns into an ID number, like 123456, and "123456" is a unique ID in a database that contains all the rest of the file information.

Most codes like that are simply numbers that have been encoded using a different base numbering system. So if you think about hexadecimal, which is Base-16, you get values like:

0 = 0
1 = 1
2 = 2
...
9 = 9
10 = A
11 = B
12 = C
13 = D
14 = E
15 = F
16 = 10
17 = 11
...
245 = FE
255 = FF
256 = 100

So using just Base-16, you can represent a database record ID of "255" using two letters. You're already "shortening" the value.

The more you increase the base numbering system, the more you can "stuff" into a short value.

If you used all 26 letters upper and lower case so that:

0 = 0
1 = 1
2 = 2
...
10 = A
11 = B
...
35 = Y
36 = Z
37 = a
38 = b
...
62 = z
63 = _
64 = .
65 = #  <-- let's say this is the stop of your custom "base" numbering system
66 = 10
67 = 11
67 = 12
...


... and so on. With that kind of numbering system, you instantly can have huge ID numbers that have been reduced to a couple of letters and symbols. (You can take out vowels to avoid accidentally generating curse words)

Now it's just a matter of storing the filename into a database and using that ID number / value in your URLs.
Just want an easier to way obscure files and still be able to easily keep track of inventory.

Then you are looking for obfuscation, not encryption. Why not try a ceasar cipher?
http://forum.codecall.net/topic/35817-php-code-simple-encryption-algorithm/#axzz2BNkhLRur

or:

Just shift the characters up 5 values in ASCII?
A (65) becomes F (70).

Where a number is greater than the range, subtract the length of the entire range +1.

Z (90) + 5 = 95, which is greater than the range, and therefore 90-26 = 64, +1 = 65 (or A)

You can create the values in an excel spreadsheet to make sure they all work.

I do not want to keep a database for the sole purpose of looking actual file names.

If the database is lost or something happens, I am stuck with thousands of obscured file names.

If you're running a system without a backup, you're asking for trouble. There is no difference between backing up DB's and backing up files (conceptually) only procedurally. Furthermore, you can use a Berkeley DB or sqllite db, which is a single file database, and can be backed up with the rest of your files.

Ultimately, I think you've confused shortlinks with base64 encoding. As gr8gonzo points out, compression and encryption are different. Base64 encoding usually EXPANDS data larger than the original.

I think you just want obfuscation. A simple Caesar Cipherwill probably suffice.
Files are backed up on Amazon S3 automatically.

Shifting the characters obscurs the string but does not allow me to reduce the number of characters for a long filename.

I guess I need to do some more research.
You cannot do what you want to do without a database (shortnames) or very complicated compression.
ASKER CERTIFIED SOLUTION
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

Link to home
membership
Create an account to see this answer
Signing up is free. No credit card required.
Create Account
Sorry for the delay in responding, but here's a quick and easy class to help you with shortening IDs to short strings. There's a single line to encode and a single line to decode values:

$original = 12345;
echo MyBase::Encode($original); // Will result in 3F7

Open in new window


$encodedValue = "3F7";
echo MyBase::Decode($encodedValue); // Will result in 12345

Open in new window


With this class, you can take any number up to around 60 billion and reduce it to a string that is 6 characters or less.

Here's the class:

<?php
/**
 * MyBase 1.0
 * 
 * This is a class to assist with custom base value encoding, typically for 
 * shortening long IDs into short strings.

 * @package     MyBase
 * @author      Jonathan Hilgeman
 * @modified    2012-11-05
 *
 * Example #1: 
 * // Encoding/Decoding using default Base-62 encoding
 * echo MyBase::Encode(12345); // 3F7
 * echo MyBase::Decode("3F7"); // 12345
 *
 * Example #2:
 * // Encoding/Decoding with custom Base-16
 * MyBase::$base = "A987B654C321D0EF";
 * echo MyBase::Encode(12345);
 * echo MyBase::Decode("7A73");
*/


class MyBase
{
	public static $base = "0123456789BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz!^*()_-~',"; // Removed AEIOUaeiou to avoid accidental swearing

	// Encode turns encoded value back into regular, decimal value	
	public function Encode($value)
	{
		$encodedValue = "";
  	$base = strlen(self::$base);
		$valueLeft = $value;
		
    while ($valueLeft > 0)
    {
    	$encodedValue .= self::$base[($valueLeft % $base)];
			$valueLeft = floor($valueLeft / $base);
    }
    
		return strrev($encodedValue);
	}
	
	// Decode turns regular, decimal value into encoded value
	public function Decode($value)
	{
		$value = (string)$value;
  	$decodedValue = 0;
  	$base = strlen(self::$base);
  	$len = strlen($value);
  	$multiplier = 1;

		// Look up each character's value, convert it to decimal, and add it's proper multiplied value  	
    for($i = $len-1; $i >= 0; $i--)
    {
    	$char = $value[$i];
    	$charValue = strpos(self::$base,$char);
    	$decodedValue += ($charValue * $multiplier);
    	$multiplier *= $base;
    }
		
		return $decodedValue;    
	}
}
?>

Open in new window

Guess that's what I get for not posting my comment response for a couple of hours.

Anyways, I would double-check with what properties you already get from Amazon S3's service. I wrote a wrapper for it a long time ago for a client, and I remember they had some function for generating public URL links for you, although I can't remember if there was a numeric ID for each file. If there IS a numeric ID, then you can use my above class/code to turn that ID into a short string, if you want to manually handle some linking behavior.
In case you do use my code, I pasted a version with a mistake that will have trouble with IDs above the 2 billion mark. Here's a fixed version:

<?php
/**
 * MyBase 1.0
 * 
 * This is a class to assist with custom base value encoding, typically for 
 * shortening long IDs into short strings.

 * @package     MyBase
 * @author      Jonathan Hilgeman
 * @modified    2012-11-05
 *
 * Example #1: 
 * // Encoding/Decoding using default Base-62 encoding
 * echo MyBase::Encode(12345); // 3F7
 * echo MyBase::Decode("3F7"); // 12345
 *
 * Example #2:
 * // Encoding/Decoding with custom Base-16
 * MyBase::$base = "A987B654C321D0EF";
 * echo MyBase::Encode(12345);
 * echo MyBase::Decode("7A73");
*/

class MyBase
{
	public static $base = "0123456789BCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz!^*()_-~',"; // Removed AEIOUaeiou to avoid accidental swearing

	// Encode turns encoded value back into regular, decimal value	
	public function Encode($value)
	{
		$value += 0;
		$encodedValue = "";
  	$base = strlen(self::$base);
		$valueLeft = $value;
		
    while ($valueLeft > 0)
    {
   		$encodedValue .= self::$base[fmod($valueLeft,$base)];
			$valueLeft = floor($valueLeft / $base);
    }
    
		return strrev($encodedValue);
	}
	
	// Decode turns regular, decimal value into encoded value
	public function Decode($value)
	{
		$value = (string)$value;
  	$decodedValue = 0;
  	$base = strlen(self::$base);
  	$len = strlen($value);
  	$multiplier = 1;

		// Look up each character's value, convert it to decimal, and add it's proper multiplied value  	
    for($i = $len-1; $i >= 0; $i--)
    {
    	$char = $value[$i];
    	$charValue = strpos(self::$base,$char);
    	$decodedValue += ($charValue * $multiplier);
    	$multiplier *= $base;
    }
		
		return $decodedValue;    
	}
}
?>

Open in new window

Thanks for the recommendation guys. I am trying these out now!

Seems like this is the only route. Glad I posted here or I would have been trying to figure this out for days.

I'll drop some comments in here shortly
gr8gonzo
I've tried your code and I am able to use it as is in your code. Spec. using 12345 -> 7A73

However, it does not seem to like a file name?
My-File-Name-For-Use-Online-Particularly-For-Embeding-Media

Ray_Paseur
Thanks Ray, I've tested your code and I get back random keys as required. I have one question. You have a create table function and also an insert statement.

Does it just use MySQL to determin if the key is unique or does it actually complete the insert at this time?

Thanks!
Hi UltraFlux,

Yes, I know. My code is designed to only shorten numeric IDs. As I said before, you cannot shorten a file name. You have to shorten the ID in a database and then look up the file name using the ID.
Ok Thanks, I miss read.

I will review Ray's reply in more detail.
determin if the key is unique
Since the column is marked UNIQUE in the table definition, MySQL will cause the INSERT statement to fail, it the new row has a value in a UNIQUE column that matches any other row in the table.  When the INSERT fails, MySQL throws error number 1062.  When the INSERT does not fail, the new row is present in the table after execution of the query.
Perfect, system seems to be working!
Thanks for the points and thanks for using EE -- it's a great question, ~Ray
Of course, thanks to the others as well!