Skip to content

Personal tools
You are here: Home » 10g » Oracle10g Articles » Protect from Prying Eyes: Encryption in Oracle 10g - Part 2
Who Are You?
I am a:
Mainframe True Believer
Distributed Fast-tracker

[ Results | Polls ]
Votes : 3550

Protect from Prying Eyes: Encryption in Oracle 10g - Part 2

by Arup Nanda

Part 1  |  Part 2

In Part 1 of this article, we discussed some of the basics of data encryption, including what is encryption, encryption algorithms, what type of encryption scheme to use when, and more. Now, let’s take a look at the other side of encryption: decryption and its elements.


The DECRYPT function in the Crypto package provides the reverse of the encryption. Let’s decrypt the value we encrypted in part 1 of this article. Since the encryption value is in RAW, we can write the encryption and decryption in one session and pass the encrypted value. For this, we have defined a SQL*Plus variable named enc_val, as shown in line 3 in the following code. Lines 4 through 21 show the piece of code used to perform encryption of an input value called “ConfidentialData” and the rest of lines show the decryption of the encrypted value in the variable enc_val.

 1  REM  
2 REM Define a variable to hold the encrypted value
3 variable enc_val varchar2(2000);
4 declare
5 l_key varchar2(2000) := '1234567890123456';
6 l_in_val varchar2(2000) := 'ConfidentialData';
7 l_mod number := dbms_crypto.ENCRYPT_AES128
8 + dbms_crypto.CHAIN_CBC
9 + dbms_crypto.PAD_PKCS5;
10 l_enc raw (2000);
11 begin
12 l_enc := dbms_crypto.encrypt
13 (
14 UTL_I18N.STRING_TO_RAW (l_in_val, 'AL32UTF8'),
15 l_mod,
16 UTL_I18N.STRING_TO_RAW (l_key, 'AL32UTF8')
17 );
18 dbms_output.put_line ('Encrypted='||l_enc);
19 :enc_val := rawtohex(l_enc);
20 end;
21 /
22 declare
23 l_key varchar2(2000) := '1234567890123456';
24 l_in_val raw (2000) := hextoraw(:enc_val);
25 l_mod number := dbms_crypto.ENCRYPT_AES128
26 + dbms_crypto.CHAIN_CBC
27 + dbms_crypto.PAD_PKCS5;
28 l_dec raw (2000);
29 begin
30 l_dec := dbms_crypto.decrypt
31 (
32 l_in_val,
33 l_mod,
34 UTL_I18N.STRING_TO_RAW (l_key, 'AL32UTF8')
35 );
36 dbms_output.put_line
37 ('Decrypted='||utl_i18n.raw_to_char(l_dec));
38* end;

Line description

The code example noted just previously also needs some explanation:

      • Line 23 — The key is declared. Note the same key is used to encrypt that is used to decrypt as well.
      • Line 24 — Since the variable enc_val is in hexadecimal, we have converted it to raw.
      • Lines 35-27 — As in encryption, we have specified the algorithm and the padding and chaining schemes as a single parameter. Note that they are the same as in encryption. They have to be, in order for the decryption to work correctly.
      • Line 34 — As in encryption, the key must be in hexadecimal as well, so we converted it.

The output of the previous code example is “ConfidentialData,” which is the same value we encrypted earlier.

These are the basics of encryption and decryption using dbms_crypto package.

Hashing and MAC

Crypto also provides mechanisms for hashing and MAC, implemented through functions HASH and MAC respectively. Hashing can be done through three different algorithms. The most popular is MD5, a 128-bit hash function. There is also an MD4 (a predecessor to MD5), which is also 128-bit, but is less secure. The other competing standard is Secure Hash Algorithm (SHA-1), which produces a 160-bit hash.

As in case of encryption, hashing algorithms are implemented in the package as constants. HASH_SH1, HASH_MD4, and HASH_MD5 correspond to the algorithms SHA-1, MD4, and MD5, respectively.

The following is a simple case of Hashing using the algorithm SHA-1:

SQL> l
1 declare
2 l_in_val varchar2(2000) := 'CriticalData';
3 l_hash raw(2000);
4 begin
5 l_hash := dbms_crypto.hash (
6 UTL_I18N.STRING_TO_RAW (l_in_val, 'AL32UTF8'),
7 dbms_crypto.hash_sh1
8 );
9 dbms_output.put_line('Hash='||l_hash);
10* end;
SQL> /

PL/SQL procedure successfully completed.

Regardless of how many times this is executed, the hash value remains the same. You can change the algorithm by chaining the parameter in line 7 to the appropriate constant (i.e., dbms_crypto.hash_md5 for MD5).

