Menu Search
Jump to the content X X
Smashing Conf Barcelona

You know, we use ad-blockers as well. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. our upcoming SmashingConf Barcelona, dedicated to smart front-end techniques and design patterns.

Replicating MySQL AES Encryption Methods With PHP

At our company, we process a lot of requests on the leading gift cards and coupons websites in the world. The senior developers had a meeting in late October to discuss working on a solution to replicate the MySQL functions of AES_ENCRYPT and AES_DECRYPT in the language of PHP. This article centers on what was produced by senior developer Derek Woods and how to use it in your own applications.

Security should be at the top of every developer’s mind when building an application that could hold sensitive data. We wanted to replicate MySQL’s functions because a lot of our data is already AES-encrypted in our database, and if you’re like us, you probably have that as well.

Further Reading on SmashingMag: Link

Why Does Encryption Matter? Link

We will begin by examining why security and encryption matter at all levels of an application. Every application, no matter how large or small, needs some form of security and encryption. Any user data you have is extremely valuable to potential hackers and should be protected. Basic encryption should be used when your application stores a password or some other form of identifying information.

Different levels of sensitive data require different encryption algorithms. Knowing which level to use can be determined by answering the basic question, “Will I ever need access to the original data after it has been encrypted?” When storing a user’s password, using a heavily salted MD5 hash and storing that in the database is sufficient; then, you would use the same MD5 hashing on the input and compare the result from the database. When storing other sensitive data that will need to be returned to its original input, you would not be able to use a one-way hashing algorithm such as MD5; you would need a two-way encryption scheme to ensure that the original data can be returned after it’s been encrypted.

Encryption is only as powerful as the key used to protect it. Imagine that an attacker breaches your firewall and has an exact clone of your database; without the key, breaking the encryption that protects the sensitive data would be nearly impossible. Keeping the key in a safe place should always be priority number one. Many people use an ini file that’s read at runtime and that is not publicly accessible within the scope of the Web server. If your application requires two-way encryption, there are industry standards for protecting such data, one being AES encryption.

What Is AES Encryption? Link

AES, which stands for Advanced Encryption Standard, was developed by Joan Daemen and Vincent Rijmen. They named their cipher, Rijndael, after a play on their two names. AES was announced as the winner of a five-year competition conducted by the National Institute of Standards and Technology (NIST) on 26 November 2001.

AES is a two-way encryption and decryption mechanism that provides a layer of security for sensitive data while still allowing the original data to be retrieved. To do this, it uses an encryption key that is used as a seed in the AES algorithm. As long as the key remains the same, the original data can be decrypted. This is necessary if your sensitive data needs to be returned to its original state.

How Does It Work? Link

AES uses a complex mathematical algorithm, which we will explore later, to combine two main concepts: confusion and diffusion. Confusion is a process that hides the relationship between the original data and the encrypted result. A classic example of this is the Caesar Cipher, which applies a simple shift of letters so that A becomes C, B becomes D, etc. Diffusion is a process that shifts, adjusts or otherwise alters the data in complex ways. This can be done using bit-shifts, replacements, additions, matrix manipulations and more. A combination of these two methods provides the layer of security that AES needs in order to give us a secure algorithm for our data.

In order to be bi-directional, the confusion and diffusion process is managed by the secret key that we provide to AES. Running the algorithm in one direction with a key and data will output an obfuscated string, thus encrypting the data. By passing that string back into the algorithm with the same key, running the algorithm in reverse will output the original data. Instead of attempting to keep the algorithm secret, the AES algorithm relies on complete key secrecy. According to its cryptographic storage guidelines5, OWASP recommends rotating the key every one to three years. The guidelines also go through methods of rotating AES keys.

PHP Mcrypt Specifics Link

PHP provides AES implementation through the Mcrypt extension, which gives us a number of other ciphers as well. In addition to the algorithm itself, Mcrypt provides multiple modes that alter the security level of the AES algorithm to make it more secure. The two definitions that we will need to use in our PHP functions are MCRYPT_RIJNDAEL_256 and MCRYPT_MODE_ECB. Rijndael 256 is the encryption cipher that we will use for our AES encryption. Additionally, the code uses an “Electronic Code Book” that segments the data into blocks and encrypts them separately. Alternative and more secure modes are available, but MySQL uses ECB by default, so we will be crafting our PHP implementation around that.

Why Should You Avoid AES In MySQL? Link

