While finishing my websites java login program and page, I decided to pass an encypted value through the URL to a validation page as an extra line of security. I have an encyrption algorithim that I wrote long ago that no one I know has cracked yet so I want to use that. But I need chars for it to properly work. From what I can tell, PHP doesn't have a char type. So my question is first, is their a char type, and secondly, is it possible to convert that to an int? Side Note: Login is a signed applet so all pages are in PHP. Edit: Forgot to mention that this is just the base of encryption and I will be adding to the algorithim.
You can reference a character in a string $str by $str[$index].
The ord function will return a character's integer value:
$val = ord($str[$index]);
The chr function does the opposite:
$char = chr($val);//$char == $str[$index]
You can access a string $s character by character by referring to $s[$i]. ord($s) gets the ASCII value of a character, chr($n) gets the character corresponding to an ASCII value.
Don't use your own cryptographic primitives unless you know what you are doing! Use PHP's own implementations of known strong algorithms (e.g. AES-256). Just because no one you know has cracked your custom algorithm doesn't mean someone else can't.
There is no char type in PHP, and the string type does not readily convert to int. PHP handles dynamic type-juggling, so type declarations are not used.
On a side note, "no one has cracked [my encryption algorithm] yet" doesn't necessarily mean someone won't in the future. If you're encrypting important stuff, use the standard encryption algorithms - they're standard for a reason.
Related
I'm setting up a PHP email tracking system that uses url parameters to track link click throughs. Something like:
www.example.com?trackToken=10
I'm looking for a simple PHP encode / decode function I can put in place that will take a number (in this case 10) and convert in to strictly to number and letters. something like:
www.example.com?trackToken=7aj8nG93nDpw9M9Nk1
I have found several variations of encrypt / decrypt functions using mcrypt. However, the encrypted output always ends up containing strange characters. These strange characters make it hard for my email messages to be sent/delivered.
Does anyone know of a good encrypt function that only outputs numbers 0-9 and letters a-z or A-Z? Additionally, I'm looking for a decrypt function to complement the encrypt function so I can actually use it.
I'm not looking for something super secure here. Just a way to mask the actual tracking token so the user can't change it on their own.
Base64 should be fine in any modern system - and any system handling email in PHP fits the definition of "modern". There is absolutely no reason I can think of to limit to just alphanumerics. The only catch is that as a URL parameter you don't want to have a '+' or '/' in the string. There is base64url to solve this problem but that doesn't have a standard PHP function. You can easily replicate that by using base64_encode() and str_replace() and to decode str_replace followed by base64_decode():
$coded = str_replace('+','-',str_replace('/','_',base64_encode($original)));
$original = base64_decode(str_replace('_','/',str_replace('-','+',$coded)));
I have a large string $string that when applied to md5(), give me
c4ca4238a0b923820dcc509a6f75849b
The length is 32, I want to reduce it, so
base64_encode(md5($string, true));
xMpCOKC5I4INzFCab3WEmw==
Removing the last two == it give me a string with length = 22.
Are there any other better algorithms?
I am not sure you realised that md5 is a hash function, and therefore irreversible. If you do not care about reversibility, you could just as well trim the md5 hash (or any hash of your liking*) down to an arbitrary number of characters. All this would do is increase the likelihood of collision (I feel this does not produce an uniform distribution though).
If you are looking for a reversible (ie. non-destructive) compression, then do not reinvent the wheel. Use the built-in functions, such as gzdeflate() or gzcompress(), or other similar functions.
*Here is a list of hash functions (wikipedia) along with the size of their output.
I suppose the smallest possible "hash function" would be a parity bit :)
One better way would be to, instead of converting to binary to hexadecimal (as md5 does) and then converting the string to base64, instead convert from the hexadecimal md5 directly to base64.
Since hexadecimal is 16 bits per character, and base64 is 64 bits per character, every 2 hexadecimal characters will make up one base64 character.
To perform the conversion, you can do the following:
Split the string into sixteen 2 character chunks
The first character should be multiplied by 2 and added to the second (keeping in mind that A-F = 10-15).
This number can be matched to the base64 scheme using the table from here: https://en.wikipedia.org/wiki/Base64
This will result in a 16 character base64 string with the same value as the hexadecimal representation of the md5 string.
Theoretically, you could do the same for any base. If we had a way to encode base128 strings in ASCII, we could end up with an 8 character string. However, as the character set is limited, I think base64 is the highest base that is commonly used.
The smaller the length of the string you want .. the smaller the number of possible combination
Total Number of Possibility with reputation
Total Possibility = nr
Since we are dealing with base64 has the printable output this means we only have 64 characters
n = 64
If you are looking at 22 letters in length
nr = 6422 = 5,444,517,870,735,015,415,413,993,718,908,291,383,296 possibilities
Back to your question : Are there any better algorithm?
Truncate the string with a good hash to desired length you want since the total possibility and collision is fixed
$string = "the fox jumps over the lazy brown dog";
echo truncateHash($string, 8);
Output
9TWbFjOl
Function Used
function truncateHash($str, $length) {
$hash = hash("sha256", $str, true);
return substr(base64_encode($hash), 0, $length);
}
This encoding generates shorter string,
print base64_encode(hash("crc32b",$string,1));
output
qfQIdw==
Not sure if MD5 is the right choice for you, but i will assume that you have reason to stick with this algorithm and are looking for a shorter representation. There are several possibilities to generate a shorter string with different alphabets:
Option 1: Binary string
The shortest possbile form of an MD5 is it's binary representation, to get such a string you can simply call:
$binaryMd5 = md5($input, true);
This string you can store like any other string in a database, it needs only 16 characters. Just make sure you do a proper escaping, either with mysqli_real_escape_string() or with parametrized queries (PDO).
Option 2: Base64 encoding
Base64 encoding will produce a string with this alphabet: [0-9 A-Z a-z + /] and uses '=' as padding. This encoding is very fast, but includes the sometimes unwanted characters '+/='.
$base64Md5 = base64_encode(md5($input, true));
The output length will be always 24 characters for the MD5 hash.
Option 3: Base62 encoding
The base62 encoding only uses the alphabet [0-9 A-Z a-z]. Such strings can be safely used for any purpose like tokens in an URL, and they are very compact. I wrote a base62 encoder, which is able to convert binary strings to the base62 alphabet. It may not be the fastest possible implementation, but it was my goal to write understandable code. The same class could be easily adapted to different alphabets.
$base62Md5 = StoBase62Encoder::base62encode(md5($input, true));
The output length will vary from 16 to 22 characters for the MD5 hash.
Base 91 looks like the most space efficient binary to ASCII printable encoding algorithm (which is what it seems you want).
I've not seen the PHP implementation, but if your software has to work with others I'd stick to Base 64; it's well-known, lightning fast, and available everywhere.
Firstly, to answer your question: Yes, there is a better algorithm (if with "better" you mean "shorter").
Use the hash() function (which has been part of the PHP core and enabled by default since PHP 5.1.2.) with any of the adler32, fnv132, crc32, crc32b, fnv132 or joaat algorithms.
Without a more in-depth knowledge of your current situation, you might as well just pick whichever one you think sounds the coolest.
Here is an example:
hash('crc32b', $string)
I set up an online example you can play around with.
Secondly, I would like to point out that what you are asking is an almost exact duplicate of another question here on stackoverflow.
I read from your post that you are searching for a hashing algorithm and not compression.
There are various standard hashing algorithms in php out there. Have a look at PHP hashing functions.
Depending on what you want to hash there are different approches. Be careful and calculate the average collision probability.
However it seems you are searching for a 'compression' which outputs the minimum possible size of chars for a given string. If you do, then have a look at Lempel–Ziv–Welch (php implementation) or others.
I'm new to this encryption thing, so i'm not realy sure how to format my question.
Anyways i'm using framework called kohana and for encryption it uses three things:
key, cipher, mode so my problem is that when it encodes some string sometimes i get / in encryption like this fclzSev6DVfOk2Z/BSSi4dRYFn4t and i don't want that so my guess is that i should change mode which right now is MCRYPT_MODE_NOFB so if i'm right what mode do i have to use?
As Francis Avila notes, the encrypted output seems to be Base64-encoded, and so may contain slashes and plus signs (and possibly equals signs at the end) in addition to letters and numbers.
You can safely replace those signs with something else, as long as you remember to change them back before decoding. The PHP strtr() function is handy for this. For example, here's how to convert a string from normal Base64 to the RFC 4648 URL-safe Base64 variant and back:
$url_safe_base64 = strtr( $base64_string, "+/", "-_" );
$base64_string = strtr( $url_safe_base64, "-_", "+/" );
mode has absolutely nothing to do with whether the generated output has slashes, but specifies what mode of encryption mcrypt should use. If you don't know what it's for use the default.
The reason there are slashes is that Kohana's encode() method will encode the binary output from the encryption in base64, which may contain slashes.
You can str_replace() the slashes with something else, but this will probably create more problems and headaches than it solves.
I need to encrypt a string using MySQL's AES_ENCRYPT function, then attach that encrypted string to the end of a URL, such that it can then be decrypted and used by a PHP script on the other end.
Basically, I am encrypting the string (using MySQL's AES_ENCRYPT), I am then using PHP's rawurlencode() function to make it "URL safe". I then pass the encrypted string in a URL, which is then retrieved by the PHP script on the other end where it gets successfully decrypted... about 95% of the time.
Seems as though about 5% of strings are encrypting in such a way that they are getting corrupted somewhere in the process, and can't be decoded on the other end after being passed by a URL. Can anyone help me out here? Is there a 100% fool-proof way to do this? I have also tried using urlencode() as well as base64_encode() in varying combinations.
Thanks.
Solved.
Once I have encrypted the string using MySQL's AES_ENCRYPT function, I use PHP's bin2hex() function to convert that encrypted data (which is in binary form) in to Hexidecimal. I then pass the Hexidecimal as a string on the end of the URL. Once the URL is received on the other end, I then use this custom PHP function to revert the Hex string back to binary:
function hex2bin($data) {
$len = strlen($data);
return pack("H" . $len, $data);
}
From there, all that's left to do is decrypt the data using MySQL's AES_DECRYPT function, and wha-la. The original string is successfully restored.
URLs have a finite maximum length. AES-encrypted strings do not.
URLs are not an appropriate vector for passing arbitrary information. Using an HTTP POST is a much better way, if you must communicate over HTTP.
About why you are having problems: quoting from the PHP manual page on urlencode:
Note: Be careful about variables that
may match HTML entities. Things like
&, © and £ are parsed by
the browser and the actual entity is
used instead of the desired variable
name. This is an obvious hassle that
the W3C has been telling people about
for years. The reference is here:
http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.2.
PHP supports changing the argument
separator to the W3C-suggested
semi-colon through the arg_separator
.ini directive. Unfortunately most
user agents do not send form data in
this semi-colon separated format. A
more portable way around this is to
use & instead of & as the
separator. You don't need to change
PHP's arg_separator for this. Leave it
as &, but simply encode your URLs
using htmlentities() or
htmlspecialchars().
What is the best way of generating a hash for the purpose of storing a session? I am looking for a lightweight, portable solution.
bin2hex(mcrypt_create_iv(22, MCRYPT_DEV_URANDOM));
mcrypt_create_iv will give you a random sequence of bytes.
bin2hex will convert it to ASCII text
Example output:
d2c63a605ae27c13e43e26fe2c97a36c4556846dd3ef
Bare in mind that "best" is a relative term. You have a tradeoff to make between security, uniqueness and speed. The above example is good for 99% of the cases, though if you are dealing with a particularly sensitive data, you might want to read about the difference between MCRYPT_DEV_URANDOM and MCRYPT_DEV_RANDOM.
Finally, there is a RandomLib "for generating random numbers and strings of various strengths".
Notice that so far I have assumed that you are looking to generate a random string, which is not the same as deriving a hash from a value. For the latter, refer to password_hash.
random_bytes() is available as of PHP 7.0 (or use this polyfill for 5.2 through 5.6). It is cryptographically secure (compared to rand() which is not) and can be used in conjunction with bin2hex(), base64_encode(), or any other function that converts binary to a string that's safe for your use case.
As a hexadecimal string
bin2hex() will result in a hexadecimal string that's twice as many characters as the number of random bytes (each hex character represents 4 bits while there are 8 bits in a byte). It will only include characters from abcdef0123456789 and the length will always be an increment of 2 (regex: /^([a-f0-9]{2})*$/).
$random_hex = bin2hex(random_bytes(18));
echo serialize($random_hex);
s:36:"ee438d1d108bd818aa0d525602340e5d7036";
As a base64 string
base64_encode() will result in a string that's about 33% longer than the number of random bytes (each base64 character represents 6 bits while there are 8 bits in a byte). It's length will always be an increment of 4, with = used to pad the end of the string and characters from the following list used to encode the data (excluding whitespace that I added for readability):
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
0123456789
/+
To take full advantage of the space available, it's best to provide an increment of 3 to random_bytes(). The resulting string will match /^([a-zA-Z\/+=]{4})*$/, although = can only appear at the end as = or == and only when a number that is not an increment of 3 is provided to random_bytes().
$random_base64 = base64_encode(random_bytes(18));
echo serialize($random_base64);
s:24:"ttYDDiGPV5K0MXbcfeqAGniH";
You can use PHP's built-in hashing functions, sha1 and md5. Choose one, not both.
One may think that using both, sha1(md5($pass)) would be a solution. Using both does not make your password more secure, its causes redundant data and does not make much sense.
Take a look at PHP Security Consortium: Password Hashing they give a good article with weaknesses and improving security with hashing.
Nonce stands for "numbers used once". They are used on requests to prevent unauthorized access, they send a secret key and check the key each time your code is used.
You can check out more at PHP NONCE Library from FullThrottle Development
Maybe uniqid() is what you need?
uniqid — Generate a unique ID
You can use openssl_random_pseudo_bytes since php 5.3.0 to generate a pseudo random string of bytes. You can use this function and convert it in some way to string using one of these methods:
$bytes = openssl_random_pseudo_bytes(32);
$hash = base64_encode($bytes);
or
$bytes = openssl_random_pseudo_bytes(32);
$hash = bin2hex($bytes);
The first one will generate the shortest string, with numbers, lowercase, uppercase and some special characters (=, +, /). The second alternative will generate hexadecimal numbers (0-9, a-f)
Use random_bytes() if it's available!
$length = 32;
if (function_exists("random_bytes")) {
$bytes = random_bytes(ceil($length / 2));
$token = substr(bin2hex($bytes), 0, $length)
}
Check it on php.net
I personally use apache's mod_unique_id to generate a random unique number to store my sessions. It's really easy to use (if you use apache).
For nonce take a look here http://en.wikipedia.org/wiki/Cryptographic_nonce there's even a link to a PHP library.
I generally dont manually manage session ids. Ive seen something along these lines recommended for mixing things up a bit before, ive never used myself so i cant attest to it being any better or worse than the default (Note this is for use with autogen not with manual management).
//md5 "emulation" using sha1
ini_set('session.hash_function', 1);
ini_set('session.hash_bits_per_character', 5);
Different people will have different best ways. But this is my way:
Download this rand-hash.php file :
http://bit.ly/random-string-generator
include() it in the php script that you are working with. Then, simply call
cc_rand() function. By default it will return a 6 characters long
random string that may include a-z, A-Z, and 0-9. You can pass
length to specify how many characters cc_rand() should return.
Example:
cc_rand() will return something like: 4M8iro
cc_rand(15) will return something similar to this: S4cDK0L34hRIqAS
Cheers!