如何缩短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
相关产品推荐
相关产品推荐

