title: DES3 encryption: ruby openssl::cipher vs. oracle dbms_obfuscation_toolkit
body: <p>I have a legacy application written in PL/SQL that encrypts and decrypts data using 3DES. Now I need to perform similar encryption from a ruby app. Eventually the resulting hash will need to be decrypted by the same PL/SQL application using its existing algorithm.</p>
  
  <p>The problem is that I'm obtaining different encrypted results in PL/SQL and Ruby and I don't know why.</p>
  
  <p><strong>First here is exactly how the PL/SQL encryption works:</strong></p>
  
  <p>From Oracle's docs about DBMS_OBFUSCATION_TOOLKIT  <a href="http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_obtool.htm" rel="nofollow">http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_obtool.htm</a></p>
  
  <p>"Oracle's implementation of 3DES supports either a 2-key or 3-key implementation, in outer cipher-block-chaining (CBC) mode."</p>
  
  <p>Function signature:</p>
  
  <pre><code>DBMS_OBFUSCATION_TOOLKIT.DES3Encrypt(
  input_string      IN     VARCHAR2,
  key_string        IN     VARCHAR2,
  encrypted_string  OUT    VARCHAR2,
  which             IN     PLS_INTEGER  DEFAULT TwoKeyMode
  iv_string         IN     VARCHAR2     DEFAULT NULL);
  </code></pre>
  
  <p>Note about the parameter which:
  "If = 0, (default), then TwoKeyMode is used. If = 1, then ThreeKeyMode is used."
  This helped me choose the cipher in the ruby version.</p>
  
  <p>Here is how the application makes that call:</p>
  
  <pre><code>set serveroutput on;
  declare 
          v_encrypted varchar2(100);
  begin  
    dbms_obfuscation_toolkit.des3encrypt(
      input_string =&gt; 'abcdefgh',       -- data to encrypt
      key_string =&gt; '16_byte_string_k', -- 16 byte = 128 bit key needed by DES3Encrypt
      encrypted_string =&gt; v_encrypted,
      iv_string =&gt; 'xxxxxxxx');         -- initialization vector
      dbms_output.put_line( lower(utl_raw.cast_to_raw(v_encrypted)) );
      -- prints 23ff779e88e2dbe1
  end;
  </code></pre>
  
  <p><strong>Second here is what I'm trying in Ruby:</strong></p>
  
  <p>OpenSSL::Cipher docs:
  <a href="http://www.ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/Cipher.html" rel="nofollow">http://www.ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/Cipher.html</a></p>
  
  <p>OpenSSL docs to give me the cipher name:
  From <a href="http://www.openssl.org/docs/apps/enc.html" rel="nofollow">http://www.openssl.org/docs/apps/enc.html</a>
  "des-ede-cbc        Two key triple DES EDE in CBC mode"</p>
  
  <pre><code>require 'openssl'
  
  cipher = OpenSSL::Cipher.new('des-ede-cbc')
  cipher.encrypt
  input = 'abcdefgh'
  cipher.key = '16_byte_string_k'
  cipher.iv = 'xxxxxxxx'
  
  # i noticed that cipher.update returns same length hash as PL/SQL
  # if called without cipher.final, but you are not supposed to do that
  #encrypted = cipher.update(input)
  encrypted = cipher.update(input) + cipher.final
  
  hex_representation = encrypted.unpack("H*")
  
  puts hex_representation
  # prints a5cfc96485d7203eb929c28ceb9fcd53
  </code></pre>
  
  <p>As shown in the code the ruby version computes a different hash value. Why? What needs to change to make them consistent?</p>
  
  <p>Points I'm unsure about:</p>
  
  <ul>
  <li>Whether des-ede-cbc is in fact the same as what Oracle does.</li>
  <li>Whether utl_raw.cast_to_raw and unpack("H*") will do the same thing
  to the    encrypted binary  data.</li>
  <li>What exactly cipher.final appends and if there's any equivalent
  way to append that data in PL/SQL.</li>
  </ul>
  
  <p><em>Note</em>: I am aware that DES is insecure and that AES has superseded it. My use case does not require these hashes to be unbreakable. The important requirement is to make the hashes consistent so that the PL/SQL app can decrypt hashes generated by the ruby app.</p>