I am unable to find a method in which I can pass IV(Initialization Vector) to CRYPT facade of Laravel framework in PHP
It appears as if it somehow internally implements it.
If it internally implements this, any way I can get the IV used for a particular encryption ?
$string = 'Some text to be encrypted';
$encrypted = \Illuminate\Support\Facades\Crypt::encrypt($string); // found NO way to pass IV here
$decrypted_string = \Illuminate\Support\Facades\Crypt::decrypt($encrypted);
If you source dive the Encrypter you can see how the encyrpt method works:
public function encrypt($value, $serialize = true)
{
$iv = random_bytes(openssl_cipher_iv_length($this->cipher));
// ... rest of the method
}
So yes, this is internally implemented.
any way I can get the IV used for a particular encryption ?
Looking at the decrypt method:
public function decrypt($payload, $unserialize = true)
{
$payload = $this->getJsonPayload($payload);
$iv = base64_decode($payload['iv']);
// ... rest of the method
}
So it is possible to get the IV used.
Although you'll have to get this out yourself.
Take a look at the Encrypter to see what's going on; vendor/laravel/framework/src/Illuminate/Encryption/Encrypter.php
Related
Good day.
Using the encryption library in CodeIgniter, I can encrypt any string by using $this->encryption->encrypt('string'); and that is the easiest way to encrypt the string. However, this method is not the safest way to secure the data I think so I decided to use salt for better encryption. I read the documentation provided by Codeigniter about the Encryption Library and I don't really understand how encryption and salt really work.
Here is my code for encryption.
<?php
defined('BASEPATH') or exit('No direct script access allowed');
class MyEncryption {
//please do not change or delete this saltKey. "5948356750394856"
private static $saltKey = "5948356750394856";
// ================
public $CI;
function __construct()
{
$this->CI =& get_instance();
$this->CI->load->library('encryption');
}
public function encryptStringWithSalt($string) {
$p = $this->CI->encryption->encrypt(
$string,
$this->encryption_config()
);
return $p;
}
public function decryptEncryptedStringWithSalt($encryptedString) {
return $this->CI->encryption->decrypt(
$encryptedString,
$this->encryption_config()
);
}
private function encryption_config(){
$key = $this->CI->config->item('encryption_key');
$hmac_key = $this->CI->encryption->hkdf(
$key,
'sha512',
MyEncryption::$saltKey,
10,
'authentication'
);
return array(
'cipher' => 'aes-128',
'mode' => 'CTR',
'key' => MyEncryption::$saltKey,
'hmac' => true,
'hmac_digest' => 'sha224',
'hmac_key' => $hmac_key
);
}
}
As we can see, I created a function that gathers the encryption configuration. Inside that function, I have called the method $this->CI->encryption->hkdf() to create hmac key as what documentation example says. For clarification, here are the parameters of hkdf() method and the provided example.
Additionally, the return keyword with array data in encryption_config() function is the 2nd parameter of encrypt() method in encryption library. I used encryption->hkdf() because of the parameter salt on it. I am new in encryption with salt in Codeigniter so I'm really struggling on how to achieve this kind of encryption. So what I've done is that the code above really works for encryption and decryption but for some reason I don't really understand why the return value is different from the normal encryption. The difference is, this encryption method $this->encryption->encrypt("some string"); returns but using the code above returns .
Though I can decrypt that symbolic character, this will not save this encrypted data to the database with the data type of varchar but instead, it will be saved as a normal character or string. Here are the data saved to database .
My questions are, I am doing correctly? if not, what is the proper way to implement this library with salt? I want the encrypted data as normal text not a symbolic character, can I achieve that goal? and lastly? is there anyway to check the string if the string is encrypted or not? Please help me. I spend days for this problem only. I watch youtube tutorial related for encryption but no luck.
Okay. after searching on the internet I found a solution without using this CI encryption Library. I achieved my goal by using this code
<?php
defined('BASEPATH') or exit('No direct script access allowed');
/**
*
*/
class SaltEncryption
{
public $CI;
function __construct()
{
$this->CI =& get_instance();
}
public function encrypt($data){
$password = "any string";
$iv = substr(sha1(mt_rand()), 0, 16);
$password = sha1($password);
$salt = sha1(mt_rand());
$saltWithPassword = hash('sha256', $password.$salt);
$encrypted = openssl_encrypt(
"$data", 'aes-256-cbc', "$saltWithPassword", null, $iv
);
$msg_encrypted_bundle = "$iv:$salt:$encrypted";
return $msg_encrypted_bundle;
}
public function decrypt($msg_encrypted_bundle){
$password = "any string";
$password = sha1($password);
$components = explode( ':', $msg_encrypted_bundle );
if (
count($components)=== 3 &&
strlen($components[0]) === 16
) {
$iv = $components[0];
$salt = hash('sha256', $password.$components[1]);
$encrypted_msg = $components[2];
$decrypted_msg = openssl_decrypt(
$encrypted_msg, 'aes-256-cbc', $salt, null, $iv
);
if ( $decrypted_msg === false )
return false;
$msg = substr( $decrypted_msg, 41 );
return $decrypted_msg;
}
return false;
}
}
PHP version: 5.6.39
Node.js version: 10.9.0
Objective: Encrypt using PHP and decrypt using Node.js
Stuck Point: I'm currently assuming that both the PHP and Node.js bindings to OpenSSL make use of PKCS7 padding. Do PHP and Node.js use incompatible bindings to OpenSSL?
Example PHP encryption/decryption code:
class SymmetricEncryption {
public static function simpleEncrypt($key, $plaintext) {
$iv = openssl_random_pseudo_bytes(16);
$ciphertext = openssl_encrypt($plaintext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv)
return base64_encode($iv) . "." . base64_encode($ciphertext);
}
public static function simpleDecrypt($key, $token) {
list($iv, $ciphertext) = explode(".", $token);
return openssl_decrypt(
base64_decode($ciphertext),
"aes-256-cbc",
$key,
OPENSSL_RAW_DATA,
base64_decode($iv)
);
}
}
Example Node.js encryption/decryption code:
class SymmetricEncryption {
static simpleEncrypt(key: Buffer, plaintext: string): string {
const iv = randomBytes(16)
const cipher = createCipheriv('aes-256-cbc', key, iv)
const encrypted = cipher.update(plaintext)
const token = Buffer.concat([encrypted, cipher.final()])
return iv.toString('base64') + "." + token.toString('base64')
}
static simpleDecrypt(key: Buffer, token: string): string {
const [iv, ciphertext] = token.split(".").map(piece => Buffer.from(piece, 'base64'))
const decipher = createDecipheriv('aes-256-cbc', key, iv)
const output = decipher.update(ciphertext)
return Buffer.concat([output, decipher.final()]).toString('utf8')
}
}
I've tested each implementation independently of one another successfully, but when encrypting in PHP and decrypting in node.js I get the following error:
Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
The stack trace points me to the offending line, which is decipher.final() in the simpleDecrypt method.
I'm using the following (failing) unit test to verify my implementation
it('should be able to decrypt values from php', () => {
const testAesKey = Buffer.from('9E9CEB8356ED0212C37B4D8CEA7C04B6239175420203AF7A345527AF9ADB0EB8', 'hex')
const phpToken = 'oMhL/oIPAGQdMvphMyWdJw==.bELyRSIwy+nQGIyLj+aN8A=='
const decrypted = SymmetricEncryption.simpleDecrypt(testAesKey, phpToken)
expect(decrypted).toBe('hello world')
})
The phpToken variable I'm using here was created using the following code:
$testAesKey = "9E9CEB8356ED0212C37B4D8CEA7C04B6239175420203AF7A345527AF9ADB0EB8";
echo SymmetricEncryption::simpleEncrypt($testAesKey, "hello world");
I suspect your issue is caused by how you pass your key in PHP. The documentation for openssl_encrypt doesn't specify anywhere that it interprets the key as hex. It does, however, truncate keys that are too long.
What is likely happening here is PHP is truncating your 64 character hex string down to 32 bytes, and using those for the key. Try using hex2bin on your PHP key before using it - this should fix your issue!
$testAesKey = hex2bin("9E9CEB8356ED0212C37B4D8CEA7C04B6239175420203AF7A345527AF9ADB0EB8");
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'm kind of new to ActionScript 3 at the moment and been trying to use the as3crypto library to encrypt some data with the blowfish algorithm before submitting it to the server for processing. I know you can use https, but most browsers still display the outbound data making it very easy for a user to fake a request. That's why I want to let the user see the page request, but not be able to read the data without decrypting.
Unfortunately for me the deocumentation on the as3crypto library is pretty much non existent aside from comments in the code (which don't help too much). I've set up the flash side of things with a couple static functions to "implement" the as3crypto blowfish encryption and they work fine for encrypting/decrypting within flash only. The problem comes when I try to use the key to decrypt in PHP using the mcrypt library. The output I get is not the original code and I've spent a couple days trying to figure out why to no avail.
Below is the code and explanations. For purposes of this example, the key used was 'mykey' (without the quotes) and the encoded data was 'Hello World' (again without the quotes).
Flash code (as3crypto blowfish helper):
package lib.ef.crypto
{
import com.hurlant.util.Base64;
import com.hurlant.crypto.Crypto;
import flash.utils.ByteArray;
import com.hurlant.crypto.symmetric.IPad;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.NullPad;
public class Blowfish
{
/**
* Encrypts a string.
* #param text The text string to encrypt.
* #param key A cipher key to encrypt the text with.
*/
static public function encrypt($text:String, $key:String=""):String
{
var cryptKey:ByteArray = new ByteArray();
cryptKey.writeUTF( $key );
var iPad:IPad = new NullPad();
var crypt:ICipher = Crypto.getCipher('blowfish-cfb',cryptKey,iPad);
iPad.setBlockSize( crypt.getBlockSize() );
var cryptText:ByteArray = new ByteArray();
cryptText.writeUTF( $text );
crypt.encrypt( cryptText );
trace( Base64.encodeByteArray( cryptText ) );
return null;
}
static public function decrypt($text:String, $key:String=""):String
{
return new String();
}
}
}
The output of that varies from run to run, but for the purpose of this example run, the base64 encoded output I get is 'EkKo9htSJUnzBmxc0A=='
When I bring that code into PHP it is base64 decoded before being passed into the method below to decrypt it:
public static function decrypt($crypttext,$key)
{
if( !function_exists('mcrypt_module_open') ) trigger_error('The blowfish encryption class requires the Mcrypt library to be compiled into PHP.');
$plaintext = '';
$td = mcrypt_module_open('blowfish', '', 'cfb', '');
$blocksize = mcrypt_enc_get_block_size($td);
$iv = substr($crypttext, 0, $blocksize);
$crypttext = substr($crypttext, $blocksize);
if (true)
{
mcrypt_generic_init($td, $key, $iv);
$plaintext = mdecrypt_generic($td, $crypttext);
}
return $plaintext;
}
At this point the output is completely unreadable. I suspect the issue may be related to the fact that either the as3crypto implementation of blowfish isn't correct (unlikely) or it could be something to do with the padding it uses (currently null padding) or lastly I've thought it may have something to do with the randomly generated initialization vector in as3crypto not being prepended to the front of the encoded string? That last one I haven't been able to really test because the as3crypto library is large, complicated, and not documented much at all. I've googled this issue and tested everything for a couple days now and I just keep coming up with unusable data in PHP. I know if I can get the Flash to PHP system working, I can reverse engineer it to get the PHP to Flash encryption running as well.
I welcome all input on this matter as it's actually been costing me sleep at night lol Thank you in advance :)
I've done some further testing today and attempted to see if it was the initialization vector as I suspected. I don't believe that's the problem. I modified some things in flash so that I could get an output of the IV used to generate the encoded output:
package lib.ef.crypto
{
import com.hurlant.util.Base64;
import com.hurlant.crypto.Crypto;
import flash.utils.ByteArray;
import com.hurlant.crypto.symmetric.IPad;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.NullPad;
public class Blowfish
{
/**
* Encrypts a string.
* #param text The text string to encrypt.
* #param key A cipher key to encrypt the text with.
*/
static public function encrypt($text:String, $key:String=""):String
{
var cryptKey:ByteArray = new ByteArray();
cryptKey.writeUTF( $key );
var iPad:IPad = new NullPad();
var crypt = Crypto.getCipher('blowfish-cfb',cryptKey,iPad);
iPad.setBlockSize( crypt.getBlockSize() );
var cryptText:ByteArray = new ByteArray();
cryptText.writeUTF( $text );
crypt.encrypt( cryptText );
cryptText.position = 0;
var iv:ByteArray = crypt.IV;
iv.position = 0;
trace( Base64.encodeByteArray( iv ) );
trace( Base64.encodeByteArray( cryptText ) );
return null;
}
static public function decrypt($text:String, $key:String=""):String
{
return new String();
}
}
}
For this example I got an encoded IV of '1bcGpqIbWRc=' and encoded encrypted data of 'XpgART3hNQO10vcgLA==' I plugged those into a modified PHP function after base64_decode() ing them:
public static function decrypt($crypttext,$key,$iv=NULL)
{
if( !function_exists('mcrypt_module_open') ) trigger_error('The blowfish encryption class requires the Mcrypt library to be compiled into PHP.');
$plaintext = '';
$td = mcrypt_module_open('blowfish', '', 'cfb', '');
if( $iv === NULL ){
$ivsize = mcrypt_enc_get_iv_size($td);
echo '<pre>'.$ivsize.'</pre>';
$iv = substr($crypttext, 0, $ivsize);
echo '<pre>'.strlen($iv).'</pre>';
$crypttext = substr($crypttext, $ivsize);
}
if ($iv)
{
mcrypt_generic_init($td, $key, $iv);
$plaintext = mdecrypt_generic($td, $crypttext);
}
return $plaintext;
}
Even this output is incorrect. I've done some tests to make sure the IV is the correct size both in flash and PHP, but for some reason the PHP side of things just can't decrypt the blowfish encoded output from Flash. I've tried using both NULL and PKCS5 padding in as3crypto and neither works with PHP's system. I've tested to make sure the IV strings are the same in both Flash and PHP. They're both using the same keys. Both are using CFB mode. I don't get it. Same algorithm, same key, same IV, same mode, but they can't decrypt from each other. It's seeming to me that the as3crypto implementation of blowfish may be incorrect. Can anyone confirm this?
After doing some digging through the as3Crypto library files and demo code, I found that the problem is I need to use the getCipher function with simple-blowfish-cfb mode instead of blowfish-cfb mode. The encrypted output from calling crypt.encyrpt( cryptText ) will then be already prefixed with the IV of the algorithm so you make a single call to Base64.encodeByteArray( cryptText ) to get the output to send to PHP. When you initialize PHP the way I have above, it will slice off the IV from the string and decrypt properly. Hopefully this helps anyone else who comes along with this problem.
The "correct" flash and PHP code* is below for all you TLDR;ers who just want a quick copy/paste solution :P
*Note: I had to remove some of my application specific calls in both code samples and did not test them to insure they're 100% functional, but they should illustrate the concept/structure enough that if they don't work correctly "out of the box" you can easily mend them for your use.
PHP "helper" class:
class Blowfish
{
public static function encrypt($plaintext,$key)
{
if( !function_exists('mcrypt_module_open') ) trigger_error('The blowfish encryption class requires the Mcrypt library to be compiled into PHP.');
$td = mcrypt_module_open('blowfish', '', 'cbc', '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$crypttext = mcrypt_generic($td, $plaintext);
mcrypt_generic_deinit($td);
$out = $iv.$crypttext;
return $out;
}
public static function decrypt($crypttext,$key)
{
if( !function_exists('mcrypt_module_open') ) trigger_error('The blowfish encryption class requires the Mcrypt library to be compiled into PHP.');
$plaintext = '';
$td = mcrypt_module_open('blowfish', '', 'cbc', '');
$ivsize = mcrypt_enc_get_iv_size($td);
$iv = substr($crypttext, 0, $ivsize);
$crypttext = substr($crypttext, $ivsize);
if ($iv)
{
mcrypt_generic_init($td, $key, $iv);
$plaintext = mdecrypt_generic($td, $crypttext);
}
return $plaintext;
}
}
Flash "helper" class:
package [your package name]
{
import com.hurlant.util.Base64;
import com.hurlant.util.Hex;
import com.hurlant.crypto.Crypto;
import flash.utils.ByteArray;
import com.hurlant.crypto.symmetric.IPad;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.IVMode;
import com.hurlant.crypto.symmetric.NullPad;
public class Blowfish
{
/**
* Encrypts a string.
* #param txt The text string to encrypt.
* #param k A cipher key to encrypt the text with.
*/
static public function encrypt(txt:String, k:String=""):String
{
var kdata:ByteArray;
kdata = Hex.toArray(Hex.fromString(k));
var data:ByteArray;
data = Hex.toArray(Hex.fromString(txt));
var pad:IPad = new NullPad;
var mode:ICipher = Crypto.getCipher('simple-blowfish-cbc', kdata, pad);
pad.setBlockSize(mode.getBlockSize());
mode.encrypt(data);
return Base64.encodeByteArray( data );
}
/**
* Decrypts a string.
* #param txt The text string to decrypt.
* #param k A cipher key to decrypt the text with.
*/
static public function decrypt(txt:String, k:String=""):String
{
var kdata:ByteArray;
kdata = Hex.toArray(Hex.fromString( Base64.decode( k ) ));
var data:ByteArray;
data = Hex.toArray(Hex.fromString(txt));
var pad:IPad = new NullPad;
var mode:ICipher = Crypto.getCipher('simple-blowfish-cbc', kdata, pad);
pad.setBlockSize(mode.getBlockSize());
mode.decrypt(data);
data.position = 0;
return data.readUTFBytes( data.bytesAvailable );
}
}
}
Thanx!
See here the correct "decrypt":
static public function decrypt(txt:String, k:String=""):String{
var kdata:ByteArray;
kdata = Hex.toArray(Hex.fromString(k));
var data:ByteArray;
data = Base64.decodeToByteArray(txt);
var pad:IPad = new NullPad;
var mode:ICipher = Crypto.getCipher('simple-blowfish-cbc', kdata, pad);
pad.setBlockSize(mode.getBlockSize());
mode.decrypt(data);
data.position = 0;
return data.readUTFBytes( data.bytesAvailable );
}
I cannot get an encryption class to work (it's in a seperate file in the classes folder). The code for the class is:
class SymmetricCrypt
{
// Encryption/decryption key.
private static $msSecretKey = "Hello";
// The initialisation vector.
private static $msHexaIv = "c7098adc8d6128b5d4b4f7b2fe7f7f05";
// Use the Rijndael Algorithm.
private static $msCipherAlgorithm = MCRYPT_RIJNDAEL_128;
public static function Encrypt($plainString)
{
$binary_iv = pack("H*", SymmetricCrypt::$msHexaIv);
// Encrypt source.
$binary_encrypted_string = mcrypt_encrypt(SymmetricCrypt::$msCipherAlgorithm, SymmetricCrypt::$msSecretKey, $plainString, MCRYPT_MODE_CBC, $binary_iv);
// Convert $binary_encrypted_string to hexadeciaml format.
$hexa_encrypted_string = bin2hex($binary_encrypted_string);
return $hexa_encrypted_string;
}
public static function Decrypt($encryptedString)
{
$binary_iv = pack("H*", SymmetricCrypt::$msHexaIv);
// Convert string in hexadecimal to byte array.
$binary_encrypted_string = pack("H*", $encryptedString);
// Decrypt $binary_encrypted_string,
$decrypted_string = mcrypt_decrypt(SymmetricCrypt::$msCipherAlgorithm, SymmetricCrypt::$msSecretKey, $binary_encrypted_string, MCRYPT_MODE_CBC, $binary_iv);
return $decrypted_string;
}
}
This is how I am calling the class:
require_once 'classes/symmetric_crypt.php';
$sc = new SymmetricCrypt();
$password = "password";
$ec_password = $sc->Encrypt($password);
... insert into database.
If I echo the contents of $password, then it displays "password". If I echo $ec_password, it returns nothing.
I've used it before on a different project on a different server. Could it be something server-related? Any other ideas?
Thanks,
Adrian
Works here.
Two notes:
Your initialization vectors should not be reused. Otherwise, it gets easier to find the encryption key (see WEP).
Like premiso saids, you should not stored store passwords as decryptable strings. Use salted hashes with strong hash functions (not MD5!).