当前位置: 首页 > 工具软件 > Crypto-Wallet > 使用案例 >

Oracle之DBMS_CRYPTO包的使用(加密包)

何超英
2023-12-01

关于加密的内容比较较多,我这里主要介绍使用DBMS_CRYPTO进行对数据的加密以及加密后的数据进行解密。下面我们以例子的形式进行说明。
如果要使用dbms_crypto包,需要授予如下权限:
SQL> grant execute on dbms_crypto to djp01
2 /

Grant succeeded.

SQL>

下面,我们看一个数据加密的例子:
SQL> set serveroutput on
SQL> declare
2 l_src_data varchar2(20) := ‘Source Data’;
3
4 l_type pls_integer := dbms_crypto.encrypt_aes128 +
5 dbms_crypto.pad_pkcs5 +
6 dbms_crypto.chain_cbc;
7 l_key varchar2(16) := ‘0123456789123456’;
8
9 l_encval raw(2000);
10 begin
11 l_encval := dbms_crypto.encrypt(
12 src=>utl_i18n.string_to_raw(l_src_data,‘AL32UTF8’),
13 typ=>l_type,
14 key=>utl_i18n.string_to_raw(l_key,‘AL32UTF8’));
15 dbms_output.put_line(l_encval);
16 end;
17 /
2644B3DAB5C617B67423F6CB7F3B91B0

PL/SQL procedure successfully completed.

SQL>
说明:在第2行,我声明了要进行加密的数据。第4,6行中,指定加密的算法(encrypt_aes128),填充方法(pad_pkcs5)以及连方法(chain_cbc)。当对一段数据进行加密时,算法不会对数据整体加密,通常会分成8个字节的小块,对每个小块进行加密;如果数据恰好不够8位时,这时,需要进行填充,补齐8字节。当数据被拆分成小块加密后,需要将其相邻的小块进行连接起来。第11行中,使用encrypt函数进行加密操作,加密后的结果以raw型进行返回。我这里使用的是utl_i18n.string_to_raw进行数据类型的转换,这是因为encrypt函数不但需要raw型数据,而且还需要使用专门的字符集——AL32UTF8,这里如果使用utl_raw.cast_to_raw,则会出现“ORA-06502”错误。第7行的字密钥长度要注意一下,这里使用的是十六位,是因为加密算法使用的是128位的加密算法,每8位进行加密的话,那么128除以8,正好是16位,所以密钥长度必须是16位,不能太长或太短,否则会出现“ORA-28234”错误。
下面我们列出一些dbms_crypto包加密算法的算法常量:
ENCRYPT_DES:标准数据加密。有效的键长度为56位,
ENCRYPT_3DES_2KEY:修改过的3DES,用两个密钥对每个数据块加密3次。有效的键长度为112位。
ENCRYPT_3DES:对每一个数据块加密3次。有效的键长度为156位。
ENCRYPT_AES128:高级加密标准。有效的键长度为128位。
ENCRYPT_AES192:高级加密标准。有效的键长度为192位。
ENCRYPT_AES256:高级加密标准。有效的键长度为256位。
ENCRYPT_RC4:唯一一个流加密,它被用于加密数据流,而不是离散数据或是表态数据。
DBMS_CRYPTO包的填充常量:
PAD_PKCS5:用PKCS#5填充。
PAD_ZERO:用零填充。
PAD_NONE:不进行填充,如果假设数据块的长度正好是8个字节,则可以使用这个方法。
DBMS_CRYPT0包的连接常量:
CHAIN_CBC:密码块连接,是最常用的方法。
CHAIN_CFB:加密反馈模式。
CHAIN_ECB:电子源码书格式。
CHAIN_OFB:输入回馈模式。
关于算法的详细信息,请查阅相关资料。

如果要加密的数据较大时(比如超过varchar2的最大值),我们也可以使用LOB类型。如下:
SQL> declare
2 l_src_data clob := ‘2644B3DAB5C617B67423F6CB7F3B91B0’;
3 l_dst_data blob;
4
5 l_type pls_integer := dbms_crypto.encrypt_aes128 +
6 dbms_crypto.pad_pkcs5 +
7 dbms_crypto.chain_cbc;
8
9 l_key varchar2(16) := ‘0123456789123456’;
10 begin
11 dbms_crypto.encrypt(
12 dst=>l_dst_data,
13 src=>l_src_data,
14 typ=>l_type,
15 key=>utl_i18n.string_to_raw(l_key,‘AL32UTF8’));
16 end;
17 /
说明:该程序没有执行成功,出现了“ORA-01405”异常。这个问题有待解决。

对于加密过的数据,我们使用两样的算法和KEY值可以将其进行解密,如下:
SQL> declare
2 l_src_data raw(100) := hextoraw(‘2644B3DAB5C617B67423F6CB7F3B91B0’);
3
4 l_type pls_integer := dbms_crypto.encrypt_aes128 +
5 dbms_crypto.pad_pkcs5 +
6 dbms_crypto.chain_cbc;
7
8 l_key varchar2(16) := ‘0123456789123456’;
9 l_decval raw(200);
10 begin
11 l_decval := dbms_crypto.decrypt(
12 src=>l_src_data,
13 typ=>l_type,
14 key=>utl_i18n.string_to_raw(l_key,‘AL32UTF8’));
15
16 dbms_output.put_line(utl_i18n.raw_to_char(l_decval));
17 end;
18 /
Source Data