Similarly, MAC is also implemented using MAC function in the package. Only MD5 and SHA-1 algorithms are supported in MAC. The constants that specify the algorithms are HMAC_SH1 and HMAC_MD5 representing SHA-1 and MD5, respectively.

Here is a simple implementation of the MAC function using SHA-1 algorithm

  1  declare
2 l_in_val varchar2(2000) := 'CriticalData';
3 l_key varchar2(2000) := '1234567890123456';
4 l_mac raw(2000);
5 begin
6 l_mac := dbms_crypto.mac (
7 UTL_I18N.STRING_TO_RAW (l_in_val, 'AL32UTF8'),
8 dbms_crypto.hmac_sh1,
9 UTL_I18N.STRING_TO_RAW (l_key, 'AL32UTF8')
10 );
11 dbms_output.put_line('MAC='||l_mac);
12* end;
SQL> /

PL/SQL procedure successfully completed.

As in the hashing example, we supplied the input value in RAW. However, unlike hashing, we have provided a key (line 9), which is what makes hash different from MAC. The key is also provided in RAW, just like the input value. While generating a MAC value, the same key must be used to perform the comparison.

Key Management

So far, we have talked about how to encrypt or decrypt data. In real life, however, that is not the more difficult challenge; it is in managing keys. Since security of the encrypted values is as tight as the security of the keys themselves, it is very important to protect the keys from falling into the wrong hands. In the following section, we will discuss the several options available for managing keys.

One Key Strategy

The simplest approach is using only one key for encrypting data. In this case, just one key must be generated and used, which could be used by users performing encryption and decryption. However, if this key is lost or stolen, the entire database becomes exposed. Therefore, the advantages of simplicity in management and risks of key theft must be balanced for a proper security.

The most common application of this strategy is in the field of mass data distribution — such as when a central location publishes data to its associated data centers in a secure manner. For example, an organization’s financial department could disseminate financial data to subsidiaries in a recordable media. The data could be encrypted in some pre-determined manner using a key that is known to both parties. The same key can be used in every circumstance of this scenario, since the parties involved are small and chances of leaks are low. But for most other applications, this is not a viable idea.

Multi-key Strategy

In sharp contrast to the one-key strategy, another is to use a key for each row of the table. In this case, even if a key is stolen or lost, only the corresponding row is exposed — not the entire database. This strategy adds more security, but also increases complexity in managing and maintaining keys.

Key Storage

Whether you choose the many- or single-key decision, you must also deal with the factor of where to locate the key. One option is to store the key in the operating system, which works well for single-key strategies. The other option is to store the key in the database.

Before making that call, you should be considering the following:

Are you trying to store keys in a location in which no one but a legitimate user can access them? If so, database storage will work out well. However, a DBA will be able to access the tables and keys; are you trying to conceal them from the DBA? No matter how you look at it, it is impossible to conceal them from the DBA using the dbms_crypto package. Thus, you should be considering other, more sophisticated options such as using a “wallet” to dispense keys from an external entity. This approach requires a fairly elaborate setup involving LDAP, Oracle Advanced Security, and more, and it is perhaps overkill, anyway. The bottom line is that using this package, a rogue DBA will be able to decrypt sensitive information.

What other potential incidents are you trying to prevent? Server or disk theft? That’s rare, but possible. In this case, storing the keys in the database exposes the database to the risk of theft, so an external file system should be used to hold keys. (Note that a server theft will not expose the disks.)

However, if the thieves steal the server disks as well as the external disks, this risk can materialize. To address that risk, you may decide to have the user carry the keys separately on his or her person using a USB disk or personal hard disk. This adds security, but increases complexity many times over, as well as carrying the risk of losing the key.

A more practical and reasonably secure strategy is to use a combination of keys:

      • A key for each row
      • A master key for the entire table

While encrypting, the actual key used is not the key stored for the row; rather, it is the XOR of the two values. The master key can be stored on a different location from the other keys. The intruder must find both the keys to successfully decrypt values. The following example is a demonstration of the scheme, shown as a variation of the original encrypt-decrypt demonstration.

