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

来源:互联网 发布:windows是比尔盖茨 编辑:程序博客网 时间:2024/06/05 01:37
关于加密的内容比较较多,我这里主要介绍使用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.

0 0
原创粉丝点击