4.4. Key Management in Oracle Database 10gYou've learned the basics of how to use encryption and decryption, as well as how to generate keys. But that's the easy part; for the most part, we've simply used Oracle's supplied programs and built wrappers around them to get the job done. Now comes the more challenging aspect of the encryption infrastructuremanaging the key. Our applications will need to have access to the key to decrypt the encrypted values, and this access mechanism should be as simple as possible. On the other hand, the key should not be so simple as to be accessible to hackers. A proper key management system balances the simplicity of key access against prevention of unauthorized access to the keys. There are essentially three different types of key management:
The following sections describe these different approaches to key management.
4.4.1. Using a Single KeyWith this approach, a single key is used to access any data in the database. As shown in Figure 4-3, the encryption routine reads only one key from the key location and encrypts all the data that needs to be protected. This key could be stored in a variety of locations:
The biggest advantage of using a single key is that the encryption/decryption routines will not need to select keys from tables or store them every time a record is manipulated in the base table. The result is that performance is generally better because of reduced CPU cycles and I/O operations. The biggest disadvantage of this approach is its dependence on a single point of failure. If an intruder breaks into the database and determines the key, the entire database becomes immediately vulnerable. In addition, if you want to change the key, you will need to change all of the rows in all of the tables, which may be quite an extensive task in a large database (see Figure 4-3). Because of these disadvantages, particularly the consequences of key theft, this approach is used only infrequently. There are a few cases where it may be useful. One example is a data publication system where a key is generally used only once during transmission of data; after transmission, the key is destroyed and a new key is used for the next transmission. Such a system might be used by financial-data publication houses sending analytical data to customers or in a situation where one division of a company is sending confidential corporate data to the other divisions or to company headquarters. 4.4.2. Using a Key for Each RowWith the second approach, a different key is used for each row of a table, as shown in Figure 4-4. This approach is far more secure than the one discussed in the previous Figure 4-3. Single database-key approachsection. Even if a thief succeeds in stealing a key, only one row will be compromised, not the entire table or the database. There are some disadvantages of this approach: the proliferation of keys makes it extremely difficult to manage them. Also, because encryption and decryption operations need to generate or retrieve a different key for each row, performance will suffer. Nevertheless, the added security provided by this approach makes it preferable in most encryption systems. 4.4.3. Using a Combined ApproachIn some cases, neither of the approaches I've described so far may be suitable. Let's examine the pros and cons of the two options.
Clearly, neither approach is perfect, and you will have to find a middle groundthat is, choose an approach somewhere between the two approaches we've discussed. Perhaps you will use a single key per column, where the same key applies to all the rows; or a key per table regardless of the number of columns; or a key per schema; and so on. The number of keys to be managed would decrease dramatically with any of these approaches, but of course the vulnerability of the data would increase. Let's take a look at a third approachI will adopt a combination of keys, as shown in Figure 4-5:
This is not the same as encrypting the encrypted value (in fact, that isn't even possible). Although I have defined one key per row, the actual key used during encryption is not the key stored for the row; it is, instead, the bitwise exclusive OR (XOR) of two valuesthe stored key and a master key. The master key can be stored in a location different from the location of the other keys, as shown in Figure 4-6. An intruder must find both keys if she is to successfully decrypt an encrypted value. Figure 4-5. The master-key approachFigure 4-6. Location of the master keyThe built-in UTL_RAW package provides the BIT_XOR function , which I can use to perform a bitwise XOR operation . Here I'll perform a bitwise XOR for two values12345678 and 87654321. /* File on web: bit_xor.sql */ 1 DECLARE 2 l_bitxor_val RAW (2000); 3 l_val_1 VARCHAR2 (2000) := '12345678'; 4 l_val_2 VARCHAR2 (2000) := '87654321'; 5 BEGIN 6 l_bitxor_val := 7 UTL_RAW.bit_xor (utl_i18n.string_to_raw (l_val_1, 'AL32UTF8'), 8 utl_i18n.string_to_raw (l_val_2, 'AL32UTF8') 9 ); 10 DBMS_OUTPUT.put_line ( 'Raw Val_1: ' 11 || RAWTOHEX (utl_i18n.string_to_raw (l_val_1, 12 'AL32UTF8' 13 ) 14 ) 15 ); 16 DBMS_OUTPUT.put_line ( 'Raw Val_2: ' 17 || RAWTOHEX (utl_i18n.string_to_raw (l_val_2, 18 'AL32UTF8' 19 ) 20 ) 21 ); 22 DBMS_OUTPUT.put_line ('After bit XOR: ' || RAWTOHEX (l_bitxor_val)); 23 END; To perform a bitwise operation, I first need to convert the values to the RAW datatype, as shown in line 8, where the call to the UTL_I18N.STRING_TO_RAW function converts the value to RAW. In line 7, I call the bitwise XOR function, and at the end, I display the two input values converted to RAW, along with the XOR'ed value. After executing the above block, I get this output: Raw Val_1: 3132333435363738 Raw Val_2: 3837363534333231 After bit XOR: 0905050101050509 Note how the bitwise XOR'ed value is very different from both of the input values. Using this technique, if I pull one value as the stored key for the row and the other as a master key , I can generate a different key that will be used in actual encryption. You will need both of the values, not just one, to arrive at the XOR'ed value. Thus, even someone who knows one of the values will not be able to decipher the XOR'ed value and thus get the actual encryption value.
I can change my original encryption/decryption program to use this master key, as shown below. I add a new variable called l_master_key in line 6, which accepts a value from the user (the substitution variable &master_key). In lines 15 through 17, I have XOR'ed the key and the master key, which was used instead of the l_key variable as the encryption key in line 22. /* File on web: enc_dec_master.sql */ 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) := 'Confidential Data'; 8 l_mod NUMBER 9 := DBMS_CRYPTO.encrypt_aes128 10 + DBMS_CRYPTO.chain_cbc 11 + DBMS_CRYPTO.pad_pkcs5; 12 l_enc RAW (2000); 13 l_enc_key RAW (2000); 14 BEGIN 15 l_enc_key := 16 UTL_RAW.bit_xor (utl_i18n.string_to_raw (l_key, 'AL32UTF8'), 17 utl_i18n.string_to_raw (l_master_key, 'AL32UTF8') 18 ); 19 l_enc := 20 DBMS_CRYPTO.encrypt (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 33 := DBMS_CRYPTO.encrypt_aes128 34 + DBMS_CRYPTO.chain_cbc 35 + DBMS_CRYPTO.pad_pkcs5; 36 l_dec RAW (2000); 37 l_enc_key RAW (2000); 38 BEGIN 39 l_enc_key := 40 UTL_RAW.bit_xor (utl_i18n.string_to_raw (l_key, 'AL32UTF8'), 41 utl_i18n.string_to_raw (l_master_key, 'AL32UTF8') 42 ); 43 l_dec := DBMS_CRYPTO.decrypt (l_in_val, l_mod, l_enc_key); 44 DBMS_OUTPUT.put_line ('Decrypted=' || utl_i18n.raw_to_char (l_dec)); 45 END; When I execute this block, this is what the output looks like. Note that first I supply the master key to encrypt the value, and then I provide the same master key while decrypting. Enter value for master_key: MasterKey0123456 old 3: l_master_key varchar2(2000) := '&master_key'; new 3: l_master_key varchar2(2000) := 'MasterKey0123456'; Encrypted=C2CABD4FD4952BC3ABB23BD50849D0C937D3EE6659D58A32AC69EFFD4E83F79D 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'; Decrypted=ConfidentialData PL/SQL procedure successfully completed. My program asked for the master key, which I supplied correctly, and the correct value came up. But what if I 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'; Encrypted=C2CABD4FD4952BC3ABB23BD50849D0C937D3EE6659D58A32AC69EFFD4E83F79D 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'; declare * 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 here: the use of a wrong master key did not expose the encrypted data. This enhanced security mechanism relies on two different keys, and both keys must be present to successfully decrypt it. If you hide the master key, it will be enough to prevent unauthorized decryption. Because the master key is stored with the client, and it is sent over the network, a potential attacker could use a tool to "sniff" the value as it passes by. To prevent this from occurring, you can use a variety of approaches:
There is no perfect key-management solution. The approach you choose will be determined by the nature of your application and your best attempts to balance security against ease of access. The three approaches described in the previous sections represent three major types of key-management techniques and are intended to give you a jump start on figuring out your own key management approach. You might very well come up with a better idea that could be more appropriate to your specific situation. For example, you might consider a hybrid approach, such as using different keys for critical tables.
|