PL/SQL procedure successfully completed.

SQL>
说明:我们通过对加密后的数据进行解密,可以得到被加密前的数据。在第2行,这里要注意一下,对于加密后的数据进行解密,我们必须使用hextoraw函数转化,因为加密后的数据是以十六进制显示的,必须转化成raw型的。如果我们使用“l_src_data varchar2(100) := ‘2644B3DAB5C617B67423F6CB7F3B91B0’,utl_i18n.string_to_raw(l_src_data,‘AL32UTF8’)”这样的形式,那么会出现“ORA-28817”错误。

上述的过程中,我们使用的密钥时常简单,这样的话,很容易被猜到。对于密钥,我们可以用如下的方法生成:
SQL> declare
2 l_src_data varchar2(20) := ‘Source Data’;
3
4 l_type pls_integer := dbms_crypto.encrypt_aes128 +
5 dbms_crypto.pad_pkcs5 +
6 dbms_crypto.chain_cbc;
7
8 l_key raw(16);
9 l_encval raw(200);
10
11 l_key_char varchar2(100);
12 begin
13 l_key := dbms_crypto.randombytes(16);
14 l_key_char := utl_i18n.raw_to_char(l_key);
15 dbms_output.put_line(‘raw:’||l_key||’ char:’||l_key_char);
16
17 l_encval := dbms_crypto.encrypt(
18 src=>utl_i18n.string_to_raw(l_src_data,‘AL32UTF8’),
19 typ=>l_type,
20 key=>l_key);
21 dbms_output.put_line(l_encval);
22 end;
23 /
raw:88424373FBFA72B1F4E58034BE7F0201 char:?BCs??r????
8FF93017257562B910C02D1D9A910CFA

PL/SQL procedure successfully completed.

SQL>
说明:在第13行,使用了randombytes函数,该函数用于返回一个raw型的随机数,该函数的参数为raw的长度。我通过使用utl_i18n.raw_to_char将其转化成字符型,则出现了乱码。

下面,我们来看一下散列加密。同样,我们使用例子进行说明。
SQL> declare
2 l_src_data varchar2(50) := ‘Source Data’;
3 l_hash raw(200);
4 begin
5 l_hash := dbms_crypto.hash(
6 src=>utl_i18n.string_to_raw(l_src_data,‘AL32UTF8’),
7 typ=>dbms_crypto.hash_md5);
8
9 dbms_output.put_line(l_hash);
10 end;
11 /
9C20448EB13AE72A8AA4099A6DB7B092

PL/SQL procedure successfully completed.

SQL>
说明:对散列加密,我们使用dbms_crypto下的hash函数,它返回的是一个raw型的数据。在第7行,指定散列类型,为hash_md5。对于散列类型,还有其他两种为hash_md4,hash_sh1。
对于使用散列加密,它有一个特点就是不可解密,加密后的值,无法通过“反向工程”回到原先的值。在理论上,两个不同的输入值,可能会得到相同的哈唏值。如果我们使用hash_md5或hash_sh1,它相同的概率极其微小,大约为10的38次方分之一。
哈唏加密,常用于对密码加密。

对于散列加密,还有另一种散列加密,叫消息验证码。它在散列加密的基础上使用了密钥措施,对于相同的输入,如果密钥不同,则产生的数据也将不同。该方法虽然有密钥,但是同散列加密一样,无法从加密后的数据,获得原数据。例子如下:
SQL> declare
2 l_src_data varchar2(50) := ‘Source Data’;
3 l_key varchar2(100) := ‘Secret Key’;
4 l_mac raw(200);
5 begin
6 l_mac := dbms_crypto.mac(
7 src=>utl_i18n.string_to_raw(l_src_data,‘AL32UTF8’),
8 typ=>dbms_crypto.hmac_sh1,
9 key=>utl_i18n.string_to_raw(l_key,‘AL32UTF8’));
10 dbms_output.put_line(l_mac);
11
12 l_key := ‘Another Key’;
13 l_mac := dbms_crypto.mac(
14 src=>utl_i18n.string_to_raw(l_src_data,‘AL32UTF8’),
15 typ=>dbms_crypto.hmac_sh1,
16 key=>utl_i18n.string_to_raw(l_key,‘AL32UTF8’));
17 dbms_output.put_line(l_mac);
18 end;
19 /
9254874CB460063F5B1AFF6781285542796D6656
F670CE519DC59B8FDAD6460DF7794C28710D6A21

PL/SQL procedure successfully completed.


作者:–扑朔迷離
来源:CSDN
原文:https://blog.csdn.net/zg_memory/article/details/40371769
版权声明:本文为博主原创文章,转载请附上博文链接!

 类似资料: