Home
Home Page
Portfolio
Blog
Information
Features Available
Prices and Services
FAQ
Links
Contact Us
Info Request Form
Site Map
 

Welcome to my blog, I have been looking for a simple easy way to keep my scripts handy, indexed and searchable.  By storing them here, I can keep them up-to-date and share them with others as well.


Search:

Recent Entries:

:: Using DBMS_CRYPTO to encrypt data
February 01, 2012
:: Oracle virtual development environment
March 25, 2012
:: Quick Hot Backup Generator
January 29, 2012


Navigation:

blog home


archive
MARCH 2012
FEBRUARY 2012
JANUARY 2012

Links:

My favorite links

Guest Book

Tell a Friend

Login

February, 2012
Using DBMS_CRYPTO to encrypt data


In addition to controlling access to the tables with user grants, you can reduce security risks by encrypting data. Data encryption is not an infallible solution for data security but is an important tool in addressing specific security threats. While getting past the access controls is a rare occurrence, hackers have obtained large lists of credit card numbers after breaking into corporate databases. If the data was encrypted, the stolen information would be useless. Encryption of stored data is thus an important tool in limiting information loss.

Securing sensitive data from users while providing access to the rest of the data can be accomplished with the use of the basic cryptographic functions and procedures available in the DBMS_CRYPTO packages of Oracle 10g and Oracle 11g.  You can encrypt/decrypt common Oracle datatypes including RAW and LOBs and it specifically supports BLOBS and CLOBS. There is also globalization support for encrypting data across different database character sets. Prior to DBMS_CRYPTO, Oracle provided the DBMS_OBFUSCATION_KIT in Oracle 8i and Oracle 9i but the DBMS_CRYPTO implementation is easier to use and manage and has more cryptographic algorithms available. To use these correctly and securely, a level of expertise is assumed and you should carefully test this before implementing in your production environment or you will be rebuilding the data from scratch.

Please do not confuse DBMS_CRYPTO with Oracle Transparent Data Encryption in 10g, which will encrypt data "at rest" in the data files. With TDE, when the data is generated, it is provided to the DB in plain text and then Oracle automatically converts that plain text into an encrypted form for storage.  With TDE, if a user has select access to the table, they see the unencrypted values of the encrypted columns. With DBMS_CRYPTO, a user with select access will see the encrypted values. The security is gained by not allowing the user access to execute the procs that encrypt or decrypt the data. You simply allow the application layer access to execute these procs and then the application can use the unencrypted value. Note that you should be "wrapping” the proc so the user community cannot see the key used in the DBA_SOURCE views to encrypt or decrypt the data.

With TDE, the front end doesn't need to know that the data was encrypted. The whole point behind transparent encryption is to keep the sensitive data in the data files safe which is especially helpful if the backups are ever compromised. Just make sure you do not store the wallet file with the backups of the datafiles and the data will be safe even if you automate the opening of the wallet during database startup.

For Batch operations, these encryption and decryption activities do require a small amount of overhead on the DB which will incrementally manifest itself during larger batch operations and will slow them down. A bit of performance testing will help you figure out if the incremental increase in time is acceptable.

Let’s look at an example using DBMS_CRYPTO to secure sensitive data from the users or applications.  Let’s setup a table with a password column. When users select the data, they will see an encrypted value. Then we will setup a stored procedure to encrypt the data when inserting into the table. When you want to use the unencrypted value in your application, you simply use the proc to decrypt it and compare it to the password provided by the end user. Limit the access to the proc to prevent users from seeing the unencrypted values outside of the application. This way only the users with access to the application can utilize the stored proc and the application can have a built in audit trail of who is accessing the secured data.


/* Start a sqlplus session as SCOTT and create a table for the username and password columns */

CREATE TABLE user_pwd (
   username    VARCHAR2(30),
   password    VARCHAR2(200)
);
 
insert into user_pwd values ('dhansen','dhansen123');
insert into user_pwd values ('eshaffer','eshaffer456');
insert into user_pwd values ('kjames','kjames789');
commit;


This table has the user logons and passwords in plain text. You can also create a primary key to keep the usernames unique in this table and perhaps a foriegn key to the primary user table so you know who is using the username, what department they work in, and the rest of the related user attributes. 

Now let's create a stored procedure for the encryption and decryption of the password field.



/* Start a sqlplus session as sysdba and create this package */

CREATE OR REPLACE PACKAGE gen_encr
AS
   FUNCTION encrypt (p_PlainText VARCHAR2) RETURN RAW DETERMINISTIC;
   FUNCTION decrypt (p_Encrypted RAW) RETURN VARCHAR2 DETERMINISTIC;
END;
/


