Monday, March 11, 2013

[jyadiual] Notes on Perl Crypt::CBC

Perl Crypt::CBC version 2.32

The documentation says, "the actual key will be derived by passing the passphrase through a series of MD5 hash operations".  Despite what it might sound like, this is NOT anything remotely resembling a strong password-based key derivation function like PBKDF2 and has none of the key strengthening features that would make the password computationally expensive to attack by brute force.  Fortunately, the option literal-key and the separate module Crypt::PBKDF2 do exist.  Note that you will have to manage the password salt manually if you use that.  (As well as the IV.)

The key derivation algorithm provides at most 128 bits of security no matter how much entropy is in the password you provide, and no matter what the key size of the underlying cipher is.  Rijndael (AES) by default uses the 256-bit key size, and the documentation for Crypt::Rijndael seems to suggest CBC can use no other size, even though Rijndael supports them.  MD5 is hard coded even though we should be moving away from it.  Here is the code in sub _key_from_key:

my $material = md5($pass);
  while (length($material) < $ks)  {
    $material .= md5($material);
  }
  return substr($material,0,$ks);

I am suspicious of the later bits of key being a direct well-known function of the earlier bits.  I would prefer something like $material .= md5($material . md5($pass)).

Similarly, salted password and initialization vector generation are done in the sub _salted_key_and_iv, though there is a non-hashed suffix every iteration.  Being non-hashed potentially allows for weird attacks to control the MD5 internal state.

  while (length $data < $desired_len) {
    $d = md5($d . $pass . $salt);
    $data .= $d;
  }
return (substr($data,0,$key_len),substr($data,$key_len,$iv_len));

I am suspicious of the key and initialization vector being computed from the same salt and linked by a function application.  I am suspicious of an IV not containing a full block's worth of entropy.  The salt may only be 64 bits.

The documentation suggests the algorithm is such as it is to be compatible with OpenSSL, suggesting these possible flaws are also present in OpenSSL.

Given Python's supposed larger mind share nowadays and the continuing relevance of the cipher block chaining mode of operation, I checked if there was something analogous to, or better than, Perl Crypt::CBC, but found nothing.  PyCrypto offers only a very low level API.

No comments :