当前位置: 首页 > 知识库问答 >
问题:

使用DBMS_CRYPTO函数解密CLOB数据时出错

方绪
2023-03-14

我的任务是完成以下两个Oracle函数:

  1. 将CLOB作为输入,并使用AES-256对其进行加密,然后返回加密的CLOB
  2. 将加密的CLOB作为输入,使用AES-256对其解密并返回解密的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”
*原因:
*操作:

共有1个答案

凌伟泽
2023-03-14

错误来自第33行,即:

l_raw    := UTL_ENCODE.base64_decode(l_temp);

base64_decode函数需要一个原始参数,因此可以转换现在的字符串:

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:at“sys.dbms_crypto_ffi”,第110行
ORA-06512:at“sys.dbms_crypto”,第64行
ORA-06512:at“stackoverflow.f_decrypt_clob”,第39行

以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;
/
 类似资料:
  • 我们有一些lob和varchar2类型的数据被错误地编码为AL32UTF8,我们需要将其编码转换为we8mswin1252字符集。我得到了用于字符集转换的convert函数,这个函数在varchar2 datatype中工作得很好,但在CLOB中使用时给出了一些模糊的字符。我当前的编码是AL32UTF8。 数据库:Oracle 12c

  • 捕获的SQLExc0019:: java.sql.SQLExc0019: ORA-29532:Java调用终止由未捕获Java异常:java.sql.SQLExc0019:未能获得服务器访问帐户详细信息: ORA-28817: PL/SQL函数返回错误。 ORA-06512:在"SYS.DBMS_CRYPTO_FFI",第67行 ORA-06512:“SYS.DBMS_CRYPTO”,第44行 O

  • 本文向大家介绍PHP对称加密函数实现数据的加密解密,包括了PHP对称加密函数实现数据的加密解密的使用技巧和注意事项,需要的朋友参考一下 项目中有一个地方用到了将用户ID加密、传至下个接点进行反解的需求。(原谅我不能透漏太多-_-!),第一个想到的就是康盛Ucenter中的一个函数,后来搜了下,在简明魔法中也找到了个简单的方法,遂整合了下,形成了自己使用的函数。 一、对称加密 发送方将明文使用密钥和

  • null 由于oracle clob字段可以包含4GB(max)的数据,是否有使用SQLPlus获得完整数据块的正确方法?我可以把它作为文件下载吗? 我希望问题是清楚的。我更喜欢在不向数据库注入PL/SQL过程的情况下做到这一点。

  • 我正在尝试使用KMS和AWS加密SDK加密数据。查看AWS文档中提供的示例,似乎没有地方可以显式设置数据键。 使用由KMS生成的数据密钥使用AWS加密SDK加密数据的推荐方法是什么?

  • 我使用密码加密和解密字节数组在Android发送到服务器。我没有使用字符串,但我仍然收到非法块大小异常。 2021-08-12 20:55:17.606 15222-15222/com.example.packageW/System.err:javax.crypto.IllegalBlockSizeExcture:错误:1e00006a:密码函数:OPENSSL_internal:DATA_NOT