Oracle迁移到Oceanbase加密数据注意事项
最近有个项目上oracle迁移到ocenabase,但是应用中使用Oracle的数据库内加密函数,数据库中存储的是加密数据,这里有两个注意事项,首先是对于加密函数是否兼容,其次是数据库内的加密数据,如何同步及同步到目标库后已加密码数据能否解密的问题。
2011年在搞oracle 10g时,当时测试也简单测试过<oracle10G 加密解密之dbms_crypto (一)>,<oracle 9i 的加密解密用法之dbms_obfuscation_toolkit(一)> , 主要是两个package dbms_obfuscation_toolkit 和dbms_crypto, 主要是两类,一是生成加密哈希算法,如最常见的MD5,二是生成加密算法,如DES和AES。 目前Oceanbase V4版本中自带了dbms_crypto 用于兼容Oracle模式,下面测试两个值是否相同。
MD5 hash测试
-- Oracle create or replace function obfuscation_md5(p_in varchar2) return varchar2 is begin return RawToHex(UTL_RAW.CAST_TO_RAW(dbms_obfuscation_toolkit.MD5(input_string=>p_in))); end; / CREATE OR REPLACE FUNCTION CRYPTO_md5(p_string IN VARCHAR2) RETURN VARCHAR2 IS v_hash RAW(2000); BEGIN v_hash := DBMS_CRYPTO.HASH( src => UTL_I18N.STRING_TO_RAW(p_string, 'AL32UTF8'), typ => DBMS_CRYPTO.HASH_MD5 ); RETURN LOWER(RAWTOHEX(v_hash)); END CRYPTO_md5; / SQL> select obfuscation_md5('anbob.com') from dual; obfuscation_md5('ANBOB.COM') -------------------------------------------------------------- 354A5B219144A6B3833864596D87DE6A SQL> SELECT CRYPTO_md5('anbob.com') from dual; CRYPTO_md5('ANBOB.COM') -------------------------------------------------------------- 354a5b219144a6b3833864596d87de6a
Note:
MD5是一种不可逆的hash算法,对于相同字符串的值生成的值是相同的,所以加密来说并不安全,可以通过MD5值反向碰撞解密。
-- Linux $ echo -n anbob.com|md5sum |cut -d" " -f1 354a5b219144a6b3833864596d87de6a
Note:
在操作系统层使用md5sum一样也可以生成,值与数据库生成的相同
-- Oceanbase for Oracle mode obclient(root@sys)[oceanbase]> select md5('anbob.com'); +----------------------------------+ | md5('anbob.com') | +----------------------------------+ | 354a5b219144a6b3833864596d87de6a | +----------------------------------+ 1 row in set (0.006 sec) obclient(SYS@orcl)[SYS]> CREATE OR REPLACE FUNCTION CRYPTO_md5(p_string IN VARCHAR2) RETURN VARCHAR2 IS v_hash RAW(2000); BEGIN v_hash := DBMS_CRYPTO.HASH( src => UTL_I18N.STRING_TO_RAW(p_string, 'AL32UTF8'), typ => DBMS_CRYPTO.HASH_MD5 ); RETURN LOWER(RAWTOHEX(v_hash)); END CRYPTO_md5; / Query OK, 0 rows affected (0.875 sec) obclient(SYS@orcl)[SYS]> SELECT CRYPTO_md5('anbob.com') from dual; +----------------------------------+ | CRYPTO_md5('ANBOB.COM') | +----------------------------------+ | 354a5b219144a6b3833864596d87de6a | +----------------------------------+ 1 row in set (0.427 sec)
Note:
在Oceanbase中可以使用md5函数和DBMS_CRYPTO生成的是一样的。 所以如果只是md5值,在oracle还是ocenabase生成的值是相同的。
安全散列算法 (SHA-1) hash测试
CREATE OR REPLACE FUNCTION get_sh1_hash(p_string IN VARCHAR2) RETURN VARCHAR2 IS v_hash RAW(2000); BEGIN v_hash := DBMS_CRYPTO.HASH( src => UTL_I18N.STRING_TO_RAW(p_string, 'AL32UTF8'), typ => DBMS_CRYPTO.HASH_SH1 ); RETURN LOWER(RAWTOHEX(v_hash)); END get_sh1_hash; / -- Oracle SQL> select get_sh1_hash('anbob.com') from dual; GET_SH1_HASH('ANBOB.COM') ------------------------------------------------------------------------- 826fddf9a33a45bf8d6968887a2565e06ea31389 -- Oceanbase for Oracle mode obclient(SYS@orcl)[SYS]> select get_sh1_hash('anbob.com') from dual; +------------------------------------------+ | GET_SH1_HASH('ANBOB.COM') | +------------------------------------------+ | 826fddf9a33a45bf8d6968887a2565e06ea31389 | +------------------------------------------+ 1 row in set (0.139 sec)
Note:
生成sh安全散列的值在oracle与ocenabase也是相同的。
加密背景
在 Oracle 数据库中,DBMS_OBFUSCATION_TOOLKIT
是 Oracle 早期提供的加密工具包,在较新版本中已被 DBMS_CRYPTO
取代。DBMS_CRYPTO 包提供了强大的加密功能。提供不同的加密算法,在Oceanbase中同样支持这个package, 加密算法支持DES\AES\SM. DBMS_CRYPTO 不直接支持 VARCHAR2 数据类型。在对 VARCHAR2 类型的数据执行加密操作之前,必须将其转换为统一数据库字符集 AL32UTF8,然后将其转换为 RAW 数据类型。完成这些转换后,可以使用 DBMS_CRYPTO 系统包对其进行加密。
加密算法需要明确指定三个关键组件,而不仅仅是基础算法(如 ENCRYPT_DES)。这是因为加密过程需要完整的参数组合才能正常工作。
Oracle 要求加密操作必须明确指定:
基础算法(如 ENCRYPT_DES):定义核心加密方法(这里是 DES)。
分组模式(如 CHAIN_CBC):定义如何分块处理数据。
填充方案(如 PAD_PKCS5):定义如何填充不满足块大小的数据。
这三个部分通过 按位或(+) 组合成一个完整的加密参数。
-- 典型的安全组合:DES + CBC + PKCS5 l_mod NUMBER := DBMS_CRYPTO.ENCRYPT_DES + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5;
DES 的块大小是 8 字节。如果数据长度不是 8 的倍数,最后一个块需要填充。
PKCS#5 填充 会添加字节,使总长度为块大小的整数倍。例如:
原始数据:’ABC’(3 字节)
填充后:’ABC\x05\x05\x05\x05\x05’(补 5 个 0x05,共 8 字节)
DBMS_OBFUSCATION_TOOLKIT 仅支持DES和MD5, DBMS_CRYPTO 支持更多算法,DBMS_OBFUSCATION_TOOLKIT 固定使用CBC模式和PKCS5填充,DBMS_CRYPTO 允许自定义这些参数
字符集问题:
对于多字节字符(如中文),建议先转换为AL32UTF8编码
可以使用UTL_I18N.STRING_TO_RAW替代UTL_RAW.CAST_TO_RAW
obclient(SYS@orcl)[SYS]> select UTL_I18N.STRING_TO_RAW('anbob.com') from dual; +-------------------------------------+ | UTL_I18N.STRING_TO_RAW('ANBOB.COM') | +-------------------------------------+ | 616E626F622E636F6D | +-------------------------------------+ obclient(SYS@orcl)[SYS]> select utl_raw.cast_to_raw('anbob.com') from dual; +----------------------------------+ | UTL_RAW.CAST_TO_RAW('ANBOB.COM') | +----------------------------------+ | 616E626F622E636F6D | +----------------------------------+
dbms_obfuscation_toolkit 加密、解密测试
oracle支持,oceanbase不支持。
create or replace function encrypt_obfuscation1(p_in varchar2,p_key varchar2) return raw is v_rtn varchar2(1000); l_encrypted varchar2(1000); begin dbms_obfuscation_toolkit.desencrypt(input_string=>p_in,key_string=>p_key,ENCRYPTED_STRING=>l_encrypted); return UTL_RAW.CAST_TO_RAW(l_encrypted); end; / SQL> select encrypt_obfuscation1('12345a23','anbob.com') from dual; ENCRYPT_OBFUSCATION('12345A23','ANBOB.COM') --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 2F7D6C1D2B798562 SQL> select encrypt_obfuscation1('12345a2323','anbob.com') from dual; select encrypt_obfuscation1('12345a2323','anbob.com') from dual * ERROR at line 1: ORA-28232: invalid input length for obfuscation toolkit ORA-06512: at "SYS.DBMS_OBFUSCATION_TOOLKIT_FFI", line 21 ORA-06512: at "SYS.DBMS_OBFUSCATION_TOOLKIT", line 115 ORA-06512: at "SYS.ENCRYPT_OBFUSCATION1", line 8
Note:
加密数据必须为8字节或倍数,使用补充。
create or replace function encrypt_obfuscation(p_in varchar2,p_key varchar2) return varchar2
is
v_in varchar2(255);
v_rtn varchar2(1000);
begin
v_in := rpad(p_in,(trunc(length(p_in)/8)+1)*8,chr(0));
return UTL_RAW.CAST_TO_RAW(dbms_obfuscation_toolkit.desencrypt(input_string=>v_in,key_string=>p_key));
end;
/
SQL> select encrypt_obfuscation('12345a234','anbob.com') from dual;
ENCRYPT_OBFUSCATION('12345A234','ANBOB.COM')
---------------------------------------------------------
2F7D6C1D2B79856235D3647FB7F129B3
create or replace function decrypt_obfuscation(p_in varchar2,p_key varchar2) return varchar2
is
v_in varchar2(2000);
begin
dbms_obfuscation_toolkit.DESDECRYPT(input_string => UTL_RAW.CAST_TO_varchar2(p_in),key_string => p_key,
decrypted_string=> v_in);
v_in := rtrim(v_in,chr(0));
return v_in;
end;
/
SQL> select decrypt_obfuscation('2F7D6C1D2B79856235D3647FB7F129B3','anbob.com') from dual;
DECRYPT_OBFUSCATION('2F7D6C1D2B79856235D3647FB7F129B3','ANBOB.COM')
----------------------------------------------------------------------------
12345a234
Note:
不是8字节的倍数,使用cha(0)补充。
dbms_crypto DES加密测试
DES 需要 8 字节密钥,DES 算法已被认为不够安全(56位有效密钥长度),生产环境建议使用 AES(DBMS_CRYPTO.ENCRYPT_AES256)
-- ORACLE SQL> r 1 DECLARE 2 l_credit_card_no VARCHAR2(19) := '1234-5678-9012-3456'; 3 l_ccn_raw RAW(128) := utl_raw.cast_to_raw(l_credit_card_no); 4 l_key RAW(128) := utl_raw.cast_to_raw('anbob.com'); 5 6 l_encrypted_raw RAW(2048); 7 l_decrypted_raw RAW(2048); 8 BEGIN 9 dbms_output.put_line('Original : ' || l_credit_card_no); 10 11 dbms_output.put_line('Key : ' || utl_raw.cast_to_varchar2(l_key)); 12 13 l_encrypted_raw := dbms_crypto.encrypt(l_ccn_raw, 14 dbms_crypto.des_cbc_pkcs5, l_key); 15 16 dbms_output.put_line('Encrypted : ' || 17 RAWTOHEX(utl_raw.cast_to_raw(l_encrypted_raw))); 18 19 l_decrypted_raw := dbms_crypto.decrypt(src => l_encrypted_raw, 20 typ => dbms_crypto.des_cbc_pkcs5, key => l_key); 21 22 dbms_output.put_line('Decrypted : ' || 23 utl_raw.cast_to_varchar2(l_decrypted_raw)); 24* END; Original : 1234-5678-9012-3456 Key : anbob.com Encrypted : 373037393732333945383935463138364641344231353635454245423846413744453632453243444145433144383337 Decrypted : 1234-5678-9012-3456 PL/SQL procedure successfully completed. -- Oceanbase for Oracle mode obclient(SYS@orcl)[SYS]> set serveroutput on obclient(SYS@orcl)[SYS]> DECLARE -> l_credit_card_no VARCHAR2(19) := '1234-5678-9012-3456'; -> l_ccn_raw RAW(128) := utl_raw.cast_to_raw(l_credit_card_no); -> l_key RAW(128) := utl_raw.cast_to_raw('anbob.com'); -> -> l_encrypted_raw RAW(2048); -> l_decrypted_raw RAW(2048); -> BEGIN -> dbms_output.put_line('Original : ' || l_credit_card_no); -> -> dbms_output.put_line('Key : ' || utl_raw.cast_to_varchar2(l_key)); -> -> l_encrypted_raw := dbms_crypto.encrypt(l_ccn_raw, -> dbms_crypto.des_cbc_pkcs5, l_key); -> -> dbms_output.put_line('Encrypted : ' || -> RAWTOHEX(utl_raw.cast_to_raw(l_encrypted_raw))); -> -> l_decrypted_raw := dbms_crypto.decrypt(src => l_encrypted_raw, -> typ => dbms_crypto.des_cbc_pkcs5, key => l_key); -> -> dbms_output.put_line('Decrypted : ' || -> utl_raw.cast_to_varchar2(l_decrypted_raw)); -> END; -> / Query OK, 1 row affected (0.881 sec) Original : 1234-5678-9012-3456 Key : anbob.com Encrypted : 373037393732333945383935463138364641344231353635454245423846413744453632453243444145433144383337 Decrypted : 1234-5678-9012-3456
Note:
加密码使用相同秘钥生成的值也是一样的。
dbms_crypto DES加密 解密测试
CREATE OR REPLACE PACKAGE encrypt_decrypt AS FUNCTION encrypt (p_plainText VARCHAR2) RETURN RAW DETERMINISTIC; FUNCTION decrypt (p_encryptedText RAW) RETURN VARCHAR2 DETERMINISTIC; END; / CREATE OR REPLACE PACKAGE BODY encrypt_decrypt AS encryption_type PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_DES + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5; encryption_key RAW (32) := UTL_RAW.cast_to_raw('anbob.com'); FUNCTION encrypt (p_plainText VARCHAR2) RETURN RAW DETERMINISTIC IS encrypted_raw RAW (2000); BEGIN encrypted_raw := DBMS_CRYPTO.ENCRYPT ( src => UTL_RAW.CAST_TO_RAW (p_plainText), typ => encryption_type, key => encryption_key ); RETURN encrypted_raw; END encrypt; FUNCTION decrypt (p_encryptedText RAW) RETURN VARCHAR2 DETERMINISTIC IS decrypted_raw RAW (2000); BEGIN decrypted_raw := DBMS_CRYPTO.DECRYPT ( src => p_encryptedText, typ => encryption_type, key => encryption_key ); RETURN (UTL_RAW.CAST_TO_VARCHAR2 (decrypted_raw)); END decrypt; END; / -- Oracle SQL> select encrypt_decrypt.encrypt('anbob') from dual; ENCRYPT_DECRYPT.ENCRYPT('ANBOB') ---------------------------------------------------- 059F611EC2A5395D SQL> select encrypt_decrypt.decrypt('059F611EC2A5395D') from dual; ENCRYPT_DECRYPT.DECRYPT('059F611EC2A5395D') ---------------------------------------------------- anbob -- Oceanbase obclient(SYS@orcl)[SYS]> select encrypt_decrypt.encrypt('anbob') from dual; +----------------------------------+ | ENCRYPT_DECRYPT.ENCRYPT('ANBOB') | +----------------------------------+ | 059F611EC2A5395D | +----------------------------------+ 1 row in set (0.258 sec) obclient(SYS@orcl)[SYS]> select encrypt_decrypt.decrypt('059F611EC2A5395D') from dual; +---------------------------------------------+ | ENCRYPT_DECRYPT.DECRYPT('059F611EC2A5395D') | +---------------------------------------------+ | anbob | +---------------------------------------------+ 1 row in set (0.017 sec)
Note:
加密解密的方法在Oracle和oceanbase中的PLSQL完全兼容,值也相同。
dbms_obfuscation_toolkit 加密dbms_crypto解密
-- dbms_obfuscation_toolkit SQL> select encrypt_obfuscation('12345678aa','anbob.com') from dual; ENCRYPT_OBFUSCATION('12345678AA','ANBOB.COM') --------------------------------------------------------------- DF0126398E1CFEB38BC840B927C02789 -- DBMS_CRYPTO SQL> select encrypt_decrypt.encrypt('12345678aa') from dual; ENCRYPT_DECRYPT.ENCRYPT('12345678AA') ------------------------------------------------------------ DF0126398E1CFEB34C95F6536264F9BB -- dbms_obfuscation_toolkit select decrypt_obfuscation('DF0126398E1CFEB34C95F6536264F9BB','anbob.com') from dual; DECRYPT_OBFUSCATION('DF0126398E1CFEB34C95F6536264F9BB','ANBOB.COM') ----------------------------------------------------------------------------------- 12345678aa -- DBMS_CRYPTO select encrypt_decrypt.decrypt('DF0126398E1CFEB38BC840B927C02789') from dual; ERROR at line 1: ORA-28817: PL/SQL function returned an error. ORA-06512: at "SYS.DBMS_CRYPTO_FFI", line 67 ORA-06512: at "SYS.DBMS_CRYPTO", line 44 ORA-06512: at "SYS.ENCRYPT_DECRYPT", line 26
Note:
两个方法生成的密文前半部分相同,但后半部分不同, DBMS_CRYPTO加密的dbms_obfuscation_toolkit可以解密,但是dbms_obfuscation_toolkit加密的DBMS_CRYPTO不可以解密。
总结
声明,我并不是安全专家,Oceanbase支持较新的DBMS_CRYPTO加密和解密,生成的MD5或sha hash是相同的,但是加密算法的值有不同,虽然我测试的dec加密在相同的秘钥下,部分密文相同,使用dbms_obfuscation_toolkit可以解密DBMS_CRYPTO的加密密文,但是不建议这种跨方法的加密解密。所以如果跨数据库如应用之前在oracle使用dbms_obfuscation_toolkit加密,但加密数据在同步到oceanbase前需要解密,再同步重新使用新方法加密。
上一篇:
下一篇: Oceanbase 分布事务XA注意事项
目前这篇文章还没有评论(Rss)