【问题标题】:Error while using DBMS_CRYPTO function to decrypt CLOB data使用 DBMS_CRYPTO 函数解密 CLOB 数据时出错
【发布时间】:2020-01-27 20:38:13
【问题描述】:

我的任务是执行两个 Oracle 功能,实现以下目标:

  1. 将 CLOB 作为输入并使用 AES-256 对其进行加密并返回加密的 CLOB
  2. 以 Encrypted CLOB 作为输入,使用 AES-256 解密并返回 Decrypted CLOB

CLOB 数据问题很大,函数应该处理好这个问题。

我能够通过第一个函数,它运行良好,即用大量数据加密 CLOB:

create or replace 
function F_ENCRYPT_CLOB (ac_input IN CLOB) return CLOB is
l_clob CLOB;
lb_variable BLOB;
v_key RAW (320);
v_encryption_type PLS_INTEGER := DBMS_CRYPTO.AES_CBC_PKCS5; 
v_iv RAW (320);
l_dest_offset  PLS_INTEGER := 1;
l_src_offset   PLS_INTEGER := 1;
l_lang_context PLS_INTEGER := DBMS_LOB.default_lang_ctx;
l_warning      PLS_INTEGER;
l_step PLS_INTEGER := 1998;
begin
    SELECT VALUE
     INTO v_key
     FROM algparameters
     WHERE name = 'key';
   SELECT VALUE
    INTO v_iv
     FROM algparameters
    WHERE name = 'iv';

dbms_lob.createtemporary(lb_variable, true);


 sys.DBMS_CRYPTO.ENCRYPT(
                 dst => lb_variable,
                 src => ac_input,
                 typ => v_encryption_type,
                 key => v_key,
                 iv => v_iv
                 );

  DBMS_LOB.createTemporary(
    lob_loc => l_clob,
    cache   => TRUE);


  FOR i IN 0 .. TRUNC((DBMS_LOB.getlength(lb_variable) - 1 )/l_step) LOOP
        l_clob := l_clob || UTL_RAW.cast_to_varchar2(UTL_ENCODE.base64_encode(DBMS_LOB.substr(lb_variable, l_step, i * l_step + 1)));
      END LOOP;
   RETURN l_clob;

end F_ENCRYPT_CLOB;

但我在使用类似步骤解密先前加密的值时遇到问题:

create or replace 
function F_DECRYPT_CLOB (ac_input IN CLOB) return CLOB is 
  lb_variable CLOB; 
  l_blob BLOB;
  v_key RAW (320);
  v_encryption_type PLS_INTEGER := DBMS_CRYPTO.AES_CBC_PKCS5;
  v_iv RAW (320);
  l_dest_offset  PLS_INTEGER := 1;
  l_src_offset   PLS_INTEGER := 1;
  l_lang_context PLS_INTEGER := DBMS_LOB.default_lang_ctx;
  l_warning      PLS_INTEGER;

  l_raw     RAW(32767);
  l_amt     NUMBER := 7700;
  l_offset  NUMBER := 1;
  l_temp    VARCHAR2(32767);
  l_step PLS_INTEGER := 7700;

begin 
    SELECT VALUE
     INTO v_key
     FROM algparameters
    WHERE name = 'key';
   SELECT VALUE
     INTO v_iv
     FROM algparameters
    WHERE name = 'iv';

    dbms_lob.createtemporary(l_blob, true);

   FOR i IN 0 .. TRUNC((DBMS_LOB.getlength(ac_input) - 1 )/l_amt) LOOP
      DBMS_LOB.read(ac_input, l_amt, l_offset, l_temp);
      l_offset := l_offset + l_amt;
      l_raw    := UTL_ENCODE.base64_decode(l_temp);
      DBMS_LOB.append (l_blob, TO_BLOB(l_raw));
    END LOOP; 

  dbms_lob.createtemporary(lb_variable, true);

 sys.DBMS_CRYPTO.DECRYPT( 
                 dst => lb_variable, 
                 src => l_blob, 
                 typ => v_encryption_type,--dbms_crypto.des_cbc_pkcs5, 
                 key => v_key,
                 iv => v_iv
                 ); 

   return lb_variable; 
end F_DECRYPT_CLOB;

它抛出的错误是:

ORA-06502:PL/SQL:数字或值错误:十六进制到原始转换错误
ORA-06512:在“SN_PRE_STAGE_415.F_DECRYPT_CLOB”,第 33 行
06502. 00000 - “PL/SQL:数值或数值错误%s”
*原因:
*行动:

【问题讨论】:

    标签: oracle plsql base64 dbms-crypto


    【解决方案1】:

    错误来自第 33 行,即:

    l_raw    := UTL_ENCODE.base64_decode(l_temp);
    

    base64_decode function 需要一个 RAW 参数,因此您可以转换您现在拥有的字符串:

    l_raw    := UTL_ENCODE.base64_decode(UTL_RAW.cast_to_raw(l_temp));
    

       FOR i IN 0 .. TRUNC((DBMS_LOB.getlength(ac_input) - 1 )/l_amt) LOOP
          DBMS_LOB.read(ac_input, l_amt, l_offset, l_temp);
          l_offset := l_offset + l_amt;
          l_raw    := UTL_ENCODE.base64_decode(UTL_RAW.cast_to_raw(l_temp));
          DBMS_LOB.append (l_blob, TO_BLOB(l_raw));
        END LOOP; 
    

    现在它正在扔这个

    ORA-28817:PL/SQL 函数返回错误。
    ORA-06512:在“SYS.DBMS_CRYPTO_FFI”,第 110 行
    ORA-06512:在“SYS.DBMS_CRYPTO”,第 64 行
    ORA-06512:在“STACKOVERFLOW.F_DECRYPT_CLOB”,第 39 行

    您的 base-64 字符串有换行符;那些正在丢弃解码。您可以使用较小的块大小,l_amt = 64,并跳过换行符:

       FOR i IN 0 .. TRUNC((DBMS_LOB.getlength(ac_input) - 1 )/(l_amt + 2)) LOOP
          DBMS_LOB.read(ac_input, l_amt, l_offset, l_temp);
          l_offset := l_offset + l_amt + 2;
    

    但通过新的l_clob 变量一次性剥离它们可能更简单、更有效:

    create or replace 
    function F_DECRYPT_CLOB (ac_input IN CLOB) return CLOB is 
      lb_variable CLOB; 
      l_clob CLOB;
      l_blob BLOB;
      ... 
    begin 
       ...
        dbms_lob.createtemporary(l_blob, true);
    
       l_clob := replace(replace(ac_input, chr(13), null), chr(10), null);
    
       FOR i IN 0 .. TRUNC((DBMS_LOB.getlength(l_clob) - 1 )/l_amt) LOOP
          DBMS_LOB.read(l_clob, l_amt, l_offset, l_temp);
          l_offset := l_offset + l_amt;
          l_raw    := UTL_ENCODE.base64_decode(utl_raw.cast_to_raw(l_temp));
          DBMS_LOB.append (l_blob, TO_BLOB(l_raw));
        END LOOP; 
       ...    
    end F_DECRYPT_CLOB;
    /
    

    全文:

    create or replace 
    function F_DECRYPT_CLOB (ac_input IN CLOB) return CLOB is 
      lb_variable CLOB; 
      l_clob CLOB;
      l_blob BLOB;
      v_key RAW (320);
      v_encryption_type PLS_INTEGER := DBMS_CRYPTO.AES_CBC_PKCS5;
      v_iv RAW (320);
      l_dest_offset  PLS_INTEGER := 1;
      l_src_offset   PLS_INTEGER := 1;
      l_lang_context PLS_INTEGER := DBMS_LOB.default_lang_ctx;
      l_warning      PLS_INTEGER;
    
      l_raw     RAW(32767);
      l_amt     NUMBER := 7700;
      l_offset  NUMBER := 1;
      l_temp    VARCHAR2(32767);
      l_step PLS_INTEGER := 7700;
    
    begin 
        SELECT VALUE
         INTO v_key
         FROM algparameters
        WHERE name = 'key';
       SELECT VALUE
         INTO v_iv
         FROM algparameters
        WHERE name = 'iv';
    
        dbms_lob.createtemporary(l_blob, true);
    
       l_clob := replace(replace(ac_input, chr(13), null), chr(10), null);
    
       FOR i IN 0 .. TRUNC((DBMS_LOB.getlength(l_clob) - 1 )/l_amt) LOOP
          DBMS_LOB.read(l_clob, l_amt, l_offset, l_temp);
          l_offset := l_offset + l_amt;
          l_raw    := UTL_ENCODE.base64_decode(utl_raw.cast_to_raw(l_temp));
          DBMS_LOB.append (l_blob, TO_BLOB(l_raw));
        END LOOP; 
    
      dbms_lob.createtemporary(lb_variable, true);
    
     sys.DBMS_CRYPTO.DECRYPT( 
                     dst => lb_variable, 
                     src => l_blob, 
                     typ => v_encryption_type,--dbms_crypto.des_cbc_pkcs5, 
                     key => v_key,
                     iv => v_iv
                     ); 
    
       return lb_variable; 
    end F_DECRYPT_CLOB;
    /
    

    【讨论】:

    • 你好亚历克斯..解决了部分问题......现在它正在抛出这个
    • ORA-28817:PL/SQL 函数返回错误。 ORA-06512:在“SYS.DBMS_CRYPTO_FFI”,第 110 行 ORA-06512:在“SYS.DBMS_CRYPTO”,第 64 行 ORA-06512:在“SN_PRE_STAGE_415.F_DECRYPT_CLOB”,第 39 行 28817. 00000 - “PL/SQL 函数返回一个错误。” *原因:PL/SQL 函数意外返回错误。 *操作:这是一个内部错误。请联系 Oracle 客户支持。
    • 加密和解密功能不同步
    • @MAVERICK1985 - 好的,我明白了...我没有使用足够长的字符串来查看该问题。我已经更新了我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多