GBase 8a
适配迁移
文章

GBase 8a集群迁移某个Oracle自定义加解密函数方法总结

发表于2025-01-08 17:46:4419次浏览0个评论

一、概述

笔者所在项目近期对一个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 ;

   

评论

登录后才可以发表评论