GBase 8a集群迁移某个Oracle自定义加解密函数方法总结
一、概述
笔者所在项目近期对一个Oracle自定义加解密函数进行了GBase 8a集群迁移,在对中文字符串的处理过程中碰到了一些问题,经过优化改写最终得以解决,其中部分函数的迁移转换方法具有一定参考意义,故进行总结记录。
二、场景环境
Oracle版本:11g,默认字符集GBK
GBase 8a集群版本:GBase8a_MPP_Cluster-9.5.2.46.6-centos8-x86_64,默认字符集UTF-8
三、需求描述
将Oracle的自定义加解密函数crypt_data迁移至GBase 8a集群,目前的业务场景为将Oracle加密结果数据传送至GBase 8a集群中完成解密。
自定义加解密函数功能概述:
加密,通过ascii函数将字符转换为码值,对该码值进行一系列加减乘除操作,然后将变换后的码值转换回字符,最后通过base64函数加密,得到加密结果字符。
解密,通过base64函数解密字符,再通过ascii函数将该字符转换为码值,对该码值进行反向加减乘除操作,最后将变换后的码值转换为字符,得到解密字符。
四、Oracle函数及主要迁移转换内容
Oracle函数内容如下(简化版):
加密:

解密:



迁移中主要涉及转换的oracle系统函数:
1)ascii,转换为ord,对于多字节字符(中文),8a的ascii函数返回值在0-255,与oracle的不同,此处转换为ord。
2)base64_encode/base64_decode, 转换为to_base64/from_base64。
迁移8a集群后的简化版函数:
create function crypt_data_s(src varchar(300), ende varchar(300)) returns varchar(300)
character set gbk
-- charset binary
begin
declare ret varchar(1024);
declare v_ret varchar(1024);
declare v_src1 varchar(1024);
declare i int;
declare lens int;
declare j bigint;
set i = 1;
set ret = '';
set lens = char_length(src);
if ende = '1'
then
-- return src;
-- 加密操作
while i <= lens
do
-- 将原始字符转换为ascii码,并对编码进行加减转换操作,再转换为字符
set j = ord(substr(src, i, 1)) + 13;
-- return j;
-- return char(j);
set ret = concat(ret, char(j));
-- return ret;
set i = i + 1;
end while;
-- 用base64加密得到结果
return to_base64(ret);
else
-- return src;
-- 解密操作
-- 用base64解密加密字符
set v_src1 = from_base64(src);
-- return v_src1;
-- return lens;
while i <= lens
do
-- 将解密字符转换为asccii码,并对编码进行加减转换操作,再转换回字符得到结果
set j = decode(ord(substr(v_src1, i, 1)),'',null,ord(substr(v_src1, i, 1))) - 13;
-- return j;
set ret = concat(ret, char(j));
-- return ret;
/*
if i = 1
then
-- return substr(v_src1, i, 1);
return j;
return ret;
end if;
*/
set i = i + 1;
end while;
return ret;
end if;
end
//
delimiter ;
五、问题及处理方法
初次迁移后的函数存在下列问题:
英文及特殊符号的加解密操作测试通过,部分中文字符的加解密在执行过程中会报错,报错信息形如:Incorrect string value: '\xBA\x07' for column 'ret' at row 1。
经过分析,需要调整的内容如下(针对中文字符):
加密,原始字符转换为ascii码,并对编码进行加减转换操作,转换为字符后,需要再通过binary格式转换再拼接起来,否则可能会造成多字节字符无法识别异常。调整的主要内容如下:
set ret = concat(ret, char(j using binary));
解密,GBase 8a的中文为双字节字符(GBK字符集),在逐个获取解密串的字符过程中,要取双字节(英文字符是单字节)。调整的主要内容如下:
set tmpValue = substr(descryptStrWithSalt,posstart,2)
此外,在逐个获取加密串字符进行反向加减乘除转换时,需要使用hex、conv函数依次转换为16、10进制后再进行反向加减乘除转换操作。在合并最终结果串时,需要用convert函数转换为GBK字符。调整的主要内容如下:
set tmpValue = unhex(conv(conv(hex(tmpValue),16,10)-13,10,16));
set ret = concat(ret,convert(tmpValue using gbk));
最终迁移后的8a集群函数如下(简化版):
create function crypt_data_s(src varchar(300) character set gbk, ende varchar(300)) returns varchar(300)
character set gbk
begin
declare ret varchar(1024) character set binary;
declare tmpValue varchar(10) character set binary;
declare v_ret varchar(1024);
declare descryptstrwithSalt varbinary(1024);
declare i int;
declare lens int;
declare j int;
declare posstart int;
set ret = '';
if ende = '1'
then
set i = 1;
set lens = char_length(src);
-- return src;
-- 加密操作
while i <= lens
do
-- 将原始字符转换为ascii码,并对编码进行加减转换操作,再转换为字符
set j = ord(substr(src, i, 1)) + 13;
-- return j;
-- return char(j);
set ret = concat(ret, char(j using binary));
-- return ret;
set i = i + 1;
end while;
-- 用base64加密得到结果
return to_base64(ret);
else
-- set posstart = instr(src,salt);
-- set src = substr(src, posstart+2);
set descryptStrWithSalt = from_base64(src);
set lens = length(descryptStrwithSalt);
set posstart = 1;
while lens > 0
do
set tmpValue = substr(descryptstrwithSalt,posstart,1);
if (tmpValue > 0x80) then -- gbk双字节
set tmpValue = substr(descryptStrWithSalt,posstart,2);
set tmpValue = unhex(conv(conv(hex(tmpValue),16,10)-13,10,16));
set posstart = posstart + 2;
set lens = lens - 2;
else -- 单字节
set tmpValue = unhex(conv(conv(hex(tmpValue),16,10)-13,10,16));
set posstart = posstart + 1;
set lens = lens - 1;
end if;
set ret = concat(ret,convert(tmpValue using gbk));
end while;
return ret;
end if;
end
//
delimiter ;
评论
热门帖子
- 12025-12-01浏览数:182764
- 22023-05-09浏览数:25062
- 42023-09-25浏览数:18526
- 52020-05-11浏览数:17529