obfuscate or encrypt some plain text data in PHP - php

I need to obfuscate or encrypt some plain text data in my php 5.2 application.
I'd prefer a solution that would have input string and output string retain the same length.
This does not need to extremely strong, as there are numerous other layers of security in place. Strong would be good, but this will just keep programmers/dba/support people/etc from accidentally reading the text from within the database.
key considerations
EDIT ADD I'd prefer a solution that would have input string and output string retain the same length.
only string text will be obfuscated/encrypted for storage in a database
the php application will need to obfuscate/encrypt the data before the database save and will need to un-obfuscate/dencrypt following the database read
this is a modification to an existing application
only some columns will need to be obfuscated/encrypted
only some rows will need to be obfuscated/encrypted, based on a Type field
there are only a few load/save points to handle
max column size is already determined for some fields, but not for others, but I'd prefer a solution to work within the existing size of the restricted fields
EDIT, ADD the key will be probably be a composite of some Primary key info +uneditable fields
here is a sample database table and data:
int char(1) varchar(24) int date
MyPrimaryKey RowType UserText UserNo DateChange
------------ ------- ------------------------ -------- ----------------
1 N nothing special here 43 6/20/2009 12:11am
2 N same thing, wow! 78 6/23/2009 1:03pm
3 S fBJKg}.jkjWfF78dlg#45kjg 43 6/25/2009 6:45am
4 N same old, same old text 21 6/25/2009 8:11am
The application would load and display rows 1,2, and 4 normally. However it would conditionally (based on row type) handle the text in row 3 using this obfuscate/encrypt and un-obfuscate/decrypt logic.
Can anyone provide obfuscate/encrypt and un-obfuscate/decrypt functions code, links, and or pointer that would help here?
thanks!
EDIT
I like the simple base64 encoding idea, but is there a method that can keep the data within a fixed size. All methods listed so far have the output value larger than the input value. This will be a problem for some columns, where the user can enter in 50 characters and it is stored in a varchar(50) column.

for simple obfuscation use strtr() - Translate certain characters:
string strtr ( string $str , string $from , string $to )
to encode in php:
$readable='This is a special test string ABC123 ([+,-!#$%&*])';
$unreadable=strtr($readable,' !"#$%&\'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
,'¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ !"#$%&\'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ '
);
print $unreadable; //outputs: "ÕéêôAêôAâAôñæäêâíAõæôõAôõóêïèAÂÃIJ³´A©Ü¬­®¢¤¥¦§«Þª"
to decode in php:
$unreadable='ÕéêôAêôAâAôñæäêâíAõæôõAôõóêïèAÂÃIJ³´A©Ü¬­®¢¤¥¦§«Þª';
$readable=strtr($unreadable,'¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ !"#$%&\'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ '
,' !"#$%&\'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
);
print $readable; //outputs: "This is a special test string ABC123 ([+,-!#$%&*])"
you can easily replicate this logic in the DB if necessary (without looping): Using a Table of Numbers, by Erland Sommarskog

How about base64 encoding? We use to use that to make SMS messages in our SMS Gateway DB unreadable by the developers.

Try these PHP functions convert_uuencode and convert_uudecode:
function encrypt_decrypt ($data, $encrypt) {
if ($encrypt == true) {
$output = base64_encode (convert_uuencode ($data));
} else {
$output = convert_uudecode (base64_decode ($data));
}
return $output;
}
$enc_txt = encrypt_decrypt ("HELLO DATA", true);
echo $enc_txt."\n"; // KjIkNSwzJFxAMSQlNDAwYGAKYAo=
echo encrypt_decrypt ($enc_txt, false); // HELLO DATA

There are a few options.
If you want very strong, you could look into mcrypt.
But if it's only so working developers cant read the text without some work to actually do it. Then you could just BASE64 encode it or uuencode it

If you have mcrypt installed (all my current PHP environments have), you could use mcrypt_encrypt and mcrypt_decrypt like this:
function encrypt ($text) {
global $key;
return mcrypt_encrypt (MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB, "abcdefghijklmnopqrstuvwxyz012345");
}
function decrypt ($secret) {
global $key;
return rtrim (mcrypt_decrypt (MCRYPT_RIJNDAEL_256, $key, $secret, MCRYPT_MODE_ECB, "abcdefghijklmnopqrstuvwxyz012345"), "\0");
}
which uses a global $key and AES (very strong).
Drawbacks are performance (in comparison to simpler ones like Base64) and that you somehow have to fix a key.
Cheers,

if you're using mysql around version 5, then you don't even need much php for it, you can do it inside your query with the mysql string functions encrypt(text, password) and decrypt(text, password)
http://dev.mysql.com/doc/refman/5.1/en/encryption-functions.html
DECODE(crypt_str,pass_str)
Decrypts the encrypted string crypt_str using pass_str as the password. crypt_str should be a string returned from ENCODE().
ENCODE(str,pass_str)
Encrypt str using pass_str as the password. To decrypt the result, use DECODE().
The result is a binary string of the same length as str.
The strength of the encryption is based on how good the random generator is. It should suffice for short strings.
update: another possibility would be rot13 ^^

