Oracle内置DBMS_CRYPTO加密包实现AES对称加密和解密

目录

一、权限检查与赋予

二、AES加密函数

三、AES加密函数

四、使用示例


一、权限检查与赋予

先检查是否具备DBMS_CRYPTO权限

sql 复制代码
SELECT * FROM user_tab_privs WHERE table_name = 'DBMS_CRYPTO';

如图所示就是已经具备权限了,否则加密和解密函数无法奏效

如果没有,则执行如下命令

sql 复制代码
GRANT EXECUTE ON SYS.DBMS_CRYPTO TO 你的用户名;

二、AES加密函数

sql 复制代码
 
create or replace function aes_encrypt(p_input VARCHAR2)
    RETURN varchar2
IS
    p_key VARCHAR2(16) := 'hj7x89H$yuBI0456';
    p_iv  VARCHAR2(16) := 'NIfb&95GUY86Gfgh';
 
    raw_key RAW(16) := UTL_I18N.STRING_TO_RAW(p_key, 'UTF8');
    raw_iv  RAW(16) := UTL_I18N.STRING_TO_RAW(p_iv, 'UTF8');
 
    l_src_data RAW(2000);
    l_encval RAW(2000);
    v_result VARCHAR2(2000);
 
    v_padded_length NUMBER;
    v_padding_length NUMBER;
    v_padded_raw RAW(2000);
BEGIN
    -- 1. 转换为RAW
    l_src_data := UTL_I18N.STRING_TO_RAW(p_input, 'UTF8');
 
    -- 2. 手动添加零填充(模拟Java的NoPadding)
    -- 计算需要填充到16字节的倍数
    v_padded_length := CEIL(UTL_RAW.LENGTH(l_src_data) / 16) * 16;
    v_padding_length := v_padded_length - UTL_RAW.LENGTH(l_src_data);
 
    -- 添加0x00填充
    v_padded_raw := l_src_data;
FOR i IN 1..v_padding_length LOOP
        v_padded_raw := UTL_RAW.CONCAT(v_padded_raw, '00');
END LOOP;
 
    -- 3. AES/CBC加密,使用零填充
    l_encval := DBMS_CRYPTO.ENCRYPT(
        src  => v_padded_raw,
        typ  => DBMS_CRYPTO.ENCRYPT_AES128
              + DBMS_CRYPTO.CHAIN_CBC
              + DBMS_CRYPTO.PAD_ZERO,
        key  => raw_key,
        iv   => raw_iv
    );
 
    -- 4. Base64编码
    v_result := UTL_I18N.RAW_TO_CHAR(
        UTL_ENCODE.BASE64_ENCODE(l_encval),
        'UTF8'
    );
 
RETURN v_result;
 
EXCEPTION
    WHEN OTHERS THEN
        RETURN NULL;
END;

三、AES加密函数

sql 复制代码
create or replace function aes_decrypt(p_input VARCHAR2)
    RETURN varchar2
IS
    -- 密钥和IV(与Java代码完全一致)
    p_key VARCHAR2(16) := 'hj7x89H$yuBI0456';
    p_iv  VARCHAR2(16) := 'NIfb&95GUY86Gfgh';
 
    raw_key RAW(16) := UTL_I18N.STRING_TO_RAW(p_key, 'UTF8');
    raw_iv  RAW(16) := UTL_I18N.STRING_TO_RAW(p_iv, 'UTF8');
 
    l_enc_data RAW(2000);
    l_decval RAW(2000);
    v_raw_result RAW(2000);
    v_result VARCHAR2(2000);
    v_length NUMBER;
    v_byte RAW(1);
BEGIN
    -- 1. Base64解码
    l_enc_data := UTL_ENCODE.BASE64_DECODE(
        UTL_I18N.STRING_TO_RAW(p_input, 'UTF8')
    );
 
    -- 2. AES/CBC解密,使用零填充(匹配Java的NoPadding)
    l_decval := DBMS_CRYPTO.DECRYPT(
        src  => l_enc_data,
        typ  => DBMS_CRYPTO.ENCRYPT_AES128
              + DBMS_CRYPTO.CHAIN_CBC
              + DBMS_CRYPTO.PAD_ZERO,
        key  => raw_key,
        iv   => raw_iv
    );
 
    -- 3. 移除零填充:找到第一个0x00字节并停止
    v_length := UTL_RAW.LENGTH(l_decval);
 
FOR i IN 1..v_length LOOP
        v_byte := UTL_RAW.SUBSTR(l_decval, i, 1);
 
        -- 遇到0x00填充字节时停止
        IF v_byte = '00' THEN
            EXIT;
END IF;
 
        -- 累积有效字节
        v_raw_result := UTL_RAW.CONCAT(v_raw_result, v_byte);
END LOOP;
 
    -- 4. 将RAW数据转换为字符串
    IF v_raw_result IS NOT NULL THEN
        v_result := UTL_I18N.RAW_TO_CHAR(v_raw_result, 'UTF8');
END IF;
 
RETURN v_result;
 
EXCEPTION
    WHEN OTHERS THEN
        -- 解密失败时返回NULL
        RETURN NULL;
END;

四、使用示例

sql 复制代码
select AES_DECRYPT(ID_CARD) , AES_ENCRYPT(ID_CARD) from AES_SYS_USER

查询结果

数据库示例

相关推荐
吠品1 小时前
PG_GBK 与 PG_UTF8 编码冲突:一次数据导入踩坑复盘
数据库
lld9510271 小时前
我做了一个 AI Agent Skill 云:用 MCP 在 Claude Code、Codex、OpenCode 之间同步技能
数据库·人工智能
辉灰笔记2 小时前
MySQL8 意外关机/误移data目录导致服务启动失败 PID报错/权限报错 修复文档
linux·数据库·mysql·centos
麦聪聊数据3 小时前
电商大促数据库管控(下):数据需求小时级交付与全链路安全管控
数据库
喜欢的名字被抢了3 小时前
MySQL核心机制:事务、锁与存储引擎
数据库·sql·mysql·教程
JosieBook3 小时前
【数据库】时序数据库通过国测认证,TimechoAI开放体验:工业数据的“存”与“智”如何协同?
数据库·时序数据库
卓怡学长4 小时前
w263基于springboot + vue 健康饮食管理系统
java·数据库·vue.js·spring boot·spring·intellij-idea
阿演6 小时前
DataDjinn v0.2.11:SQL 编辑、AI 协作和表格操作继续打磨
数据库·人工智能·sql
不坑老师6 小时前
Excel总表如何按班级拆分并分别发送?
前端·数据库·人工智能·excel·ppt·office
智脑API平台7 小时前
Codex 国内使用会封号吗?账号安全、中转站和合规边界说明
数据库·redis·缓存