CREATE OR REPLACE PACKAGE BODY gen_encr
AS
   EncryptionType PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_AES256
                               + DBMS_CRYPTO.CHAIN_CBC
                               + DBMS_CRYPTO.PAD_PKCS5;

      /*  ENCRYPT_AES256 is the encryption algorithem AES 256-bit algorithm.
          CHAIN_CBC for Cipher Block Chaining, a process that hides plain text patterns
                    by XORing blocks with the previous ciphertext block, and then encrypted.
          PAD_PKCS5 Provides padding which complies with the
                    PKCS #5 Password-Based Cryptography Standard.      */

   EncryptionKey RAW (32) := UTL_RAW.cast_to_raw('ThisTextIsMyEncryptionKeyForThisPackage');
     -- The encryption key for AES256 algorithem, should be 32 bytes or more.

   FUNCTION encrypt (p_PlainText VARCHAR2) RETURN RAW DETERMINISTIC
     IS
        encrypted_raw      RAW (2048);
     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_Encrypted RAW) RETURN VARCHAR2 DETERMINISTIC
     IS
        decrypt_raw      RAW (2048);
     BEGIN
        decrypt_raw := DBMS_CRYPTO.DECRYPT
        (   src => p_Encrypted,
            typ => encryption_type,
            key => encryption_key
        );
        RETURN (UTL_RAW.CAST_TO_VARCHAR2 (decrypt_raw));
   END decrypt;
END;
/

grant execute on gen_encr to scott;
create public synonym gen_encr for sys.gen_encr;
exit;

The funciton will always return the same output for any given input arguement so we are using a deterministic clause in the function so the database won't re-execute the function once it has been executed for a specific input value. This will increase performance of the package.  The encryption or decryption of a VARCHAR2 doesn't work directly using DBMS_CRYPTO, so we have to convert it to RAW before encrypting it.

Once we have a package with the encryption and decryption functions, let's see how to use it.

/* From the sqlplus session logged on as scott, use the package to show the encrypted value */

select gen_encr.encrypt('Hello World') encrypted from dual;

ENCRYPTED
----------------------------------
89738046FA0CFDD2581198FBF98DE2C5


/* Now let's try to decrypt that value using the package we created. */

select gen_encr.decrypt('89738046FA0CFDD2581198FBF98DE2C5') decrypted from dual;

DECRYPTED
------------------
Hello World


/* Now let's use the package with a table to store the encrypted values. */

column username format a10
column password format a12
select * from user_pwd;

USERNAME   PASSWORD
---------- ------------
DHANSEN    dhansen123
ESHAFFER   eshaffer456
KJAMES     kjames789


/* The passwords are in plain text above, let's encrypt them in the table. */

update users set password = gen_encr.encrypt(password);
commit;


/* The passwords are now encrypted using the algorithm and key specified in the package gen_encr. */

column password format a32
select * from user_pwd;

USERNAME   PASSWORD
---------- --------------------------------
DHANSEN    D705C2186A64B1A6FF3B6E6220746731
ESHAFFER   98DDCC4DAB5F13140C8D657D381E05FC
KJAMES     D9A656AD83B7ADC7443D6BECD173715E


/* You should see encrypted passwords now instead of plain text. */

insert into user_pwd values ('STIGER', gen_encr.encrypt('scott456'));
commit;

select * from user_pwd;

USERNAME   PASSWORD
---------- --------------------------------
DHANSEN    D705C2186A64B1A6FF3B6E6220746731
ESHAFFER   98DDCC4DAB5F13140C8D657D381E05FC
KJAMES     D9A656AD83B7ADC7443D6BECD173715E
STIGER     41D69256E23E7A3D2AFEFF2E5C082FFD

/* Notice the newly created record for SCOTT has an encrypted password. */

grant select on user_pwd to hr;


These encrypted values can be seen by the users who have SELECT access on the user_pwd table.  The data can only be decrypted using the same key and algorithem it was encrypted with so all the password values can only be decrypted using the package gen_encr.  I have granted SELECT on table to HR. Lets see what happens when he querys data from the user_pwd table.

/* start a sqlplus session as the hr user */

column username format a10
column password format a32
select * from user_pwd;

USERNAME   PASSWORD
---------- --------------------------------
DHANSEN    D705C2186A64B1A6FF3B6E6220746731
ESHAFFER   98DDCC4DAB5F13140C8D657D381E05FC
KJAMES     D9A656AD83B7ADC7443D6BECD173715E
STIGER     41D69256E23E7A3D2AFEFF2E5C082FFD

/* Now try to decrypt the passwords */

SQL> select gen_encr.decrypt(password) from scott.user_pwd;
select gen_encr.decrypt(password) from scott.user_pwd
       *
ERROR at line 1:
ORA-00904: : invalid identifier


