Bug: CBC with non 'l' switch chops the key parameter's input to the underlying $md5 hash function.

The limit of 56-bytes is being applied as an output filter to the key parameter, instead of being applied only as the input filter to the key schedule subroutine which accepts a string of 1-56 bytes and expands it to length 72.

This affects the CBC switch combos which do not use the 'l' switch: 'cr' and 'ci' which use hash(key parameter) as input to calculating (secret56), and 'c' and 'cs' use hash(key_parameter:salt) to generate 64 digits for (secret56:IV8). The purpose of the $md5 hash is to ensure the input can't be longer than the 56 limit, so there's no reason to limit that type of input. This alias shows 4 examples of 94-byte key parameters which are able to be decrypted with non-literal 56-byte keys, where this is caused by the input to md5(string) limiting the 'key' portion of the input at 56 bytes:

alias bf_hash_input_limit56 {
  var -s %key94 $regsubex(junk,$str(x,94),/x/g,$chr($calc(32+ \n))) , %key56 $left(%key94,56)
  var -s %a $encode('mc' hash key94 + random salt,mc,%key94)
  echo -a $decode(%a,mc,%key56)
  var -s %a $encode('mcs' hash key94 + fixed salt,mcs,%key94,SaltOrIV)
  echo -a $decode(%a,mc,%key56)
  var -s %a $encode('mcr' hash key94 only + random iv  ,mcr,%key94)
  echo -a $decode(%a,mcr,%key56)
  var -s %a $encode('mci' hash key94 only + fixediv  ,mci,%key94,SaltOrIV)
  echo -a $decode(%a,mci,%key56,SaltOrIV)


The 2nd of 4 examples on this page is a test vector where the input key is a binary string of length 80 bytes. It does not display the 56-byte secret key generated by the hash, but it does display the IV as 3c05d2f32c8d1d14, which matches the output from the above algorithm modified to accept binary keys, and which does not limit the length of the string being hashed by $md5. In this alias, $md5 is hashing a binary string of length 16+56+8=80 bytes, and the test vector's IV is the last 8 of 64 bytes generated by the hashing subroutine.

alias Openssl_salted_keygen_binary {
  bunset &raw &key
  var -s %binkey 1122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900112233445566778899001122334455667788990011223344556677889900
  var -s %binsalt 0000000000000000
  bset -c &pass+salt 1 $regsubex(junk,%binkey $+ %binsalt,/(..)/g,$base(\t,16,10) $chr(32))
  while ($bvar(&key,0) < $calc(56+8)) { noop $salted_digest_to_binary }
  bcopy -c &pass 1 &key 1 56 | bcopy -c &iv  1 &key 57 8
  var %bin_key  $regsubex($bvar(&key,1-56) ,/(\d+)/g,$base(\t,10,16,2) $chr(32))
  var %bin_salt $regsubex($bvar(&key,57- ) ,/(\d+)/g,$base(\t,10,16,2) $chr(32))
  echo 4 -a literal key in hex: %bin_key
  echo 4 -a literal  iv in hex: %bin_salt
alias salted_digest_to_binary {
  if ($bvar(&hash,0)) bcopy -c &raw 1 &hash 1 -1 | bcopy &raw -1 &pass+salt 1 -1
  bset -c &hash 1 $regsubex($md5(&raw,1),/(..)/g,$base(\1,16,10) $chr(32)) | bcopy &key -1 &hash 1 -1
  if ($bvar(&key,0) > $calc(56+8)) bcopy -c &key 64 &key 64 1
  echo 3 -a $bvar(&key,0) of 64 generated: $regsubex($bvar(&key,1-) ,/(\d+)/g,$base(\t,10,16,2) $chr(32))

Result from running: /Openssl_salted_keygen_binary

literal key in hex: C3 63 D2 5C 49 8B 5B E0 D5 5C 23 38 06 D8 89 BC 73 4C 49 FE E8 71 BB E1 73 24 0C 38 EA CC B8 5A 73 9D BA 62 8D 2D 64 15 FE 34 61 EC 17 69 02 E8 71 15 CE 92 A7 81 EA 34
literal iv in hex: 3C 05 D2 F3 2C 8D 1D 14

... which matches the IV shown in the linked test vector.


The other routine used by 'cr' and 'ci' is described at:


It limits the non-literal key's strength to 128 bits because it expands the $md5 hash digest from 16 to 56 bytes in a way where identical first-16 bytes must always have identical bytes 17-56. After describing the method of md5-hashing the non-literal key, it says:

"On Line 7, it is perfectly all right to use a key of arbitrary length because regenerate_key is set to 1."

I read 'arbitrary' as meaning the input to the hash is allowed to be any length, including those longer than the 56 limit of the secret key. I haven't located any test vectors to prove that 'arbitrary' means md5(string longer than 56).