Try using the mcrypt library. It's not included with standard PHP, but it's easily downloadable and very commonly used. Here's a quick tutorial on what you can do with it.
It's best to make sure the key you use for the encryption is stored in a secure place, but if you aren't really concerned about security, you'd probably be OK just hardcoding the key into your code somewhere.

Related

esp32 and php XXTEA strings encryption

I'm using esp32 (Arduino platform not esp-idf) with the "HTTPClient.h" library to send get requests with parameters to my PHP server.
I want to encrypt the parameter values and decrypt them in my PHP code And vice versa (my server sends back JSON data to my esp32).
I tried using the XXTEA protocol with these libraries for PHP, and for esp32.
But the encrypted string won't decrypt properly on PHP.
Example:
When I encrypt "HELLO WORLD" on my esp32 with the key "ENCRYPTION KEY" I get this:
35bd3126715874f741518f4d
And when I decrypt it on PHP it returns blank.
Moreover, when I encrypt it on my PHP server I get this:
T1YNYC4P4R2Y5eCxUqtjuw==
My esp32 sketch looks like this:
#include <xxtea-iot-crypt.h>
void setup() {
Serial.begin(115200);
}
void loop() {
String plaintext = "HELLO WORLD";
// Set the Password
xxtea.setKey("ENCRYPTION KEY");
// Perform Encryption on the Data
Serial.print(F(" Encrypted Data: "));
String result = xxtea.encrypt(plaintext);
Serial.println(result);
// Perform Decryption
Serial.print(F(" Decrypted Data: "));
Serial.println(xxtea.decrypt(result));
delay(2000);
}
My PHP code looks like this:
require_once('xxtea.php');
$str = "HELLO WORLD"
$key = "ENCRYPTION KEY";
$encrypt_data = xxtea_encrypt($str, $key);
error_log($encrypt_data);
Is there a way to have an encrypted strings communication between PHP and esp32?
Thanks in advance.
This problem may result from inputs being of different data type, since no current XXTEA implementation seems to do any type or range checking.
Or it could be due to different endian behavior of the two computers involved, since binary is typically stored as an array of words constructed from bytes.
Or it could be due to lack of official or standard reference examples for correct encryption of a specific string and key. In the absence of reference examples (using either hexadecimal or base64 conversion of the binary encryption result) there is no way to tell whether an implementation of encryption is correct, even if its results decrypt correctly using a corresponding decryption implementation.
ADDED:
I think I've found one compatibility problem in the published code for XXTEA. It may be worth taking some space here to discuss it.
Specifically, the problem is that different implementations create different results for encrypting the same plaintext and key.
Discussion:
This problem results from the addition of the length of the plaintext as the last element of the array of longs. While this solves the problem of plaintext that has a length that is not a multiple of 4, it generates a different encrypted value than is generated by the JavaScript implementation.
If you insert "$w=false;" at the start of the long2str and str2long functions, the encrypted value for the PHP implementation becomes the same as the JavaScript implementation, but the decrypted value has garbage at the end.
Here are some test case results with this change:
PHP:
text: >This is an example. !##$%^&*(){}[]:;<
Base64: PlRoaXMgaXMgYW4gZXhhbXBsZS4gIUAjJCVeJiooKXt9W106Ozw=
key: 8GmZWww5T97jb39W
encrypt: sIubYrII6jVXvMikX1oQivyOXC07bV1CoC81ZswcCV4tkg5CnrTtqQ==
decrypt: >This is an example. !##$%^&*(){}[]:;<��
Note: there are two UTF-8 question-mark characters at the end of the "decrypt" line.
JavaScript:
text: >This is an example. !##$%^&*(){}[]:;<
Base64: PlRoaXMgaXMgYW4gZXhhbXBsZS4gIUAjJCVeJiooKXt9W106Ozw=
key: 8GmZWww5T97jb39W
encrypt: sIubYrII6jVXvMikX1oQivyOXC07bV1CoC81ZswcCV4tkg5CnrTtqQ==
decrypt: >This is an example. !##$%^&*(){}[]:;<
The reason there is no garbage in the JavaScript implementation even though it does not save the length of the plaintext is given in a comment there: "note running off the end of the string generates nulls since bitwise operators treat NaN as 0". In other words, the generated string is padded with NULs that are never seen, even though JavaScript, like PHP, can include NULs in strings because it stores the length separately.
I don't have an opinion about which approach is best, but one should be chosen for all implementations.
The reason that there should be a standard for the result of encryption (regardless of whether the binary is converted to hex or to base64 for safe transit) is that one might want to use, say, PHP for encoding but JavaScript for decoding, depending on which languages are natural to use at two locations. After all, encryption is most often used to communicate between two locations, and the language used at the target location might not even be known.
Why not using the wificlientsecure library? Works great on the esp32.