SQL> desc gen_encr
ERROR:
ORA-04043: object "SYS"."gen_encr " does not exist


Since the user HR has no access on the gen_encr package they cannot see the encrypted data. This will keep your encrypted data safe from intruders.

Its all about keeping your encryption algorithm and key hidden. If they are exposed, anyone can decrypt your encrypted data and see it all. In our case the key and the algorithm is stored in the gen_encr package itself.

encryption_key     RAW (32) := UTL_RAW.cast_to_raw('ThisTextIsMyEncryptionKeyForThisPackage');
encryption_type    PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_AES256
                                  DBMS_CRYPTO.CHAIN_CBC
                                  DBMS_CRYPTO.PAD_PKCS5;

Anyone having DBA privileges can see the source code of the package and leak out the encryption algorithm with the key. I have seen this happen even though it was inadvertent. We must wrap the code to hide the stuff in the code before we create or ship the package with the application. Here is how to wrap your PL/SQL code to hide it from users.

I put CREATE PACKAGE statements in a file named create_gen_encr_package.sql and then run the wrap utility to wrap the code into a new file named create_gen_encr_package.wrp.

$ wrap iname=create_gen_encr_package.sql oname=create_gen_encr_package.wrp

PL/SQL Wrapper: Release 10.2.0.1.0- Production on Sun Aug 15 06:44:32 2010

Copyright (c) 1993, 2004, Oracle.  All rights reserved.

Processing create_gen_encr_package.sql to create_gen_encr_package.wrp


Lets see the contents of this new file create_gen_encr_package.wrp.

$ more create_gen_encr_package.wrp
CREATE OR REPLACE PACKAGE gen_encr wrapped
a000000
1
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
9
a6 b2
ceYtyd1wwstfJ/3xbNlo4sobVxYwg0xHAMusaS/pOPYrUgzeeSYbTuJ789ScOKWw4LWYL191
ERLxTlyzbW7nRf8Cg4W0plfc4t7qD8d69uAPwYNtQpv3U6F9kwZQZnVeV a5FlnUcEgL7J8k
hQZIhcYLQoTZ/irf0ixRnEj 4VqG1c4=



The wrap utility actually has encrypted the PL/SQL code in the .sql file, and made it unreadable for anyone. Now use create_gen_encr_package.wrp file to create the package. Keep your .sql source file safe with you as if you want to make changes to the package later on, you will need it i.e. make changes to the .sql file, wrap it again and recreate the package.

$ sqlplus / as sysdba

Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options

SQL> @create_gen_encr_package.wrp

Package created.


Package body created.

SQL> column text format a72
SQL> select text from dba_source where name = 'gen_encr';

TEXT
----------------------------------------------------------------------
PACKAGE gen_encr wrapped
a000000
1
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
9
a6 b2
ceYtyd1wwstfJ/3xbNlo4sobVxYwg0xHAMusaS/pOPYrUgzeeSYbTuJ789ScOKWw4LWYL191
ERLxTlyzbW7nRf8Cg4W0plfc4t7qD8d69uAPwYNtQpv3U6F9kwZQZnVeV a5FlnUcEgL7J8k
hQZIhcYLQoTZ/irf0ixRnEj 4VqG1c4=

PACKAGE BODY gen_encr wrapped
a000000
1
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
b
40a 1de
e5uq2Fhk2UgpK5ktxFEVOrE3zyowg5DxLdxqfC9AWE6OGeznw1zpVqLpwIrvVN522Z83WRwv
HQw142Mg0KQxSHaso6WOT7ud5P5VvVmrcR3le4Pvj9tpyogriMDGGQGWIR5T3g4s5tMka Qj
TA4FsoMpOy3 bK/y/VW u8 zHHC1m0LOziMSmnhkB nM U1jEvvRFGGXfOJrOSmXs VcyVr8
pyIFRQgr3JDZotwcfIZAw10k4Dcm87LMeBk6c0q2wdqgqcA422/awXKrAODetRti870jSTpn
46w5MWX/ickZHdrfBh6mMttQ8x4jDaNEcZR3X7VRdReUt05S6/LToL4T/VwlYFIqbzH7rbOR
kaEYBQchlWDg5n3hRBahHVLvEeOuoQVsdBqMwA55PfP1yqqsYWSBW4Mm4OYFJP/ry1NJYbbA
wVAA/SBw965bdu5doXjpf6y7D5dHh5dtIOL9uUA=


As can be seen that after creating the package from wrapped sql script the package source code is unreadable to anyone, even the owner of the package. This way we can hide the encryption logic completely from every one.







posted by admin February 01, 2012 0:00 | permalink | comments (1) | Encryption

1 - 1 of 1











Copyright © 2007 - 2012 DataToTheMax.com, LLC. All rights reserved.