Take the 2-minute tour ×
Cryptography Stack Exchange is a question and answer site for software developers, mathematicians and others interested in cryptography. It's 100% free, no registration required.

Is there a definied keysize to be used with the "AES_256-CBC" method in PHP, and what is the size?

Some background:

I want to store encrypted text into a PostgreSQL database. The user who posts the data has a key (stored in db) which gets appended to a generic private key hard coded in the library.

$key = $genericKey . $userKey;

The used encryption method is "AES-256-CBC" with an iv_size of 16. The IV gets prepended to the encrypted string

$return = $iv.$encrypted

This is then stored in the database.

It appears that if I produce an extremely large generic key, then store some data with $userkey1, and then decrypt it with $userkey2, the data just gets decoded. If I rerun it with a small generic key and small user key, it does not get decoded. To me, it looks as if the big key gets truncated somehow.

Could someone confirm this and tell me what the max keysize is? What is the best-practice to make sure the set key doesn't exceed the key_size* E.g.: md5($key) because this produces a "fixed" amount of characters.

update

Because apparently php has its own implementation of the AES, this is the way I implement it in my own Class:

class Crypto {

function __construct(){
  $this->iv_size = 16;
  $this->sleutel = 'somelongkey';
  $this->encryptionMethod  = 'AES-256-CBC';
}

    private function encrypt($str){
	$sleutel = $this->sleutel . $this->userKey;
	$iv = $this->generateRandomString($this->iv_size);
	$cipher = openssl_encrypt($str, $this->encryptionMethod, $sleutel, 0, $iv);
	return $iv.$cipher;
    }
    public function decrypt($data){
        $iv = substr($data, 0, $this->iv_size);
	$sleutel = $this->sleutel . $this->userKey;

        return openssl_decrypt(substr($data, $this->iv_size), $this->encryptionMethod, $sleutel, 0, $iv);

    }
}
share|improve this question
2  
AES-256 uses a 256 bit or 32 byte key by definition. No more, no less. –  CodesInChaos Oct 11 '13 at 11:48
    
Since PHP does not have native AES crypto support, you're either using a module or library. To be sure we're all talking about the same thing, it would be cool if you could mention if you are using Mcrypt, some other module, or maybe even a PHP class or library? (Because sometimes, the devil hides in the details.) –  e-sushi Oct 11 '13 at 12:13
1  
I updated my question with the code used in my class. –  stUrb Oct 11 '13 at 12:38
    
@stUrb Thanks for your update. I think I've spotted the problem straight-on… check my answer. –  e-sushi Oct 11 '13 at 14:19

1 Answer 1

up vote 1 down vote accepted

You're simply appending the userKey to your "sleutel" (aka key) in this piece of code:

$sleutel = $this->sleutel . $this->userKey;

Problem is, doing that can result in $sleutel lengths beyond the expect 256 bits (32 bytes), or - as you are experiencing - less than the expected 256 bits (32 bytes/characters).

As @CodesInChaos correctly mentioned in his comment:

AES-256 uses a 256 bit or 32 byte key by definition. No more, no less.

So, to fix your problem, you will have to make sure the key you are passing to your cipher function is no more and no less than 32 bytes.

To achieve that, you can simply choose to follow the usual path of encryption by taking your $sleutel and hash your key to the expected 256-bit length with (for example) MD5, like this:

$sleutel = md5($this->sleutel . $this->userKey);

or — if you prefer to choose another hash and a speedier function — you can use PHP's hash function, with it's multiple of available hashes to select from, like (for example) this:

$sleutel = hash('ripemd128', $this->sleutel . $this->userKey);

But… that's not the way I would recommend you to do it! Because, you don't want to use a weak hash like MD5 (which is known to have collisions), and you surely don't want to feed a weak hexadecimal character sequence to your cipher either, do you?

My Recommendation

Following current crypto standards, my recommendation is to use SHA256 the way it is supposed to be used in this case:

$sleutel = hash('sha256', $this->sleutel . $this->userKey, TRUE);

Notice that there's a 3rd parameter which is set to TRUE, which means $sleutel will contain 32 raw bytes (= binary characters) instead of 64 human-readable hexadecimal characters.

I'm sure that will fix your "short-key" related problems, as well as any potential "long-key" problems.

share|improve this answer
    
Wow. Thank you e-sushi for this elaborate answer! Am I correct that with your recommended solution I always will produce a correct size key, no matter the size of $this-sleutel.$this->userKey ? –  stUrb Oct 11 '13 at 15:37
    
@stUrb Absolutely correct. That's one of many reasons why I recommended it… ;) As noted, remember to set that 3rd parameter to TRUE to be sure you get binary instead of hex characters in your $sleutel. (Btw.: Vlaams of Nederlands? In ieder geval, graag gedaan!) –  e-sushi Oct 11 '13 at 15:40
1  
Just to be sure, right :) (Jups, kom uit Roermond, Nederland :)) –  stUrb Oct 11 '13 at 15:53
    
@stUrb Right! (zegt de Belg die in Duitsland leeft. 8]) Hope to see you around every once in a while… de groetjes! –  e-sushi Oct 11 '13 at 15:57
1  
For password based keys derivation (i.e. where the input entropy is significantly below your key size), you should better use a slow hash function instead of any fast one like SHA-256. –  Paŭlo Ebermann Oct 18 '13 at 19:47

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.