Encrypted values (mcrypt_encrypt) in URL parameters generating different results while requesting.How to tackle the situation?

I am using the following function to encrypt a string ($str) using a key ($key) to make a unique key.
Sample Code:
<?php
$key = "####";
$str = "123456789";
$encrypted_key = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $str, MCRYPT_MODE_CBC, md5(md5($key))));
echo $encrypted_key; // 3rfmDKb/Ig5FuUnkY8fiHpqA3FD4PflXMksJw+6WAns=
?>
The function is returning values consisting special characters including '+' . I am storing this values in database as a unique ID.
However in certain conditions, I need to pass the $encrypted_key through URLs . i.e; for using it with RESFful web services
Sample URL:
www.example.com/index.php?encrypted_key=3rfmDKb/Ig5FuUnkY8fiHpqA3FD4PflXMksJw+6WAns=
But this when requested through URL will decode '+' into 'spaces'
Code:
echo $encrypted_key = $_REQUEST['encrypted_key'];
// 3rfmDKb/Ig5FuUnkY8fiHpqA3FD4PflXMksJw 6WAns=
This conversion is further affecting the DB checks :
'3rfmDKb/Ig5FuUnkY8fiHpqA3FD4PflXMksJw 6WAns=' against '3rfmDKb/Ig5FuUnkY8fiHpqA3FD4PflXMksJw+6WAns='
Also I am having a concern of storing these encrypted values into indexed MySQL DB columns.
What should be the best practice to be adopted here? Any advise will be highly appreciated.
This answer only addresses the representation, not the likely-to-be-wrong use of crypto.
When you build objects that have special representation rules like database queries, paths in URLs, HTML code, JS code, and so on, you must ensure that you perform the proper kind of encoding of the values so that they roundtrip without harm.
For database query parameters, do not use string concatenation. Use prepared statements and placeholders.
For URLs, use the proper URL encoding function or an URL builder to construct your URL, do not blindly concatenate strings.
First, is not a good idea to use encrypted values as Unique ID or as Conditional Field, because they will change for the same value. This is very commom in encryption. If an encryption algorithm don't change the result for the same entry, it is not a good encryption.
Second, I had the same problem to deal with encryption and URL, and in my case a made my own encryption algorithm, using only valid characters for URL.
It is not dificult to implement an encryption: I used the ASCII code, one simple key, one simple math function, and nothing more. To decryption, I "reversed" the math function.

Validate a string using pack('H*')

I'm working on an encrypted database... I have been using m_crypt functions.. I have sucessfully got my method of encryption/decryption.. But a problem lies with creating my OO class to serve this function.. I have the following:
class Encryption {
public function __construct($Hex = null){
if (isset($Hex)){
if (ctype_xdigit($Hex)){
echo "Is Hex";
}
if (preg_match('~^[01]+$~', $Hex)) {
echo "Is Binary";
}
}
}
}
$key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");
$Class_OO = new Encryption($key);
The echos are for testing purposes.. But I want to validate this as a valid hexidecimal/binary or the datatype this string is.
performing:
print_r($key);
Returns the following:
¼°K~:صGcï¼U«à)ýë®^A~/û*£
But what datatype is this? On the documentation: http://www.php.net/manual/en/function.mcrypt-encrypt.php The line is presented:
convert a string into a key
key is specified using hexadecimal
So my question is what datatype is this? I understand this is in the ASCII range, but that is as far as my knowledge goes.. Furthermore, a successful answer for this will also assist me in creating another key which is not the one specified by the actual documentation
Your $key is the return value from pack, which in this case is a binary string (essentially raw binary values). See the first line in the documentation for the pack() function return value: http://php.net/manual/en/function.pack.php
Pack given arguments into binary string [emphasis added] according to format.
You would normally base64 encode a binary string before attempting any kind of output, because by definition, a binary string may (and often does) include non-printable characters, or worse - terminal control/escape sequences which can hose up your screen.
Think of it like printing a raw Word or Excel file: you'll probably see recognizable values (although in this case occasional alpha-numerics), but lots of garbage too.
Base64 encoding is a technique to inspect these strings in a safe way.
But what your question implies is that you are very much entering this territory new. You should probably take a look at the Matasano crypto tutorial here: http://www.matasano.com/articles/crypto-challenges/. It is an excellent starting point, and completing exercise #1 in it (maybe 20 minutes of work) will shed complete light on your question above.
In response to your question.. The only viable viable datatype this is submitted in is a string. As you said in your comment:
I have figured using the IV functions of mcrypt then using bin2hex,
using this in the second param of the pack function seems to work
without a fail.. BUT, my overall question is how to validate:
¼°K~:صGcï¼U«à)ýë®^A~/û*£ down to a specific datatype
You have answered how to create an acceptable format for the pack('H*') but as far as validation goes:
if (is_string($Var)){
}
Is the way to go, as this is how it's submitted. It's not a bool, hex, binary, int.. So the only valid method of validating is to validate it as a string.