We have added a new variable called l_master_key in line 6, which accepts a value from the user (the substitution variable  and master_key). In lines 14 through 17, we have XORed the key and the master key, which was used as the encryption key in line 22, instead of the l_key variable.

  1  REM
  2  REM Define a variable to hold the encrypted value
  3  variable enc_val varchar2(2000);
  4  declare
  5      l_key     varchar2(2000)    := '1234567890123456';
  6      l_master_key varchar2(2000) := '&master_key';
  7      l_in_val  varchar2(2000) := 'ConfidentialData';
  8      l_mod     number := dbms_crypto.ENCRYPT_AES128
  9                        + dbms_crypto.CHAIN_CBC
 10                        + dbms_crypto.PAD_PKCS5;
 11      l_enc     raw (2000);
 12      l_enc_key raw (2000);
 13  begin
 14      l_enc_key := utl_raw.bit_xor (
 15         UTL_I18N.STRING_TO_RAW (l_key, 'AL32UTF8'),
 16         UTL_I18N.STRING_TO_RAW (l_master_key, 'AL32UTF8'
 17      );
 18      l_enc := dbms_crypto.encrypt
 19         (
 20            UTL_I18N.STRING_TO_RAW (l_in_val, 'AL32UTF8'),
 21            l_mod,
 22            l_enc_key
 23         );
 24      dbms_output.put_line ('Encrypted='||l_enc);
 25      :enc_val := rawtohex(l_enc);
 26  end;
 27  /
 28  declare
 29      l_key     varchar2(2000)    := '1234567890123456';
 30      l_master_key varchar2(2000) := '&master_key';
 31      l_in_val  raw (2000) := hextoraw(:enc_val);
 32      l_mod     number := dbms_crypto.ENCRYPT_AES128
 33                        + dbms_crypto.CHAIN_CBC
 34                        + dbms_crypto.PAD_PKCS5;
 35      l_dec     raw (2000);
 36      l_enc_key raw (2000);
 37  begin
 38      l_enc_key := utl_raw.bit_xor (
 39         UTL_I18N.STRING_TO_RAW (l_key, 'AL32UTF8'),
 40         UTL_I18N.STRING_TO_RAW (l_master_key, 'AL32UTF8')
 41      );
 42      l_dec := dbms_crypto.decrypt
 43         (
 44            l_in_val,
 45            l_mod,
 46            l_enc_key
 47         );
 48      dbms_output.put_line ('Decrypted='||utl_i18n.raw_to_char(l_dec));
 49* end;

When we execute this block, here is what the output looks like:

Enter value for master_key: MasterKey0123456
old 3: l_master_key varchar2(2000) := '&master_key';
new 3: l_master_key varchar2(2000) := 'MasterKey0123456';

PL/SQL procedure successfully completed.

Enter value for master_key: MasterKey0123456
old 3: l_master_key varchar2(2000) := '&master_key';
new 3: l_master_key varchar2(2000) := 'MasterKey0123456';

PL/SQL procedure successfully completed.

This code example asked for the Master Key, which we supplied correctly, and the correct value popped up. But what if we supply a wrong Master Key?

Enter value for master_key: MasterKey0123456
old 3: l_master_key varchar2(2000) := '&master_key';
new 3: l_master_key varchar2(2000) :='MasterKey';

PL/SQL procedure successfully completed.

Enter value for master_key: MasterKey0123455
old 3: l_master_key varchar2(2000) := '&master_key';
new 3: l_master_key varchar2(2000) := 'WrongMasterKey';
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 41
ORA-06512: at line 15

Note the error in this: The use of a wrong master key did not expose the encrypted data. This enhanced security mechanism relies on two different keys, and both the keys must be present to successfully decrypt it.


Encryption is the art of disguising data to protect it from unauthorized intruders; authorized users can decrypt the data to look at the actual value. The Oracle-supplied package dbms_crypto provides all the implementations of the algorithms, and chaining and padding mechanisms commonly used in the cryptographic community. In this article, you learned how to use these methods to create an encryption system from scratch and how to work around the challenges to manage the keys securely.

It’s important to understand that encryption is not a substitute for common sense security such as a good authorization scheme or better security in the database. It’s designed to be the last resort defense to prevent an intruder from seeing sensitive data.

For more information on advanced encryption and sophisticated key management and user authentications using application contexts, you can refer to Oracle Privacy Security Auditing (ISBN 0972751394). You will also learn how to use the older dbms_obfuscation_toolkit to perform encryption and decryption.


Arup Nanda is the Lead DBA at Starwood Hotels & Resorts. He has been an Oracle DBA for more than 11 years, touching all aspects of database management — from modeling to performance tuning to disaster recovery. He is the co-author of the book Oracle Privacy Security Auditing (2003, Rampant Tech Press).

Arup Nanda
Last modified 2006-01-06 02:03 PM
Transaction Management
Reduce downtime and increase repeat sales by improving end-user experience.
Free White Paper
Database Recovery
Feeling the increased demands on data protection and storage requirements?
Download Free Report!

Powered by Plone