You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何缩短DBMS_CRYPTO加密函数的输出长度至16字符

解决方案

首先需要修正原函数中密钥(key)和初始化向量(iv)的生成错误,然后通过编码优化缩短加密输出长度,以下是具体步骤和修改方案:

一、原函数的核心错误修正

原代码中使用RAWTOHEX转换密钥和iv是错误的,这会导致密钥长度翻倍且值不符合预期。AES256需要32字节的密钥,CBC模式需要16字节的iv,正确的生成方式是直接将字符串转换为RAW并截断到指定长度:

-- 修正密钥生成:转RAW后截断到32字节
key_bytes_raw := UTL_RAW.SUBSTR(UTL_RAW.CAST_TO_RAW('E@ghjk%We%g@ioy_'||Gkey||'015!5!24'), 1, 32);
-- 修正iv生成:转RAW后截断到16字节
iv_raw := UTL_RAW.SUBSTR(UTL_RAW.CAST_TO_RAW('AFC@_'||Gkey||'15!'), 1, 16);

二、缩短加密输出的两种方案

方案1:使用Base64编码压缩长度(推荐,兼顾安全和长度优化)

原函数将加密后的RAW自动转为十六进制字符串(2字符/字节),改用Base64编码(4字符/3字节)可大幅缩短长度。例如32字节的加密结果,十六进制是64字符,Base64仅为44字符。

修改后的完整函数:

CREATE OR REPLACE function Encrypt_decrypt(input_string in VARCHAR2,Gkey varchar2,Pkey char default 'e')
return varchar2
is
    output_string     VARCHAR2 (200);
    decrypted_raw     RAW (2000);
    key_bytes_raw     RAW (32);
    encryption_type   PLS_INTEGER
        := DBMS_CRYPTO.ENCRYPT_AES256
           + DBMS_CRYPTO.CHAIN_CBC
           + DBMS_CRYPTO.PAD_PKCS5;
    iv_raw            RAW (16);
BEGIN
    key_bytes_raw := UTL_RAW.SUBSTR(UTL_RAW.CAST_TO_RAW('E@ghjk%We%g@ioy_'||Gkey||'015!5!24'), 1, 32);
    iv_raw := UTL_RAW.SUBSTR(UTL_RAW.CAST_TO_RAW('AFC@_'||Gkey||'15!'), 1, 16);

    case when lower(Pkey)='e' then  
        -- 加密后转Base64并去除换行符
        output_string := UTL_ENCODE.BASE64_ENCODE(
            DBMS_CRYPTO.ENCRYPT (
                src   => UTL_I18N.STRING_TO_RAW (input_string, 'AL32UTF8'),
                typ   => encryption_type,
                key   => key_bytes_raw,
                iv    => iv_raw
            )
        );
        output_string := REPLACE(output_string, CHR(10), '');
        output_string := REPLACE(output_string, CHR(13), '');
    when lower(Pkey)='d' then
        -- 先Base64解码再解密
        decrypted_raw := DBMS_CRYPTO.DECRYPT (
            src   => UTL_ENCODE.BASE64_DECODE(input_string),
            typ   => encryption_type,
            key   => key_bytes_raw,
            iv    => iv_raw
        );
        output_string := UTL_I18N.RAW_TO_CHAR (decrypted_raw, 'AL32UTF8');
    else 
        output_string := 'Invalid Key';
    end case;
    return output_string;
exception when others then 
    return 'Error Denied Key';
END;
/

方案2:使用RC4流加密实现16字符输出(仅适用于非敏感数据)

AES是块加密算法,输出长度为16字节的倍数,无法通过编码压缩到16字符。若必须得到16字符的可逆输出,可改用RC4流加密(输出长度与输入长度一致):

  • 当输入字符串为12字节(UTF-8编码下约9-12个汉字/字符)时,Base64编码后恰好是16字符。

注意:RC4属于弱加密算法,安全性低,不建议用于敏感数据场景。

修改后的完整函数:

CREATE OR REPLACE function Encrypt_decrypt(input_string in VARCHAR2,Gkey varchar2,Pkey char default 'e')
return varchar2
is
    output_string     VARCHAR2 (200);
    decrypted_raw     RAW (2000);
    key_bytes_raw     RAW (32);
    encryption_type   PLS_INTEGER
        := DBMS_CRYPTO.ENCRYPT_RC4; -- RC4流加密
BEGIN
    key_bytes_raw := UTL_RAW.SUBSTR(UTL_RAW.CAST_TO_RAW('E@ghjk%We%g@ioy_'||Gkey||'015!5!24'), 1, 32);

    case when lower(Pkey)='e' then  
        -- 加密后转Base64并去除换行符
        output_string := UTL_ENCODE.BASE64_ENCODE(
            DBMS_CRYPTO.ENCRYPT (
                src   => UTL_I18N.STRING_TO_RAW (input_string, 'AL32UTF8'),
                typ   => encryption_type,
                key   => key_bytes_raw
            )
        );
        output_string := REPLACE(output_string, CHR(10), '');
        output_string := REPLACE(output_string, CHR(13), '');
    when lower(Pkey)='d' then
        -- 先Base64解码再解密
        decrypted_raw := DBMS_CRYPTO.DECRYPT (
            src   => UTL_ENCODE.BASE64_DECODE(input_string),
            typ   => encryption_type,
            key   => key_bytes_raw
        );
        output_string := UTL_I18N.RAW_TO_CHAR (decrypted_raw, 'AL32UTF8');
    else 
        output_string := 'Invalid Key';
    end case;
    return output_string;
exception when others then 
    return 'Error Denied Key';
END;
/

关键说明

  • 若坚持使用AES算法,无法将加密输出压缩到16字符(AES最小输出为16字节,对应Base64编码22字符),只能接受长度优化后的结果。
  • RC4方案仅适用于对安全性要求极低的场景,敏感数据务必使用AES等强加密算法。

内容的提问来源于stack exchange,提问作者Bahy Mohamed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 13:14:50