php encode string and vice-versa

I have some entities(objects), each one having an id(unique) and a name.
When i want to display oneof these , i have a url like www.domain.com/view/key:xxx.
The key is just the id of the entity encoded with base64_encode, so it's not straightforward from the url what the id is.
What i'm trying to do now (due to the projects specifications) is have the key contain only numbers and letters (base64_encode provides a result like eyJpZCI6IjM2In0= or eyJpZCI6IjM2In0%3D after url encode).
Is there a simple alternative to this? It's not a high-security issue - there are many ways the id can be revealed -, i just need to have a key that contains only letters and numbers that is produced by the entity ID (maybe in combination with its name) that can be decoded to give me the ID back.
All different encode methods i've found can contain special characters as well.
Any help here?
Thanks in advance
This answer doesn't really apply encryption, but since your question was tagged with encoding as well ...
Since PHP 5 you can use bin2hex:
$s = base64_decode('eyJpZCI6IjM2In0=');
echo bin2hex($s);
Output:
7b226964223a223336227d
To decode:
$s = hex2bin($data);
Or:
$s = pack('H*', $data);
Btw, if the id is sensitive you might want to consider tamper proofing it as an alternative to full-blown encryption.
Forgot to mention how you can make base64 encoded data URL safe:
function base64_url_encode($input)
{
return strtr(base64_encode($input), '+/=', '-_,');
}
function base64_url_decode($input)
{
return base64_decode(strtr($input, '-_,', '+/='));
}
There are many PHP encoding/decoding functions.
You can find a lot here and here.
Alternatively just get rid of the = at the end of the base64_encode and add it in the PHP code for base64_decode to find the ID.

PHP short encrypt

I'm using this code:
$url = "http://www.webtoolkit.info/javascript-base64.html";
print base64_encode($url);
But the result is very long: "aHR0cDovL3d3dy53ZWJ0b29sa2l0LmluZm8vamF2YXNjcmlwdC1iYXNlNjQuaHRtbA=="
There is a way to transform long string to short encryption and to be able to transform?
for example:
new_encrypt("http://www.webtoolkit.info/javascript-base64.html")
Result: "431ASDFafk2"
encoding is not encrypting. If you're depending on this for security then you're in for a very nasty shock in the future.
Base 64 encoding is intended for converting data that's 8 bits wide into a format that can be sent over a communications channel that uses 6 or 7 bits without loss of data. As 6 bits is less than 8 bits the encoded string is obviously going to be longer than the original.
This q/a might have what you're looking for:
An efficient compression algorithm for short text strings
It actually links here:
http://github.com/antirez/smaz/tree/master
I did not test it, just found the links.
First off, base64 is an encoding standard and it is not meant to encrypt data, so don't use that. The reason your data is so much longer is that for every 6 bits in the input string, base64 will output 8 bits.
There is no form of encryption that will directly output a shortened string. The result will be just as long in the best case.
A solution to that problem would be to gzip your string and then encrypt it, but with your URL the added data for the zip format will still end up making your output longer than the input.
There are a many different algorithms for encrypting/decryption. You can take a look at the following documentation: http://www.php.net/manual/en/function.mcrypt-list-algorithms.php (this uses mcrypt with different algorithms).
...BUT, you can't force something to be really small (depends on the size you want). The encrypted string needs to have all the information available to be able to decrypt it. Anyways, a base64-string is not that long (compared with really secure salted hashes for example).
I don't see the problem.
Well... you could try using md5() or uniqid().
The first one generate the md5 hash of your string.
md5("http://www.webtoolkit.info/javascript-base64.html");
http://php.net/manual/en/function.md5.php
The second one generates a 13 unique id and then you can create a relation between your string and that id.
http://php.net/manual/en/function.uniqid.php
P.S. I'm not sure of what you want to achieve but these solutions will probably satisfy you.
You can be creative and just do some 'stuff' to encrypt the url so that it is not easy quess able but encode / decode able..
like reverse strings...
or have a random 3 letters, your string encoded with base64 or just replace letters for numbers or numbers for letters and then 3 more random letters.. once you know the recipe, you can do and undo it.
$keychars = "abcdefghijklmnopqrstuvwxyz0123456789";
$length = 2;
$randkey = "";
$randkey2 = "";
for ($i=0;$i<$length;$i++) $randkey .= substr($keychars, rand(1, strlen($keychars) ), 1);

Categories