Zend Framework Encrypt Decrypt Online
How do I encrypt data in PHP, properly, using symmetric-key encryption? I have a message M and a secret S. I'm looking for a solution that uses cryptography properly without making any of the usual mistakes. In particular, the solution should use authenticated encryption, choose IVs properly, and generate the actual encryption key from the secret S using a suitable slow hash (in case S happens to be a password instead of an actual cryptographic key). Can you suggest PHP code for this purpose? My motive: I'd like to give PHP programmers good advice on how to do this, not bad advice. Is a real disappointment: it is full of highly-upvoted answers that are appallingly bad (ECB mode encryption?
Repeating IVs? Encryption without authentication?). Let's figure out the right answer -- a code snippet that does things right -- and then go fix that broken window on StackOverflow. In keeping with the PHP programmer ethos, I'd prefer a snippet of code (that works for as many settings as possible; possibly with explanation and/or explanation of limitations/caveats) instead of just advice about algorithms and concepts.
Dezender decrypt zend encryption php. Allow you to decode zend, ioncube and. By.end to end encryption with zend framework 3. Be used to implement end to end. Zend Encrypt and Decrypt. Browse other questions tagged php security encryption zend-framework cryptography or ask your own question.
I think your question has more to do with how do I change the PHP community to understand the importance of understanding choosing the right cryptography and what the various modes of an algorithm mean. The reason they chose and upvoted the ECB mode was because it was the easiest, and it worked. Whose to say that if you give a good example with one of the feedback modes that anyone would understand the implications of why it's better?
I think the code is really the unimportant part, and that sort of 'copy/paste' mentality is the real culprit destroying security. – Feb 4 '15 at 23:48. Can you suggest PHP code for this purpose?
In order of preference. PECL Libsodium If you haven't heard of libsodium,. I very strongly if possible. Should get you started with installing libsodium and the PECL extension on your computer. The rest of that e-book should give you an understanding of how to use specific components, and contains plenty of example code. If you need a starting point for PHP cryptography to point non-experts to, libsodium is the best available today.
For secret-key authenticated encryption, refer to. Paragonie/halite (Disclaimer: I wrote Halite.) All the power of libsodium, and an interface that looks like: use ParagonIE Halite Symmetric Crypto as Symmetric; $key = KeyFactory::loadEncryptionKey('/path/to/key/file'); $ciphertext = Symmetric::encrypt($plaintext, $key); Check it out:. Defuse/php-encryption Defuse Security published an encryption* library on Github. Thank you for sharing your code! It requires two separate passphrases, which is unrealistic. Instead, you should derive all the keys from a single passphrase: perform a slow hash of the passphrase, then generate your encryption key and authentication key from that (e.g., if p is the passphrase and h is a slow hash like PBKDF2 or scrypt, set k = h(p), then use E_k(0),E_k(1) as the encryption key and E_k(2),E_k(3) as the authentication key, where E is AES ECB encryption). – Sep 12 '15 at 23:54 2.
@D.W., I'd like to better understand what you're saying. Can you give a PHP sample for deriving the two keys? I think I follow you but I'm sketchy on proper terminology. I'm just not seeing the need for a slow hash in these circumstances and I'd like to understand. The primary use of a slow hash, as I understand it, is for something like a large number of stored passwords. With individual salts, each hash must be attacked individually, and the slow hash makes the time factor prohibitive. In this case we are not storing the hashed result so there is nothing to attack.
– Sep 13 '15 at 0:06 1. D.W., the answer needs to come more in the form of a Design Pattern than a code snippet. One reason for this is the state of the art with PHP and the PHP community. There are precious few examples of 'getting it right' that are available to average PHP developers. Examples of this difficulty: •: mycrypt, as of last time I looked, is no longer maintained and is effectively abandoned. However, mycrypt is the extension able to obtain random numbers from /dev/urandom, which does appear to be the right way to do it on Linux-based servers.
•: PHP's openssl extension gets it wrong. Openssl is the extension to use for new development, but it doesn't get everything right.
This brings us to the conclusion that we need to create our own cryptography code. Any expert will tell us, 'Don't do that!' But with PHP there may not be an alternative. There are community-provided crypto packages, but it's the same issue: How do we know if that package 'gets it right?'
The other reason is that, with PHP, the question comes up because of a specific situation. Are you trying to store hashed passwords across an insecure network?
One set of protocols might be best. Are you trying to secure web services between your server and your mobile app? A different approach may be more appropriate.
(For example, can you depend on the app keeping a secret key secret, when the app can be reverse-engineered by an attacker?) For the record, here are the steps I considered with symmetric secret-key encryption. I am using PHP 5.3, the mcrypt extension for access to /dev/urandom, and openssl for aes-256-cbc. • Recognize that everything depends on keeping the secret key secret. If the secret keys can be extracted from the remote client software (or from either endpoint of your communication), an attacker with access to the encrypted text can read anything and everything, and insert spurious messages. • Recognize that transmitting over HTTPS, for example, provides insufficient security against some attacks. For example, an attacker can install our app and observe decrypted HTTPS traffic being sent/received to/from our app. • In other words, understand the environment in which your encryption is operating, and find out what attacks must be considered.
• Both sides of the encryption need the same shared secret key. Both sides need to obtain the key, and both need to keep the key from being stolen, seen, reverse engineered, etc. • I believe (but lack sufficient expertise to be sure) that it's correct practice to hash your secret key to exactly 256 bits (for AES-256), e.g., use hash('sha256', $secretKey) to create the 256-bit key to feed into the encrypt/decrypt function.
In other words, plain ASCII text as-is doesn't have enough entropy to be directly used as the secret key. So, use a hash function creating (or being truncated to) the correct number of bytes. • For AES, you need a 128-bit input vector. Understand that this input vector needs to be different for every encryption/transmission. I have seen too many code samples with a fixed input vector! Use mcrypt with mode MCRYPT_DEV_URANDOM for the random bytes. • *thanks @mti2935) states that, if you perform ANY cryptographic operation on the received message before verifying its integrity, it will SOMEHOW inevitably lead to doom.
One best practice is to use the HMAC (the next point). • (not enough reputation to post the link): Understand that Encryption is not Authentication.
The HMAC can only verify that the message has not been altered. It also verifies that the message was sent by someone possessing your secret key. You may or may not consider that fact to be sufficient authentication. • The HMAC must cover ALL inputs to your decryption function. That means both the encrypted message AND the input vector. If you have some identifier showing which decryption algorithm to use, THAT must also be part of the HMAC calculation.
Otherwise, the attacker could change that indicator and mount certain attacks, and your HMAC validation will still appear clean. • The above is the 'encrypt-then-HMAC' school of thought. There are opposing schools of thought, notably including Bruce Schneier. Bruce's reasoning is that it's notably difficult to get 'encrypt-then-HMAC' right.
If Bruce says it's notably difficult, it's notably difficult. My point is that if you are encrypting and HMAC'ing, in whatever order, FIND OUT what is so difficult to get right, and get concurrence that you got it right. This is an interesting discussion.
However, I wasn't looking for principles or concepts or ideas or a design. I was looking for specific code that I can recommend to PHP developers. I already understand the principles and already present the outline of a specific design in the question. It sounds like you might have some of the pieces, but you miss a few of the requirements in the question: item 5 fails to use a slow hash; item 8 doesn't describe how to compute a HMAC in PHP; we need a code snippet for key derivation (deriving multiple independent keys from a passphrase).
– Sep 12 '15 at 3:39 2. What do you mean by protecting the IV? It should be unique and it should not be reused. That are the requirements of an IV in CBC mode.
So what do you mean exactly. Furthermore you are talking about timing attacks for string comparison.
Well, I'm no expert in that particular field, so please enlighten me how it should be done instead. I mean it's not that I did not expect downvotes, but instead you could just be a little bit more precise and help to actually increase the quality of the answer. I think it's at least a good starting point and I don't claim a perfect solution, yet. – Mar 9 '15 at 10:40 1.
During a recent project, the client requested that uploaded files be encrypted for security reasons. As I already had the uploaded code ready and tested I just needed to add some extra encryption capability to the code.
As earlier I’d encountered Zends wonderful class, I decided to go with it and use the Zend_Filter_Encrypt and Zend_Filter_Decrypt to accomplish the work. The Zend_Filter component provides a set of common useful data filters, among which are the encryption filters. Although my project was not developed in Zend, I could easily integrate the required classes in the code. Note that Zend has a great upload library,, that lets you easily manage file uploading and also encryption, but as I already had the upload code tested, I decided to just add the encryption part. Downloading the Zend framework As the following code requires the Zend framework make sure you it first.
For this code I used Zend 1.11.0 Full version. You can also download the required files at the end of this post. Which Zend framework files do I need You only need some selected files to make the below code work. The following is a list of files and directories that I used from the ‘ZendFramework-1.11.0 library Zend’ directory. The top three in the list are directories. There are also many files in the ‘Filter’ directory that are not required, but for keeping it simple we will use the whole thing. File (dir) Filter (dir) Loader (dir) Loader.php Filter.php Exception.php Encrypting uploaded files For the following example I’ve not included the file uploading code.
I assume you already have the upload code ready. You can also use the following code by itself to encrypt/decrypt files. The program for file encryption is shown below. 'mcrypt', // Initialization vector 'vector' =>'236587hgtyujkirtfgty5678', // Encryption algorithm 'algorithm' =>'rijndael-192', // Encryption key 'key' =>'KFJGKDK$$##^FFS345678FG2' ); /* Initialize the library and pass the options */ $encrypt = new Zend_Filter_File_Encrypt ( $options ); /* Set output filename, where the encrypted file will be stored. If we omit this, the encrypted file will overwrite the original file. */ $encrypt ->setFilename ( 'test.enc.pdf' ); /* Now encrypt a file */ $encrypt ->filter ( 'test.pdf' );?>Decrypting the encrypted files is as simple as above.
Note that you need to keep the ‘vector’ and ‘key’ values the same as you used for encryption, or you will not be able to correctly decrypt the file. 'mcrypt', // Initialization vector 'vector' =>'236587hgtyujkirtfgty5678', // Decryption algorithm 'algorithm' =>'rijndael-192', // Decryption key 'key' =>'KFJGKDK$$##^FFS345678FG2' ); /* Initialize the library and pass the options */ $decrypt = new Zend_Filter_File_Decrypt ( $options ); /* Set output filename, where the decrypted file will be stored. Mhdd 4 6 Rus Isotope.
*/ $decrypt ->setFilename ( 'test.pdf' ); /* Now decrypt the previously encrypted file */ $decrypt ->filter ( 'test.enc.pdf' );?>Selecting a encryption algorithm In the example given I’ve used the algorithm but you can choose some other according to the availability. ‘rijndael’ is fine for most requirements. First you will need to know what algorithms are supported by your installation. A quick way to find out is to use the following code.
Cast-128, gost, rijndael-128, twofish, arcfour, cast-256, loki97, rijndael-192, saferplus, wake, blowfish-compat, des, rijndael-256, serpent, xtea, blowfish, enigma, rc2, tripledes. Selecting a random Initialization vector Before we continue our discussion, a brief overview of Initialization vector (IV). An IV is a random string that can be used along with a key for data encryption. IV is used to prevent a sequence of text that is identical to a previous sequence from producing the same exact cipher-text when encrypted. As you can see from the example code we have used a fixed IV. The disadvantage of this is that there is a possibility that a committed hacker would be able to guess the IV by studying the pattern in the encrypted files and thus break the encryption.
The best way then is to let the class generate a random IV for each new encryption. This requires a little change of code, as shown below. The only extra step we now require is to store the generated random IV in a database which will then be used for decryption.
'mcrypt', // Encryption algorithm 'algorithm' =>'rijndael-192', // Encryption key 'key' =>'KFJGKDK$$##^FFS345678F54' ); /* Initialize the library and pass the options */ $filter = new Zend_Filter_File_Encrypt ( $options ); /* Generate a random vector */ $filter ->setVector ( ); /* Set output filename, where the encrypted file will be stored. */ $filter ->setFilename ( 'test.enc.pdf' ); /* Now encrypt a file */ $filter ->filter ( 'test.pdf' ); /* Save the vector in a DB or somewhere else, we will need this during decryption */ $vector = $filter ->getVector ( );?>Decryption.
'mcrypt', // Encryption algorithm 'algorithm' =>'rijndael-192', // Encryption key 'key' =>'KFJGKDK$$##^FFS345678F54' ); /* Initialize the library and pass the options */ $filter = new Zend_Filter_File_Decrypt ( $options ); /* Use the saved vector for decryption. Note that using a wrong vector will result in a incorrect decryption. */ $filter ->setVector ( 'your-saved-vector' ); /* Set output filename, where the decrypted file will be stored. */ $filter ->setFilename ( 'test.dec.pdf' ); /* Now decrypt the previously encrypted file */ $filter ->filter ( 'test.enc.pdf' );?>Selecting the correct ‘vector’ and ‘key’ size Before you run the code make sure that you set your PHP error reporting to ‘E_ALL’. Mcrypt requires that you use a correct IV and key length, which depends on which algorithm is used. Selecting a wrong IV (if you are using a fixed IV) or key length can generate the following error, which if the errors are disabled will be hidden and you will keep wondering as to why the files are not getting encrypted.: – in case of a wrong vector length: Fatal error: Uncaught exception ‘Zend_Filter_Exception’ with message ‘The given vector has a wrong size for the set algorithm’ – in case of a wrong key length: Fatal error: Uncaught exception ‘Zend_Filter_Exception’ with message ‘The given key has a wrong size for the set algorithm’ To get the correct sizes use the following code.
I’ve used ‘rijndael-192’ algorithm here, but you need to substitute whatever algorithm you have selected instead.
I'm using to encrypt a data. Here's my code. $cipher = BlockCipher::factory('mcrypt', array( 'algorithm' =>'aes', )); $cipher->setKey('mypassphrase'); $encrypted = $cipher->encrypt('Hey, I am the secret data'); Cool, it works well! Now, I need to decrypt that $encrypted data (Hey, I am the secret data) in Python. I am using pycrypto to do that.
What the steps to decrypt data outside my PHP environment? From Crypto.Cipher import AES import base64 import hashlib password = 'mypassphrase' key = hashlib.sha256(password).digest() decoded = base64.standard_b64decode(encrypted) cipher = AES.new(key, AES.MODE_CBC) data = cipher.decrypt(decoded) I need to specify an IV because Zend uses MODE_CBC by default.
How can I specify it in my Python code? Here's the Zend2 documentation: The output of the encryption is a string, encoded in Base64 (default), that contains the HMAC value, the IV vector, and the encrypted text. The encryption mode used is the CBC (with a random IV by default) and SHA256 as default hash algorithm of the HMAC.
The Mcrypt adapter encrypts using the PKCS#7 padding mechanism by default. You can specify a different padding method using a special adapter for that (Zend Crypt Symmetric Padding). The encryption and authentication keys used by the BlockCipher are generated with the PBKDF2 algorithm, used as key derivation function from the user’s key specified using the setKey() method.
Can someone help me to adapt my Python code to decrypt the data? I found a way to decrypt the data encrypted by Zend2. Here's my code: from base64 import b64decode from Crypto import Random from Crypto.Cipher import AES from Crypto.Hash import SHA256, HMAC from Crypto.Protocol.KDF import PBKDF2 # The hmac starts from 0 to 64 (length). Hmac_size = 64 hmac = data[:hmac_size] # The cipher text starts after the hmac to the end. # The cipher text is base64 encoded, so I decoded it. Ciphertext = data[hmac_size:] ciphertext = b64decode(ciphertext) # The IV starts from 0 to 16 (length) of the ciphertext.
Iv = ciphertext[:16] # The key size is 256 bits ->32 bytes. Key_size = 32 # The passphrase of the key. Password = 'mypassphrase' # The key is generated using PBKDF2 Key Derivation Function. # In the case of Zend2 Crypt module, the iteration number is 5000, # the result length is the key_size * 2 (64) and the HMAC is computed # using the SHA256 algorithm the_hash = PBKDF2(password, iv, count=5000, dkLen=64, prf=lambda p, s: HMAC.new(p, s, SHA256).digest()) # The key starts from 0 to key_size (32). Key = the_hash[:key_size] # The hmac key starts after the key to the end. Key_hmac = the_hash[key_size:] # HMAC verification hmac_new = HMAC.new(key_hmac, 'aes%s'% ciphertext, SHA256).hexdigest() if hmac_new!= hmac: raise Exception('HMAC verification failed.' ) # Instanciate the cipher (AES CBC).
Cipher = AES.new(key, AES.MODE_CBC, iv) # It's time to decrypt the data! The ciphertext starts after the IV (so, 16 after).
Data = cipher.decrypt(ciphertext[16:]) Mission succeeded!