title: AES encryption inconsistency in PHP using the Open SSL library and coding CBC mode from scratch
body: <p>I suppose I should deal with my first statement first. Is there an inconsistency in the way PHP does AES-128-CBC encryption when you use the Open SSL library?</p>
  <p>I am asking this because if you look through <a href="https://www.ietf.org/rfc/rfc3602.txt" rel="nofollow noreferrer">RFC3602</a> for AES then you'll find some test vectors in section 4. The first one I tried was:</p>
  <blockquote>
  <p>Case #1: Encrypting 16 bytes (1 block) using AES-CBC with 128-bit key</p>
  <p>Key       : 0x06a9214036b8a15b512e03d534120006</p>
  <p>IV        : 0x3dafba429d9eb430b422da802c9fac41</p>
  <p>Paintext : &quot;Single block msg&quot;</p>
  <p>Cphertext: 0xe353779c1079aeb82708942dbe77181a</p>
  </blockquote>
  <p>Using the open SSL library with the following code:</p>
  <pre><code>echo bin2hex(openssl_encrypt($str, 'aes-128-cbc', $key, OPENSSL_RAW_DATA, $iv));
  </code></pre>
  <p>You actually get back:</p>
  <pre><code>e353779c1079aeb82708942dbe77181ab97c825e1c785146542d396941bce55d
  </code></pre>
  <p>Now this is all well and good and decrypts back just fine, and the first 32 bytes are the expected cipher text &quot;e353779c1079aeb82708942dbe77181a&quot;. However, there appears to be another 32 bytes at the end of the cipher text returned from the Open SSL library. Why is this? This question becomes relevant next.</p>
  <p>As part of something I am doing for fun I am trying to implement AES CBC mode encryption sort of from scratch. The code I currently have for doing this is (based on the RFC previously referenced and on CBC diagrams at the <a href="https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29" rel="nofollow noreferrer">&quot;Block cipher mode of operation&quot; Wikipedia page</a>):</p>
  <pre><code>public function cbcEncrypt($str, $iv, $key) {
      $bl = 16;
      
      $bs = str_split($str,$bl);
      $pv = null;
      $r = '';
      
      foreach($bs as $b) {
          if($pv === null) $pv = $iv;
          if(strlen($b)&lt;$bl) $b = $this-&gt;pkcs7Pad($b, $bl);
          $pv = openssl_encrypt($b^$pv, 'aes-128-ecb', $key, OPENSSL_RAW_DATA);
          $r .= $pv;
      }
      
      return $r;
  }
  </code></pre>
  <p>At the moment I'm pretty sure this code wont work on strings longer than the current test 16 byte string anyway, however, I ran this code side by side with the Open SSL implementation to compare. The return value from by CBC implementation is:</p>
  <pre><code>e353779c1079aeb82708942dbe77181a8b1ccc6f8cd525ffe22d6327d891a063
  </code></pre>
  <p>When called via:</p>
  <pre><code>$crypto = new CryptoTools();
  $enc = $crypto-&gt;cbcEncrypt('Single block msg',hex2bin(&quot;3dafba429d9eb430b422da802c9fac41&quot;),hex2bin(&quot;06a9214036b8a15b512e03d534120006&quot;));
  </code></pre>
  <p>Again, the first 32 bytes are correct, but the second 32 bytes are again added but completely different from the Open SSL implementation of CBC. Any clues as to why?</p>
  <p>Also, the Open SSL implementation of ECB mode returns a 32 byte string, which means CBC encrypting strings currently greater than 16 bytes in length the new value of $pv will be 32 bytes in length and then it will be XOR'd against the second plain text block when in reality shouldn't $pv always be 16 bytes in length? Is it usually just accepted that you truncate $pv from 32 to 16 bytes?</p>
  <p>Just in case it helps, the pkcs7Pad method in the code above looks like:</p>
  <pre><code>public function pkcs7Pad($str, $b = 8) {
      if(trim($str) == '') return false;
      if((int)$b &lt; 1)  return false;
      $p = $b - (strlen($str) % $b);
      return $str . str_repeat(chr($p),$p);
  }
  </code></pre>
  <p>Any help would be greatly appreciated. Needless to say there's not much documentation on this as people aren't usually stupid enough to try and reinvent the wheel, certainly in PHP...</p>