I am implementing a reversible encryption algorithm based on an example at http://www.edzynda.com/create-a-self-destructing-encrypted-message-app-in-laravel-part-1/
I have put the code inside a model event function:
public static function boot()
{
parent::boot();
// Setup event bindings...
static::creating(function($account)
{
/* encrypt password and save iv */
$encryption = self::encrypt($account->db_password); // or: Input::get('db_password')
$account->db_password = $encryption['encrypted_string'];
$account->iv = $encryption['iv'];
Log::debug($account);
//print_r ($encryption);
});
}
public static function encrypt($string)
{
// Generate an IV
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CFB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM);
// Encrypt the string
$encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $_ENV['ACCOUNT_KEY'], $string, MCRYPT_MODE_CFB, $iv);
return ['encrypted_string' => $encrypted_string, 'iv' => $iv];
}
In my database seeder, I am calling Model::create to make the string is encrypted before saving. This is called from my tests. However, I am getting
[ErrorException]
json_encode(): Invalid UTF-8 sequence in argument
I've made sure that the column type is binary.
Extra info: when I perform mb_detect_encoding on either value ($iv or $string) I get either UTF-8, or nothing, I guess depending not the random characters that appear in the result.
My solution: for storage and transportation, the encrypted string and IV need to be base64 encoded.
The relevant line above changed to:
return [
'encrypted_string' => base64_encode($encrypted_string),
'iv' => base64_encode($iv)
];
and of course base64_decode must be used before decrypting the string with the stored IV value.
Related
I'm using a function to encode and decode some text ,
But seems it doesn't support my country language (Persian) and change them to some unreadable text, How can i fix it .
<?php
class encrypt {
/********* Encode *********/
public static function encode($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, md5(base64_encode(trim($encryption_key))), utf8_encode(trim($pure_string)), MCRYPT_MODE_ECB, $iv);
return base64_encode($encrypted_string);
}
/********** Decode ************ */
public static function decode($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, md5(base64_encode(trim($encryption_key))),base64_decode(trim($encrypted_string)), MCRYPT_MODE_ECB, $iv);
return $decrypted_string;
}
}
?>
The same IV needs to be used for encryption and decryption, a general method is to prefix the encrypted data with the IV for use during decryption.
There is no need to Base64 encode or trim the encryption key.
Do not trim the encrypted data, encrypted data can contain null (0x00) bytes.
Encryption operates on bytes, not characters, as such any text language makes no difference.
Adding calls inline to other calls just makes debugging more difficult, separate the steps into separate statements with intermediate variables.
Do not use Blowfish, use AES, even the creator of Blowfish uses AES.
Do not use ECB mode, it is insecure, see ECB mode, scroll down to the Penguin.
ECB mode does not use an IV.
What you are doing is encryption, not encoding.
Consider using defuse or RNCryptor, they provide a complete solution and are being maintained.
How can i decrypt a string which has been encrypted using the Laravel 4 Encrypt class, outside of Laravel, only with PHP?
The Laravel Encrypter class uses Rijndael with a block size of 256 bit for encryption which is provided by the Mcrypt PHP extension. The Encrypter class works using two simple methods, encrypt() and decrypt().
An example below:
<?php
$secret = Crypter::encrypt('some text here'); //encrypted
$decrypted_secret = Crypter::decrypt($secret); //decrypted
?>
Since you're asking how to do it "outside of Laravel":
The encryption and decryption is done by the encrypter class. Laravel source is public and here's the relevant part:
<?php
public function encrypt($value)
{
$iv = mcrypt_create_iv($this->getIvSize(), $this->getRandomizer());
$value = base64_encode($this->padAndMcrypt($value, $iv));
$mac = $this->hash($iv = base64_encode($iv), $value);
return base64_encode(json_encode(compact('iv', 'value', 'mac')));
}
protected function padAndMcrypt($value, $iv)
{
$value = $this->addPadding(serialize($value));
return mcrypt_encrypt($this->cipher, $this->key, $value, $this->mode, $iv);
}
public function decrypt($payload)
{
$payload = $this->getJsonPayload($payload);
$value = base64_decode($payload['value']);
$iv = base64_decode($payload['iv']);
return unserialize($this->stripPadding($this->mcryptDecrypt($value, $iv)));
}
protected function mcryptDecrypt($value, $iv)
{
return mcrypt_decrypt($this->cipher, $this->key, $value, $this->mode, $iv);
}
?>
For documentation and comments, see Laravel source code on GitHub.
I hope this helps.
The Encrypter class of Laravel is prone to changes. This is due to some security vulnerabilities that got fixed. So to successfully decrypt you need to do the following things:
Get the right source code, e.g. for 4.2.16;
Get it to work on your machine. Make sure you run on the same PHP environment (using OpenSSL extensions for the latest versions);
Instantiate the class in Encrypter with the correct key, and possibly set the correct mode and algorithm;
Finally, call decrypt.
All other required parameters for decryption (IV and MAC value) should be contained within the ciphertext.
I am using a text
const ENCRYPTION_KEY = '3aa22e01c04c7059778c54d122b0273689fba00f4a166a66d15f7ba6a8ba8743';
$str = "1844427316My Name Is Dave1336407610774000000000000";
function encrypt($str){
trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128,ENCRYPTION_KEY, $str,MCRYPT_MODE_CBC,mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128,MCRYPT_MODE_CBC),MCRYPT_RAND))));
}
function decrypt($encryptedtext){
return trim(
mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
ENCRYPTION_KEY,
base64_decode($encryptedtext),
MCRYPT_MODE_CBC,
mcrypt_create_iv(
mcrypt_get_iv_size(
MCRYPT_RIJNDAEL_128,
MCRYPT_MODE_CBC
),
MCRYPT_RAND
)
)
);
}
But whenever I refresh the page calling these function with values mentioned above, I get different values encryption, but in decryption, the initial decrypted value changes everytime but rest gets decrypted correctly like wise:
F7…Ÿ{4©eŠQ9t¤e Is Dave1336407610774000000000000
I have also refered the SIMILAR QUESTION and used the "iv" function in decryption as well as answered in it
Could some one guide me whats getting wrong in here?
It was thoughtful But I found the Solution:
While decrypting, I used the same IV and key as when encrypting.
My encrypt function needs to return the IV as well as the encrypted data. That IV is sent to the decrypt function with the data and the key.
See the below Change in Code with complete code:
class Encypt{
const ENCRYPTION_KEY = '3aa22e01c04c7059778c54d122b0273689fba00f4a166a66d15f7ba6a8ba8743';
function createQueryString(){
$str = "1844427316My Name Is Dave1336407610774000000000000";
$encStr = $this->encrypt($str);
return $encStr;
}
function encrypt($strValue){
$iv =mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128,MCRYPT_MODE_CBC),MCRYPT_RAND);
$encData = trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128,self::ENCRYPTION_KEY, $strValue,MCRYPT_MODE_CBC,$iv)));
$data['iv'] = $iv;
$data['encdata'] = $encData;
return $data;
}
/**
* Function to decrypt data using AES Encryption Symmetric Algorithm 128 bytes
*/
function decrypt($strValue, $iv){
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128,ENCRYPTION_KEY,base64_decode($strValue),MCRYPT_MODE_CBC,$iv));
}
}
$enc_obj = new Encypt();
$encstr = $enc_obj->createQueryString();
echo "Encrypted Str:-->".$encstr['encdata']."<br>";
$deCrypt = $enc_obj->decrypt($encstr['encdata'], $encstr['iv']);
echo "Decrypted Str:-->".$deCrypt;
These days I read a lot here on SO about password hashing and data encryption. It's a real mess, I mean, deciding what the best practice is. I need a very simple class that can be reused anywhere and that provide a decent-but-not-paranoic security level for my PHP applications (I do not handle bank data). Additionally, I want to rely as much as possible on PHP standard libs. I came up with this:
class Security {
public static function hashPassword($plain) {
$salt = md5(rand(0, 1023) . '#' . time()); // Random salt
return crypt($plain, '$2a$07$' . $salt); // '$2a$07$' is the Blowfish trigger
}
public static function checkPassword($plain, $hash) {
return (crypt($plain, $hash) === $hash);
}
public static function generateIv() {
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC); // It's 32
return mcrypt_create_iv($iv_size, MCRYPT_RAND);
}
public static function encrypt($key, $data, $iv = null, $base64 = true) {
if (is_null($iv)) $iv = md5($key);
$ret = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_CBC, $iv);
return ($base64 ? base64_encode($ret) : $ret);
}
public static function decrypt($key, $data, $iv = null, $base64 = true) {
if (is_null($iv)) $iv = md5($key);
return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $base64 ? base64_decode($data) : $data, MCRYPT_MODE_CBC, $iv), "\0");
}
}
As you can see, I choose to hash passwords with crypt() using Blowfish hashing algorithm. The return value of hashPassword() is the salt + hash that then I store in the DB. I made this choice because crypt() is available on every server, provides a confortable way to check hash regardless of algorithm used (it's based on salt prefix) and, I read, bcrypt is a decent hashing method.
Then, for data encryption I used mcrypt() Rijndael 256 algorithm with CBC mode. As you can see, I can use encryption methods in two way. I can pass a IV (and generateIv() helps me to create one) that I will store in the DB along crypted data, or, if I don't, a basic IV is derived from key in both crypt and decrypt process.
What do you think about it? Am I missing something? Can I be finally relaxed about hashing and encryption in my PHP aplications?!?
You are using Rijndael 256 bit encryption, which is not AES standard. Try to use AES (MCRYPT_RIJNDAEL_128) using 256 bit keys instead.
A random IV should be kept with cipher text if the derived key is also used to encrypt other data.
You are using out of date functions, you might want to use bcrypt and SHA-256 for the IV (only use the 16 - blocksize - left most bytes) .
Note that this list may not be complete.
I have a problem with CBC mode when I try to encrypt/decrypt some text using php's mcrypt extension. I've created a class to perform this operations, it works fine with other modes but CBC.
The problem is as follow:
I use the clear text Even in cryptography, silence is golden. I do the encryption part, no problem till this point. But each time I try to decrypt, I get something like this: 9��'t"�cryptography, silence is golden. As you can see, the first 8 characters of the text are wrong. I don't know what may be causing this behavior.
The parts of my class which handle these operations are:
public function encrypt($data)
{
$cypher = $this->_getCypher();
$iv = $this->_getIv($cypher);
return trim(base64_encode(mcrypt_encrypt($cypher, self::KEY, $data, MCRYPT_MODE_CBC, $iv)));
}
public function decrypt($data)
{
$cypher = $this->_getCypher();
$iv = $this->_getIv($cypher);
return trim(mcrypt_decrypt($cypher, self::KEY, base64_decode($data), MCRYPT_MODE_CBC, $iv));
}
protected function _getCypher()
{
return self::$_cyphers[$this->_algorithm];
}
protected function _getIv($cypher)
{
return mcrypt_create_iv(mcrypt_get_iv_size($cypher, MCRYPT_MODE_CBC), MCRYPT_RAND);
}
And the algorithm used for above example is 3DES. As I said before, using other mode, such as ECB, everything works fine.
Any suggestions ?
You need to remember the IV that you used for encryption and use that again for decryption.