I've been having trouble trying to communicate between PHP and my iOS application using AES encryption.
So far, I've considered two methods of implementation. The first was to use OpenSSL.
On the iOS side, I implemented in a way to mimic the code shown here: http://saju.net.in/code/misc/openssl_aes.c.txt.
On the PHP side, I took the generated key and IV (from the iPhone) and used it as input to the PHP openssl encrypt.
The results differed in terms of the output...
I have also considered: http://iphonedevelopment.blogspot.com/2009/02/strong-encryption-for-cocoa-cocoa-touch.html
but this SO post: AESCrypt decryption between iOS and PHP deterred me.
The project is not tied down to AES, it just seemed like a strong encryption algorithm that wouldn't be too hard to implement.
My basic question is: what is the easiest way to implement a good encryption algorithm that can easily be used to communicate between iOS and PHP?
I just got through this same sort of project. I used the library you referenced in "also considered..."
Here is some example code to decrypt with php:
$iv2 = '';
for($i=0;$i<16;$i++){
$iv2 .= "\0";
}
$plain_text_CBC = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted_text, MCRYPT_MODE_CBC, $iv2);
var_dump($plain_text_CBC);
Make sure your keys are both 256-bit (32 characters, I have not yet had any encoding issues, but if you do, remember that you are encrypting bytes, not characters). Note that 128 in MCRYPT_RIJNDAEL_128 is the block size and not the key size, while in the method AES256DecryptWithKey, 256 is a reference to the key size, while the block size is 128. AES256DecryptWithKey runs in CBC mode, but has a null initialization vector (iv).
CBC means that each block depends on the last block, and so it uses a pre-set, usually random, "block -1" called the IV
ECB means that each block is encrypted in the same way, hence it reveals when two blocks in the same message are the same. The library mentioned does not use it, so I mentioned it just for contrast.
The use of a zero iv (0000000000000000 in bytes) is considered insecure. To fix this you would have to create an NSData *iv variable for the IV and modify the CCcrypt argument of NSData+AESCrypt.m to add [iv bytes] for the iv parameter (I have not yet tested this code), and you would need to store this iv and pass it to the php along with you message. But first I would test and have everything working with a zero iv.
As said in the comments, it would probably easiest for you to use HTTPS.
I once set up an iPhone app that had to communicate with a PHP backend over HTTPS, and spent many hours trying to find out why the iPhone wouldn't accept the encrypted connection.
As it turned out, it didn't work because I was using a self-signed certificate on the server side. Buying an SSL certificate from a Certificate Authority solved all issues.
SSL certificates that validate a single domain name without company or extended validation are really cheap, so I suggest you give that a try!
For a direct example, my open source project "Techno Tap" contains PHP and iOS source that uses AES encryption successfully, feel free to take a look here
The encryption on iOS is done in ScoreboardManager.m (using NSData+AES) and decryption is done on the PHP side in Scoreboard.php
Related
I would like to use phpAES to encrypt users' passwords with AES256/CBC, transfer the data and decrypt it using different software. In testing used the example provided by the developer and tried decrypting the cypher online at AES Encryption and Decryption Online Tool, unfortunately, I received the following error.
Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
Can anyone provide me with guidance?
Here is the response I received a from the developer.
The link you provided likely uses a different padding scheme, probably PKCS5. This library currently only supports null byte padding.
Try testing using OFB or CFB modes. More info on block cipher padding can be found here cipher CryptoSys PKI Pro Manual
I am trying to pass a JSON string from one web application to another using URL parameters (for an internal SSO server).
What I need to do is be able to encrypt the JSON string (which is a user payload object) with a pre-shared key, forward the user to the service provider application with the payload attached as a URL parameter and then on the service provider application decrypt the payload back into a JSON string to get the required information.
Now this part isn't as much of an issue thanks to all of PHP's built in encryption functions but the next part is the difficulty. I am needing to embed a checksum within the encrypted string which can be checked when decrypting it so that if it has been modified in transit then I can raise an exception.
The purpose of this is to make sure that the user payload has not been modified in transit either accidentally or deliberately.
You want to provide more than a "checksum" (usually defined as "calculable by any party"); you want to provide an authentication tag or message authentication code (MAC). You have a couple options:
Use an "authenticated encryption" (AE) or "authenticated encryption with associated data" (AEAD) cipher to do this. AE(AD) ciphers provide an "authentication tag" over the cipher text, either in a single pass or with a repeated process over the encrypted cipher text. Examples (probably available in whichever PHP cipher library you're using) are GCM, EAX, and CCM. This is recommended, as the decryption operation will fail if the authentication tag is not verified, and only one shared secret (key) is necessary.
You can construct the system yourself using cryptographic primitives. This is less ideal, as you are responsible for more independent pieces, you need to manage more keys (if you have access to an OMAC implementation, you can use the same key), and your individual construction is not vetted by third parties (aka the collective work of the internet). If you follow this path, you need to keep some key details in mind:
Use a strong hash-based message authentication code (HMAC) such as HMAC/SHA-256, -384, or -512. Do not use SHA-1 or MD5, as these are easily brute forced.
Verify the HMAC before decrypting the cipher text. Any HMAC that fails means the entire cipher text should be discarded. You can remember this (on the generating side) as Encrypt Then MAC, and if you search for it, you'll see that not following this advice is the source of many cryptographic vulnerabilities and implementation exploits.
Verify the HMAC with a constant-time algorithm (i.e. do not use a short-circuit string equality comparison, the default in Java). PHP provides hash_equals to do this. Here's a quick explanation of timing attacks and a code review of a PHP example.
For either choice you'll want to encode the resulting cipher text and authentication tag with URL-safe Base64 in order to avoid data loss or corruption. If your message format is not strictly structured with included lengths, you'll have to pre-share the protocol ahead of time (i.e. for message m of length n bytes -> 16 bytes IV | n-48 bytes cipher text | 32 bytes HMAC).
Last note: always use a unique, non-predictable IV for each message that is encrypted with a key. Many people gloss over this, because it's "easy to just use 0x00 * 16", but any stream cipher mode of operation like CTR used as the foundation of GCM and CCM will lose fundamental security if two messages are encrypted with the same IV and key.
I have a project that I'm working on that requires me to send data out to a third party in an encrypted format. We chose AES-256 as the encryption for the data.
I'm using PHP and the other party is using VB. I'm using the MCrypt Library to do my encryption on my end.
I can't seem to match my encryption to their encryption. Is a shared initial vector required, in addition to a shared key phrase? Are there any other things to take into consideration to make allow my data to be decrypted by the other party?
Additionally I've been told that VB uses a byte array for the IV. With the MCrypt library the examples use regular strings such as "1234567890123456" for the IV. Should I assume all that is required is a conversion from the above string to a byte array and all will be well?
Everything needs to be the same at both ends: IV, key, mode (use CBC or CTR) and padding (use PKCS#7). If any of these if different then things will fail. Crypto systems are designed to fail if anything is wrong.
Here's a theoretical one that not only applies to PHP, but probably to more languages.
Let's say that I encrypt a string with the mcrypt library using and the AES-256 cipher. The string, encrypted, would now look similar to þøÆ{”ò(ü´îÚÜÇW¹ËŸK¯L‘rø?ª¶!JF£º+Œ’Ú'‚.
If the encryption key would change between the events of decryption and encryption, the result of the decryption would obviously be worthless.
Since an encrypted string contains, at least to me, random chars, It wouldn't be easy to run some sort of test on it to ensure that it is in encrypted/decrypted state.
I've spent some time thinking. How can I test that a string has been properly decrypted?
What if I appended a small prefix to the original string before encrypting it in the first place, and then removed this prefix upon decryption. If this prefix wasn't found, it would be safe to say that the decryption has failed.
Would this be an appropriate way to handle this?
To test data integrity you want a Message Authentication Code (MAC).
There are a few stand-alone MAC algorithms, which look like a hash function with a key. The very standard MAC algorithm is HMAC (which uses a hash function).
Since you also encrypt the data, you will want to use an encryption mode with a builtin MAC; there are a few such modes, such as GCM or EAX. Those modes apply to a block cipher, usually the AES.
Adding a known prefix or suffix to the data before encryption is a homemade MAC. MACs are subtle and error prone. For instance, if you add a CRC32 and then encrypt with a stream cipher (or a block cipher in CTR mode), then you are reproducing one of the seven capital sins of WEP (see section 4 in particular, for the CRC32-as-MAC issue). Basically your integrity check is no longer resistant to active attacks; you are only detecting innocent mistakes, such as using the wrong key.
(Unfortunately, it seems that MCrypt does not support any combined encryption/MAC mode. PHP itself, when compiled with the --with-mhash option, provides the mhash() function which implements both raw hashing, and HMAC.)
How can I test that a string has been properly decrypted?
The "small prefix" idea should be fine; also the excellent idea by #CodeInChaos. Other than that, storing the string in some defined format (like serialize() or json_encode()) and failing to restore it (unserialize(), json_decode()) would be indication of a broken decryption as well.
I'll keep this short and simple. As part of PHP's mcrypt library there are 40 or so possible ciphers, see here.
Not knowing much about encryption myself, I'm working under the assumption regardless of the cipher used, the data when decrypted is identical as the data encrypted (otherwise what's the point right?)
I need to encrypt and then decryption either an array or serialised standard object. I've browsed a couple examples online of the basic implementation of the mcrypt library and noticed that each example used a different cipher. It got me wondering if there was any significance to this, or simply personal preference?
My question is, is there any significant differences between these ciphers I should be concerned with knowing that
I'll be encrypting/decrypting is an either an array or serialised standard object, and contain relatively little data.
This operation will be fairly uncommon so speed isn't a massive issue, anywhere in the range on < 2s is acceptable.
The encrypted string will need to be stored in a cookie and transmitted via url query string (so there are limitations on length and character set)
Note
I'm not after a debate about whether I should be using a hash or hmac. Encryption is necessary and the correct option for this problem.
Any reasonable cipher encrypts/decrypts between plaintext/ciphertext given the correct key.
There are huge differences to which cipher you choose. Be it block length, key length and/or general security. For instance, you should never use DES because it only uses a 56-bit key. Similar for other ciphers on the list you refer to. Before using any cipher always read up on it and determine whether it is a good cipher for your context.
But I can't go into detail about every cipher on your list here. :-)
I personally like AES (Rijndael) which takes three sizes of keys 128, 192 and 256 bits. The best known attack is faster than a brute-force attack but is still infeasible. It is fast, too (actually Intel included machine instructions for AES in Westmere and Sandy Bridge).
Serpent and Twofish are also good ciphers. Serpent came second to Rijndael and Twofish came third (I think it was) in the AES contest some years back.