1

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!

4

2 回答 2

0
  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;

默认的 IV 是……我不知道,但是 OBFS 工具包和 DBMS_CRYPTO 有不同的。我只需要指定它,我用 0 IV 进行了测试。此外,OBFS 的默认设置是 2-key 3des,所以我需要将which => 1其更改为 3key。谢谢您的帮助!

编辑:由于对 PKCS#7/5 规范的误解,原来的“解决方案”实际上在长度 %8 == 0 的字符串上失败了......我已经更新了上面的解决方案以显示整个/功能代码。

于 2013-07-29T06:45:11.277 回答
0

“ DBMS_CRYPTO 的输出,它实现了 PKCS#5,但由于权限问题,并非所有员工都可以使用:”

其他员工不需要访问 DBMS_CRYPTO,他们只需要访问您的函数。因此,您可以构建一个以特定和批准的方式使用受限功能的函数,并使其广泛可用,而不会违反更广泛的权限问题。

当然,我假设您的应用程序已经以合理的方式实现了模式,这允许分散对对象的最低必要权限。我最近写了一篇关于类似问题的博客文章,如果您想了解更多信息

于 2013-07-26T09:30:52.490 回答