Using MySQL’s AES encryption and decryption functions is very simple. Setting up requires less work, and it is generally far easier to understand. Apart from the obvious benefit of simplicity, there are three main reasons why PHP’s Mcrypt is superior to MySQL’s AES functions:

  1. MySQL needs a database link between the application and database in order for encryption and decryption to occur. This could lead to unnecessary scalability issues and fatal errors if the database has internal failures, thus rendering your application unusable.
  2. PHP can do the same MySQL decryption and encryption with some effort but without a database connection, which improves the application’s speed and efficiency.
  3. MySQL often logs transactions, so if the database’s server has been compromised, then the log file would produce both the encryption key and the original value.

MySQL AES Key Modification Link

Out of the box, PHP’s Mcrypt functions unfortunately do not provide encrypted strings that match those of MySQL. There are a few reasons for this, but the root cause of the difference is the way that MySQL treats both the key and the input. To understand the causes, we have to delve into MySQL’s default AES encryption algorithm. The code segments presented below have been tested up to the latest version of MySQL, but MySQL could possibly alter their encryption scheme. The first problem we encounter is that MySQL will break up our secret key into 16-byte blocks and XOR the characters together from left to right. XOR is an exclusive disjunction, and if the two bytes are the same, then the output is 0; if they are different, then the output is 1. Additionally, it begins with a 16-byte block of null characters, so if we pass in a key of fewer than 16 bytes, then the rest of the key will contain null characters.

Say we have a 34-character key: 123456789abcdefghijklmnopqrstuvwxy. MySQL will start with the first 16 characters.

new_key = 123456789abcdefg

The second step taken is to XOR (⊕) the next 16 characters in the value in new_key with the first 16.

