PBKDF2 in Oracle

Recently we were looking at password encryption and decided to implement PBKDF2 for lots of good reasons which I won’t repeat here. Unfortunately there is no native implementation for this in Oracle (as of 11.2.0.3), and a Google search turned up nothing useful.

My first thought was to write a call specification to make use of the implementation in Java that is installed in the database. This compiled fine, however when executed it transpired that the algorithm was introduced in Java 1.6, and the version in the database is Java 1.5.

So I needed to code the algorithm in PL/SQL. This wasn’t especially difficult, however I think it is worth publishing in case it saves time for anyone else.

Here is the function:

CREATE OR REPLACE FUNCTION pbkdf2
( p_password   IN VARCHAR2
, p_salt       IN VARCHAR2
, p_count      IN INTEGER
, p_key_length IN INTEGER
)
  RETURN VARCHAR2
IS
  l_block_count INTEGER;
  l_last        RAW(32767);
  l_xorsum      RAW(32767);
  l_result      RAW(32767);
BEGIN
  l_block_count := ceil(p_key_length / 20);  -- 20 bytes for SHA1.

  FOR i IN 1..l_block_count
  LOOP
    l_last := utl_raw.concat(utl_raw.cast_to_raw(p_salt), utl_raw.cast_from_binary_integer(i, utl_raw.big_endian));

    l_xorsum := NULL;

    FOR j IN 1..p_count
    LOOP
      l_last := dbms_crypto.mac(l_last, dbms_crypto.hmac_sh1, utl_raw.cast_to_raw(p_password));

      IF l_xorsum IS NULL
      THEN
        l_xorsum := l_last;
      ELSE
        l_xorsum := utl_raw.bit_xor(l_xorsum, l_last);
      END IF;

    END LOOP;

    l_result := utl_raw.concat(l_result, l_xorsum);

  END LOOP;

  RETURN rawtohex(utl_raw.substr(l_result, 1, p_key_length));

END pbkdf2;
/

And here is an implementation of the test vectors from https://www.ietf.org/rfc/rfc6070.txt  Note this takes about 3 minutes to run (on my hardware), owing to the case with 16M iterations.

SELECT t.*
     , pbkdf2(password, salt, iterations, key_length) output
FROM   ( SELECT 'password' password
              , 'salt' salt
              , 1 iterations
              , 20 key_length
              , '0C60C80F961F0E71F3A9B524AF6012062FE037A6' expected_output
         FROM   DUAL
         UNION ALL
         SELECT 'password'
              , 'salt'
              , 2
              , 20
              , 'EA6C014DC72D6F8CCD1ED92ACE1D41F0D8DE8957'
         FROM   DUAL
         UNION ALL
         SELECT 'password'
              , 'salt'
              , 4096
              , 20
              , '4B007901B765489ABEAD49D926F721D065A429C1'
         FROM   DUAL
         UNION ALL
         SELECT 'password'
              , 'salt'
              , 16777216
              , 20
              , 'EEFE3D61CD4DA4E4E9945B3D6BA2158C2634E984'
         FROM   DUAL
         UNION ALL
         SELECT 'passwordPASSWORDpassword'
              , 'saltSALTsaltSALTsaltSALTsaltSALTsalt'
              , 4096
              , 25
              , '3D2EEC4FE41C849B80C8D83662C0E44A8B291A964CF2F07038'
         FROM   DUAL
         UNION ALL
         SELECT 'pass'||chr(0)||'word'
              , 'sa'||chr(0)||'lt'
              , 4096
              , 16
              , '56FA6AA75548099DCC37D7F03425E0C3'
         FROM   DUAL
       ) t
/

Platform Information

The material in this article was most recently tested against Oracle 11.2.0.3.0 on 64-bit Linux.

About these ads
This entry was posted in Security and tagged . Bookmark the permalink.

One Response to PBKDF2 in Oracle

  1. Yugene says:

    Thanks for this function! You’ve saved a lot of time for me :)

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s