Pergunta

I need to do some encryption in PL/SQL + Oracle using the outdated DBMS_OBFUSCATION_TOOLKIT package, but it has to be decryptable (if that's even a word) in both Java and Javascript. The Java and JS decryptions use for PKCS#7 / PCKS#5 padding. It's simple (I think) to implement Zero padding, and I could change the Java and JS, but I don't know if I'll ever have problems with the zero padding being irreversible.

Therefore, I'd like to roll my own PKCS#7, but I'm having some trouble producing the right output. This code compares what I have side by size with the output from DBMS_CRYPTO, which has PKCS#5 implemented, but is not available to all employees, due to permissions issues:

  FUNCTION  DESWithPKCS5Padding(trash VARCHAR2) 
  RETURN VARCHAR2 
  IS 
    lv_encrypted_data           VARCHAR2 (2000); 
    lv_decrypted_data           VARCHAR2 (2000); 
    piv_str                     VARCHAR2 (2000) := 'apples'; 
    piv_pass_key                VARCHAR2 (2000) := 'testForNathan123testForN'; 
    a_var                       VARCHAR2 (100);
    num_padding_bytes               Int;
    padding_bytes               raw(100);
    test_byte                   raw(1);
    zero_byte                   raw(1);
    piv_raw                     raw(2000);
    piv_raw_orig                raw(2000);
    error_in_input_buffer_length EXCEPTION; 
    PRAGMA EXCEPTION_INIT (error_in_input_buffer_length, -28232); 
    input_buffer_length_err_msg VARCHAR2 (100) := 
  BEGIN 
      dbms_output.Put_line ('Input_string->:' 
                            || piv_str );

  -- Since 3DES needs data to be in multiples of 8 bytes we had pad the data, if the 
  -- data did not meet the 8 bytes boundary requirement. 
  num_padding_bytes := MOD(Length(piv_str),8);

  piv_raw_orig := utl_raw.cast_to_raw(piv_str);

  IF (num_padding_bytes) != 0 THEN 
    padding_bytes := '';
    zero_byte := '0';
    test_byte := utl_raw.cast_to_raw(8-num_padding_bytes);
    test_byte := utl_raw.bit_and(test_byte, '0F');

    for lcntr in 1..8-num_padding_bytes
      loop
      padding_bytes := UTL_RAW.CONCAT(padding_bytes, test_byte);
      end loop;

      piv_raw := utl_raw.concat(utl_raw.cast_to_raw(piv_str), padding_bytes);
  END IF;

  dbms_output.put_line('Without padding: ' || piv_raw_orig);
  dbms_output.put_line('After padding: '|| piv_raw);

  lv_encrypted_data := dbms_obfuscation_toolkit.Des3encrypt ( 
                       input => piv_raw, key => utl_raw.cast_to_raw(piv_pass_key),
                       which => 1);

  dbms_output.Put_line ('Encrypted Data OBFS: ' 
                        || lv_encrypted_data);

  lv_encrypted_data := dbms_crypto.encrypt (src => piv_raw_orig,
      KEY => utl_raw.cast_to_raw(piv_pass_key), typ =>  dbms_crypto.des3_cbc_pkcs5);

  dbms_output.Put_line ('Encrypted Data CRYPTO: ' 
                        || (lv_encrypted_data));                            

  lv_decrypted_data := dbms_crypto.Decrypt (src => lv_encrypted_data,
      KEY => utl_raw.cast_to_raw(piv_pass_key), typ =>  dbms_crypto.des3_cbc_pkcs5);

  dbms_output.Put_line('Decrypted: ' || utl_raw.cast_to_varchar2(lv_decrypted_data)); 
END;

And the output:

Input_string->:apples
Without padding: 6170706C6573
After padding: 6170706C65730202
Encrypted Data OBFS: 36DEFCBBC60BC58A
Encrypted Data CRYPTO: CF7676DF282DCC5C
Decrypted: apples

As you can see, it appears the padding is being applied correctly (0202 present at the end of the After padding RAW), but DBMS_CRYPTO is producing a different result than the DBMS_OBFUSCATION_TOOLKIT. Any ideas why?

Thanks in advance!

Foi útil?

Solução 2

  function ApplyPKCS5Padding (v_to_pad raw)
  return raw
  IS 
    a_var                       VARCHAR2 (100);
    num_padding_bytes               Int;
    padding_bytes               raw(100);
    test_byte                   raw(1);
    zero_byte                   raw(1);
    output                      raw(2000); 
  BEGIN                          
      -- Since DES needs data to be in multples of 8 bytes we pad the data, if the 
      -- data did not meet the 8 bytes boundry requirment.
      num_padding_bytes := MOD(Length(utl_raw.cast_to_varchar2(v_to_pad)),8);
      output := v_to_pad;

      IF (num_padding_bytes) != 0 THEN 
        padding_bytes := '';
        zero_byte := '0';

        test_byte := utl_raw.cast_to_raw(8-num_padding_bytes);
        test_byte := utl_raw.bit_and(test_byte, '0F');

        for lcntr in 1..8-num_padding_bytes
          loop
          padding_bytes := UTL_RAW.CONCAT(padding_bytes, test_byte);
          end loop;

          output := utl_raw.concat(v_to_pad, padding_bytes);
        ELSE
        padding_bytes := '0808080808080808';
        output := utl_raw.concat(v_to_pad, padding_bytes);
      END IF;

  return output;

  END;

The default IV is... I have no idea, but the OBFS toolkit and DBMS_CRYPTO have a different one. I just had to specify it, I did the testing with a 0 IV. Also, the default for OBFS is 2-key 3des, so I needed the which => 1 to change it to 3key. Thanks for the help!

EDIT: The original "solution" actually failed on Strings with length%8 == 0, due to a misinterpretation of the PKCS#7/5 spec... I've update the solution above to show the entire/functioning code.

Outras dicas

" the output from DBMS_CRYPTO, which has PKCS#5 implemented, but is not available to all employees, due to permissions issues:"

The other employees don't need access to DBMS_CRYPTO, they just need access to your function. So you can build a function which uses the restricted functionality in a specific and approved fashion, and make it widely available without violating the broader permissions issues.

Of course, I am assuming your application has implemented schemas in a sensible manner, which allows for dispersal of minimum necessary privileges on objects. I wrote a blog article on a similar issue quite recently, if you would like to find out more.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top