new_key = new_key ^ hijklmnopqrstuvw
new_key = 123456789abcdefg ^ hijklmnopqrstuvw
new_key = Y[Y_Y[YWI

Finally, the two remaining characters will be XOR’d starting from the left.

new_key = new_key ^ xy
new_key =  Y[Y_Y[YWI ^ xy
new_key = !"Y_Y[YWI

This is, of course, drastically different from our original key, so if this process does not take place, then the return value from the decrypt/encrypt functions will be incorrect.

Key Padding Link

The second major difference between Mcrypt PHP and MySQL is that the length of the Mcrypt value must have padding to ensure it is a multiple of 16 bytes. There are numerous ways to do this, but the standard is to pad the key with the byte value equal to the number of bytes left over. So, if our value is 34 characters, then we would pad with a byte value of 14.

To calculate this, we use the following formula:

$pad_value = 16-(strlen($value) % 16);

Using our 34-character example, we would end up with this:

$pad_value = 16-(strlen("123456789abcdefghijklmnopqrstuvwxy") % 16);
$pad_value = 16-(34 % 16);
$pad_value = 16-(2);
$pad_value = 14;

MySQL Key Function Link

In the previous section, we dove into the issues surrounding the MySQL key used to encrypt and decrypt. Below is the function that’s used in both our encryption and decryption functions.

function mysql_aes_key($key)
	$new_key = str_repeat(chr(0), 16);
		$new_key[$i%16] = $new_key[$i%16] ^ $key[$i];
	return $new_key;

First, we instantiate our key value with 16 null characters. Then we iterate through each character in the key and XOR it with the current position in new_key. Since we’re moving from left to right and using modulus 16, we will always be XOR’ing the correct characters together. This function changes our secret key to the MySQL standard and is the first step in achieving interoperability between PHP and MySQL.

Value Transformation Link

We run into the last caveat when we pull the data from MySQL. For the data encrypted with AES, the padded values that we added before encryption will remain tacked onto the end after we decrypt. In general, this would go unnoticed if we were only fetching the data in order to display it; but if we’re using any of basic string functions on the decrypted data, such as strlen, then the results will be incorrect. There are a couple ways to handle this, and we will be removing all characters with a byte position of 0 through 16 from the right of our value since they are the only characters used in our padding algorithm.

The code below will handle the transformation.

$decrypted_value = rtrim($decrypted_value, "..16");

Throwing all the concepts together, we have a few main points:

  1. We have to transform our AES key to MySQL’s standards;
  2. We have to pad the value that we want to encrypt if it’s not a multiple of 16 bytes in size;
  3. We have to strip off the padded values after we decrypt the encrypted value from MySQL.

It’s advantageous to segment these concepts into components that can be reused throughout the project and in other areas that use AES encryption. The following two functions are the end result and perform the encryption and decryption before sending the data to MySQL for storage.

MySQL AES Encryption Link

function aes_encrypt($val)
	$key = mysql_aes_key('Ralf_S_Engelschall__trainofthoughts');
	$pad_value = 16-(strlen($val) % 16);
	$val = str_pad($val, (16*(floor(strlen($val) / 16)+1)), chr($pad_value));
	return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $val, MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_DEV_URANDOM));

The first line is where we get the MySQL encoded key using the previously defined mysql_aes_key function. We are not using our real key in this article, but are instead paying homage to one of the creators of OpenSSL (among other technologies that he’s been involved in). The next line determines the character value with which to pad our data. The last two lines perform the actual padding of our data and call the mcrypt_encrypt function with the appropriate key and value. The return of this function will be the encrypted value that can be sent to MySQL for storage — or used anywhere else that requires encrypted data.

MySQL AES Decryption Link

function aes_decrypt($val)
	$key = mysql_aes_key('Ralf_S_Engelschall__trainofthoughts');
	$val = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $val, MCRYPT_MODE_ECB, mcrypt_create_iv( mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_DEV_URANDOM));
	return rtrim($val, "..16");

The first line of the decrypt function again generates the MySQL version of our secret key using mysql_aes_key. We then pass that key, along with the encrypted data, to the mcrypt_decrypt function. The final line returns the original data after stripping away any padded characters that we might have used in the encryption process.

See It In Action Link

To show that the encryption and decryption schemes here do in fact work, we must exercise both encryption and decryption functions in PHP and MySQL and compare the results. In this example, we have integrated the aes_encrypt/aes_decrypt and key function into a CakePHP model, and we are using Cake to run the database queries for MySQL. You can replace the CakePHP functions with mysql_query to obtain the results outside of Cake. In the first group, we are encoding the same data with the same key in both PHP and MySQL. We then base64_encode the result and print the data. The second group runs the MySQL encrypted data through PHP decrypt, and vice versa for the PHP encrypted data. We’re also outputting the result. The final block guarantees that the inputs and outputs are identical.


// Group 1
$a = $this->User->aes_encrypt('test');
echo base64_encode($a).'

$result = $this->User->query("SELECT AES_ENCRYPT('test', '".MY_KEY."') AS enc");
$b = $result[0][0]['enc'];
echo base64_encode($b).'

// Group 2
$result = $this->User->query("SELECT AES_DECRYPT('".$a."', '".MY_KEY."') AS decc");
$c = $result[0][0]['decc'];
echo $c."

$d = $this->User->aes_decrypt($b);
echo $d."

// Comparison

Output Link

The snippet below is the output when you run the PHP commands listed above.

bool(true) bool(true)

Final Thoughts Link

AES encryption can be a bit painful if you are not familiar with the specifics of the algorithm or familiar with any differences between implementations that you might have to work with in your various libraries and software packages. As you can see, it is indeed possible to use native PHP functions to handle encryption and decryption and to actually make it work seamlessly with any legacy MySQL-only encrypted data that your application might have. These methods should be used regardless so that you can use MySQL to decrypt data if a scenario arises in which that is the only option.


Footnotes Link

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5

↑ Back to top Tweet itShare on Facebook

Chad Smith is a Senior Programmer for OmniPrepaid LLC based in Pittsburgh, PA. He has a passion for UX, API, jQuery, CSS, PHP and Symfony2/Doctrine development. In his spare time he enjoys spending time with his two children, wife, and enjoys watching The Easy API grow. Derek Woods is a Senior Developer at OmniPrepaid LLC based in Pittsburgh, PA. He spends his time creating products across a wide range of technologies from Mongo and MySQL to PHP, Node.js and Java. Every now and then he blogs about it.

  1. 1

    Dave McDermott

    May 22, 2012 7:59 am

    I’ve seen many times, programmers use two-way encryption schemes when they’re just using it for one-way verification.

    *slaps head*

    If you don’t need the original source data, don’t provide a means of retrieving it.

    • 2

      Derek Woods

      May 22, 2012 10:07 am

      That is indeed true. That lesson certainly comes from knowledge/background or from a security breach and an ensuing hard lesson. These methods should be used sparingly and only for sensitive data that the application needs to access in its original form. Thanks for the point!

  2. 3

    I would highlight what both Chad and Derek said – the AES settings used by MySQL aren’t ideal. The ECB mode mentioned above has the problem that if two plaintext blocks are identical, then their output ciphertext blocks are identical too. This can leak information, and if an attacker replaced a particular ciphertext block it wouldn’t be detectable. Better modes would be CTR or CBC.

    For those who are curious, I highly recommend ‘Practical Cryptography’ by Ferguson and Schneier
    (Warning, may contain Math)

    • 4

      Derek Woods

      May 22, 2012 10:06 am

      You are absolutely correct. I would hope this would serve more as a segue rather than a “Hey – this is cool! I never have to worry about encryption again!” because, as you said, there are much more secure algorithms out there to use but unfortunately it still remains the case that large, monolithic codebases exist and they are not easy to transition without taking small steps. Thanks for the comment and the recommendation!

      • 5

        It seems strange to acknowledge that ECB Mode has known vulnerabilities then publish a working example using it. If you want to move away from MySQL’s AES functions why repeat their weaknesses? I see comments on this thread that assume this code IS GOOD, and secure, but it could be much better with little effort. Publishing weak crypto implementations “just for fun” is fine I suppose, but on a magazine used and read by professional programmers? I’m going to politely disagree.

        Simply switching the code to use CFB or CBC Mode would take zero effort and opens up the possibility to use an IV. In fact if CFB was used you wouldn’t have deal with null bytes and could instead discuss how to create an IV and append it to the ciphertext. I’d be happy to explain further if this comment is unclear.

  3. 6

    Dustan Curtis

    May 22, 2012 9:18 am

    Loved the article and can’t wait to test this out.

    I would love if these coding articles became more frequent on SmashingMag. The quality of the writing/editing is hard to find for most coding pieces on other sites. Here we have an ideal mix: background information on AES encryption and best practices; benefits of encrypting in PHP rather than in MySQL; solid examples to back it up.

    Very refreshing compared to the usual “Responsive Web [insert rest of title]” tutorials.


    • 7

      Derek Woods

      May 22, 2012 10:13 am

      Thanks for the positive feedback and I hope you find the article/code useful!

  4. 8

    Another reason to avoid the MySQL built-in encryption functions is that the plaintext and encryption key are sent over the wire between the server running PHP and the MySQL server. Unless an SSL connection is used! Both can be easily sniffed.

    • 9

      That is why proper use of the PDO/MySQLi/MySQL connection using strictly the file I/O (mysql.sock) vs. the standard TCP port 3306 is recommended.

      Disabling the TCP port listener in MySQL as a service startup flag is trivial as well as initializing a connection to the file socket.

      In such cases where replication & load balancing come into play rsync & an OS that uses a clustered file system such as coda, hadoop, gfs or tivoli should be implemented.

  5. 11

    i’m not sure i understand the reason why you would duplicate mysql well established and recognised aes functions with a php version of it.
    it seems to me that you will always use these functions when interacting with the database, so the active connection doesn’t seem to be a problem?
    the logging of transactions can be disabled (i humbly suppose), so why did you have to duplicate the functions ?
    interesting piece though :)

    • 12

      Derek Woods

      May 22, 2012 7:17 am

      There are a few reasons why you wouldn’t want to use the DB only:

      1. You are forever tied to MySQL. If you decide to go to another RDMS (Postgre, Mongo) you will have to redo your entire system where it relies on “SELECT AES_DECRYPT…”. If you use a single point for the encryption it is much less painful, but your data migration will involve MySQL-specific encryption so the likelihood of being able to decrypt it in other RDMS systems is pretty unlikely. This article doesn’t aim to solve that but it does prep you for doing these things.
      2. Database connection overhead. Assuming we want to just encrypt some data that will not reside in the database you would have to create a useless database connection. Additionally if you are encrypting 1,000 items that’s 1,000 queries where in PHP it would be 0. Typically scaling most often occurs at the application level since the DB is pretty efficient if designed right. In this context you would be forced to scale your DB architecture in the same manner as the concurrent requests get higher.
      3. If you are at a company where your data is audited they will want to look at your DB logs, in which case if you are encrypting card numbers, for instance, the log will contain the unencrypted card numbers. This is dependent on what mechanisms are used to log the queries but some do not allow you to turn off specific types of INSERTS/UPDATES.
      4. You can achieve much more secure encrypted data if using other algorithms that PHP in particular give you. The default settings for MySQL are not ideal.

  6. 13

    Billy Hoffman

    May 22, 2012 6:08 am

    Actually, storing passwords as MD5 hashes, even salted MD5 hashes, is no longer safe. This has nothing to do with flaws in MD5. It has nothing to do with rainbow tables.

    Modern GPU’s can calculate nearly a billion MD5 hashes a second. There are even special made Clustered GPU Amazon EC2 instances tuned for MD5 brute forcing. No hardware investment is needed. Brute cracking MD5 hashes is now trivial and so MD5 should not be used to store passwords at all.

    The generally agreed upon best practices is to now use bcrypt, which was specifically designed with hashing passwords in mind.

    • 14

      This is a very fair point. This is why the community is so strong on SmashingMagazine!

      Thank you for sharing,
      Chad Smith

    • 15

      Can’t stress this enough. Do NOT use MD5 for hashing passwords. MD5 is not a secure hashing algorithm, it’s just a hashing algorithm. So use it for what it was designed for (e.g. building checksums of files). As mentioned, bcrypt is a good way to hash passwords. The authors might go as far as updating the article so programmers not reading the comments don’t get the idea of using MD5 for their passwords. Maybe even better, use third party logins such as Facebook, OpenID, etcetera. If your database is compromised, these users won’t have any problems.

    • 16

      Thanks for pointing out what I was just about to. I’d have serious concerns trusting an article on security that still thinks MD5 is fine. Even the SHA family is looking shaky these days under the sheer brute force that a GPU farm can apply. For a bulletin board or blogging site SHA-256 is probably okay, but for something holding sensitive information you’d be mad to go for anything less secure than Blowfish.

      • 17

        Derek Woods

        May 24, 2012 4:10 am

        I agree with your standpoint. The MD5 sequence was supposed to serve as an example and not a guideline and was added late enough that we obviously missed how that paragraph would be interpreted (and worded). We do not, of course, use MD5 for anything other than hashing and would reiterate that no one should use it for anything sensitive as well.

        Thank you for your critique. It’s difficult to truly read an article after reading it over and over again and to that point we apologize for any oversights.

  7. 18

    I would like to know if you had any performance issue while decryting / encrypting requested data. Have you ever done a performance check? I really like to know about it.

    • 19

      Derek Woods

      May 24, 2012 4:18 am

      Speed is fairly nominal with this implementation. More secure versions would take more time but it’s not something that should vary widely across implementations. Rest assured the overhead in PHP vs MYSQL is much less from an application standpoint.

      We tested 1000 encryptions and it completes in roughly 150~200ms, which should be more than fast enough for most applications.

  8. 20

    Although I agree with the cipher mode (CBC vs. ECB) I disagree with a few points.

    1. In terms of security audits or PCI compliance audits; a production server should NOT have any type of transaction logging taking place on the database. These logs should be implemented within a development environement ONLY.

    Additionally the use of stored procedures to utilize the AES family of functions within MySQL do not log transactions by default and serve to provide a unified method of encrypting/decrypting data upon any and all transactions scales well in terms of multiple applications being given a unified method of access.

    2. Using MySQL’s AES family of functions to encrypt data outside of the application layer should definately not be implemented. If application layer data requires encryption the use of mcrypt symmetric encryption should be used.

    I have never heard of anyone using a SELECT AES_ENCRYPT($var); within application layer code to perform encryption and do not recommend it as there are plenty of libraries available within PHP, Ruby, Perl, Python etc. to perform this task.

    • 21

      Derek Woods

      May 25, 2012 1:49 pm

      For point 1 the PCI DSS standards mandate the use logging when accessing sensitive information (like credit card information) so that if they ask “Who has access this data and what did they do with it?” you can actually prove that point. There is nowhere you could log except the database to prove this point – since on the application level any number of reasons could prevent that log from being written to.

      Stored Procedures are viable, but not viable everywhere. They introduce difficulties in maintenance in normal build procedures and can explicitly be mandated as “no use”. Similarly you still want to log access and use of this data for PCI compliance reasons.

      With regards to point 2 – no sane developer SHOULD do this, but it exists. I have seen it numerous times unfortunately.

      Thanks for the feedback!

      • 22

        That is pretty wild, this is the first time I have ever heard of anyone using MySQL’s AES family of functions within application layer logic.

        I still disagree with logging transactions in a production environment, enabling logging of the database transactions where a key is used to encrypt & decrypt information disables security in the event of a file system compromise as well as a SQL injection occuring.

        Anonymous (or perhaps account name) access logging seems more appropriate in cases such as this.

        It still kills me that the mcrypt libraries still refer to the AES cipher as the RIJNDAEL cipher, although correct in terms of the original name, since its inception as the standard symmetric algorithm you think the mcrypt authors would adjust this to make it easier for people using their libraries.

        • 23

          Derek Woods

          May 29, 2012 4:16 am

          Let me specify that I am of course talking about logging in a non-aes-encoded-through-mysql world. In this scenario you are only logging SELECT statements with no actual KEYs being in the log (just the data you wanted) – which is in fact another reason to use non-mysql AES functions – so that you can actually do this type of audit trail without logging sensitive information.

          Using a log in conjunction with MySQL’s AES functions would of course be a terrible idea and one we allude to in the article as a reason for doing this transition in the first place. Thank you for the feedback. I absolutely agree PHP could simply things quite a bit instead of cryptic RIJNDAEL constants.

          • 24

            Fair enough, still don’t like the idea of logging data base information on a production server however.

        • 25

          Jas I understand your concern about logging but how do you perform database replication without bin logs?

      • 26

        I know this is not about the topic above, but a suggestion for Turbo Keys. Maybes you could use 1 key to acavitte a number of keys. For example, assigning key 1 to acavitte various keys on what to do. This could save a lot of time for dropping items for example, meaning you only have to click once for the whole inventory to drop in about 3 seconds or less.

  9. 27

    I’ve been using this code, and it works perfectly except for one thing. In the decryption function, the trim line should be
    rtrim($val, ” 0..x10″)
    rtrim($val, ” 0..16″)
    (The comment sanitizer is eating my backslashes. Pretend they’re there and correct. The important thing is to replace “16” with “x10”.)

    • 28

      I ran into this problem as well. Specifically, when a string gets padded with x10 or x0F my data was getting returned with the padding, which was not obvious (since they are control characters) until loading the data into an XML parser. It would be nice if the article were updated to fix this bug. Thanks!

  10. 29

    One of the most popular adervtising on the web today are Google ads and Yahoo ads. You can choose either adervtising only on search pages or on content sites.I would also suggest you try and find blogs related to your topic which are popular and receive lots of traffic or ask website owners if they would publish (and advertise) your company on their sites.Most of them are happy to add content and will probably just ask you for a link back to their site.I have added a link to one such site with lots of content and an example of how one company is advertised on their site.

  11. 30

    Is the entire code available to play around with… just to learn more about the subject? If so is there a link?

  12. 31

    I’m thinking to try this technique out. Perhaps you could comment for me on Ed Venator’s comment above regarding the alleged bug in the code he’s found, so that I know whether to I should use ’10’ or ’16’?

    Also, you mentioned Base64 encoding and I was wondering if by doing this, you can store the data directly in a ‘char’ type database field, rather than a varbinary? Perhaps you could elaborate a little on that? Should I be base64 encording it before storing it and what field type should I use?

    Great article. Informative and easy to read. Thanks.

  13. 32


    first of all: Thank you very much for your useful blog post!

    But I think I found a little mistake in the decryption-function (aes_decrypt()). It seems that removing padding from the decrypted string does not work properly. I noticed that while working with empty or 1 byte strings (the problem does not occur if working with strings > 1 byte). Thats the output of var_dump() after decryption:

    string ‘1’ (length=16)

    (notice: strlen() respectively var_dump() returns 16!)

    So I used a for-loop to get the ASCII-Codes (using PHP ord()-function) of each character of my decrypted string:

    int 49
    int 15
    int 15
    int 15
    int 15
    int 15
    int 15
    int 15
    int 15
    int 15
    int 15
    int 15
    int 15
    int 15
    int 15
    int 15

    As you can see, the first character of the string is correct, ASCII decimal 49 is “1”. The remaining characters are from AES padding. You used rtrim() to remove the padding:

    return rtrim($val, “..16”);

    The PHP manual says:

    “With .. you can specify a range of characters. ”

    Thats correct so far, but you have to use the hexadecimal representation of the ASCII-characters for the range:

    return rtrim($val, “x00..x10”);

    Now, the function is also working for empty and single-byte strings.

    My test script:
    PHP Version 5.4.7, Windows NT 6.1 Build 7601, MSVC9 (Visual C++ 2008)
    HTTP Server: Apache/2.4.3 (Win32) OpenSSL/1.0.1c PHP/5.4.7


↑ Back to top