Skip to Main Content

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question.

Asked: March 15, 2011 - 9:34 am UTC

Last updated: February 22, 2018 - 1:51 am UTC

Version: 10.2

Viewed 10K+ times! This question is

You Asked


HI Tom - facing this issue of incorrect string sizing while decrypting.Usage of trim doesnt solve the issue. Below are the codes.

1.CREATE
OR
REPLACE FUNCTION CRYPT( P_STR IN VARCHAR2 )
RETURN VARCHAR2
AS
L_DATA VARCHAR2(255);
BEGIN
L_DATA := RPAD( P_STR, (TRUNC(LENGTH(P_STR)/8)+1)*8, CHR(0) );
DBMS_OBFUSCATION_TOOLKIT.DESENCRYPT
(INPUT_STRING => L_DATA
,KEY_STRING => 'MAGICKEY'
,ENCRYPTED_STRING=> L_DATA
);
RETURN UTL_RAW.CAST_TO_RAW( L_DATA );
END;
/

2.CREATE
OR
REPLACE FUNCTION DECRYPT( P_STR IN RAW )
RETURN VARCHAR2
AS
L_DATA VARCHAR2(255);
BEGIN
L_DATA := utl_raw.cast_to_varchar2( hextoraw(P_STR) );

DBMS_OBFUSCATION_TOOLKIT.DESDecrypt
(INPUT_STRING => L_DATA
,KEY_STRING => 'MAGICKEY'
,DECRYPTED_STRING=> L_DATA
);
RETURN ( TRIM(L_DATA) );
END;
/

3.20:01:31 SQL> select crypt( '012345678' ),DECRYPT('5D4552B02E93B2AA40885DE131D180B4'),length(crypt(
'012345678' )),length(DECRYPT('5D4552B02E93B2AA40885DE131D180B4')) from dual;

CRYPT('012345678')
--------------------------------------------------------------------------------
DECRYPT('5D4552B02E93B2AA40885
--------------------------------------------------------------------------------
LENGTH(CRYPT('012345678')) LENGTH(DECRYPT('5D4552B02E93B2
-------------------------- ------------------------------
5D4552B02E93B2AA40885DE131D180B4
012345678
32 16

After decrypting the string length should be length ('012345678') and not 16 as shown. Please suggest.

and Tom said...

do NOT use dbms_obfuscation_toolkit - it is obsolete and frankly - broken.

The result of encrypting something is a binary, raw piece of data. It is not suitable for storing in a varchar2 - this is something learned over and over again the hard way.

If the client character set is NOT identical the database character set - then character set conversion takes place - which will scramble up your encrypted data - destroying it.

You MUST use a raw type.

This is an excerpt from my last book - Expert Oracle Database Architecture volume II

<quote>
Implementing Manual Application Encryption

In this and the next two major sections we’ll look at the three approaches a developer/DBA can use to encrypt data in the database. We’ve had an overview of them already; now it is time to look at each in more depth. First up is Manual Application Encryption.

Manual Application Encryption is achieved programmatically using one of two builtin packages:

o DBMS_OBFUSCATION_TOOLKIT: A package supplied with the database since Oracle 8i. This package employs the Data Encryption Standard (DES) and Triple DES (3DES) encryption algorithms only. It is also capable of generating MD5 checksums of data. It can only work with RAW and VARCHAR datatypes. It should not be used for two reasons: it is deprecated as of Oracle 10g and above, replaced by the next package in this list and the name of it is really hard to type and say out loud.

o DBMS_CRYPTO: In addition to being much easier to type and say – this is the currently supported encryption API. It supports a broader range of encryption algorithms including DES, 3DES, Rivest Cipher 4 (RC4) and Advanced Encryption Standard (AES). It is also capable of generating a variety of hashes and message authentication codes (MAC) such as MD5, MD4, SHA-1. It is capable of working with RAW, CLOB and BLOB datatypes.

I will not be discussing the DBMS_OBFUSCATION_TOOLKIT package directly, but everything I say about the DBMS_CRYPTO package will apply to it as well.

Reasons to Avoid The Manual Approach

I firmly believe that if you have the documented need for encrypting data at rest – your best approach is to not use the manual approach. If you do manual application encryption, you are responsible for key management and as we discussed earlier in this chapter in the section on “The Oracle Wallet” we know how code intensive that would be. Implementing a secure key store is a non-trivial exercise and in order to be somewhat sure it is impervious to attack, you would need to expose it to a level of testing that is typically not feasible in a single organization. On the other hand, if you use off the shelf implementations (such as the Oracle wallet) you have knowledge that it is extensively tested and probed on a daily basis.

In addition to the key management issue (which is a large one – to me more than enough to not want to consider it), there is the fact that you have to code the encrypt/decrypt routines and make sure they are hooked into the application at the correct places. Whenever data comes into the database – you are responsible for encrypting the data and whenever it leaves, you are responsible for decrypting it. That comes at the expense of yet more code to be developed as well as a definite performance impact, which we’ll measure shortly.

A third reason to give serious thought before employing manual application encryption is that the application has to be involved in the process – every application that touches this data will have to be involved. That is because the column that will be encrypted must (I stress the word must here) use the RAW datatype as its underlying datatype. If you are to encrypt a LAST_NAME column that was originally defined as a VARCHAR2(70), you will be redefining that column to be a RAW(80). You must use a RAW datatype because the result of encrypting data is a binary set of bytes – they are not characters. You cannot store them in a character datatype such as VARCHAR2. I’ll refer you to Chapter 12 “Datatypes” and the discussion on NLS character set conversion for the reason why this is so. The VARCHAR2 type is subject to character set conversion – and the bytes that one client sees can and will be different from the bytes another client sees in a VARCHAR2 string. When dealing with true character strings – this is a good thing, when dealing with encrypted data – it is definitely a bad thing, it is called “corrupting the data”. Character set conversion would tend to change the encrypted data – making it so you cannot decrypt it anymore (that is, you just lost it forever). I’ve seen that happen more than once in real life – the developers used a VARCHAR2 to store encrypted data – and it was not detected for a while (that the conversion had taken place) effectively destroying that bit of data. If it had been detected early, near the point of the corruption being introduced – we could have resurrected the data from backups (before the implicit conversion corrupted it) but it would have been a non-trivial task.

Also – note that I said that a VARCHAR2(70) would require a RAW(80). This is because encrypted data is stored in multiples of 16 bytes. It takes five 16 byte pieces of raw data to store 70 single byte characters (or 71, 72 and so on). So unless your existing data attribute byte length is divisible by 16 – you’ll be computing a new field length. Again, a mistake I’ve seen time and time again is for a developer to just try to store the encrypted data in the existing VARCHAR2(70) field – it won’t work because of the implicit character set conversion that will corrupt the data some day and it won’t work because it simply won’t fit in that field. Sure, some of the data will – any of the data that was 64 bytes or less before encrypting would fit – but a value that was 65 bytes or more would need 80 bytes after encrypting. This gets even worse when you start considering multi-byte data!!


Performance Implications of The Manual Approach


The last reason to avoid the manual approach is one of performance. There is a measurable overhead in application-implemented encryption. Any layer of code we as developers add between the client and the database will add some level of overhead – and encryption can be a very expensive one to implement. So, let’s create a package to easily encrypt/decrypt with and compare the performance of a VARCHAR2(30) string stored non-encrypted and again encrypted. We’ll just compare single row INSERT performance, bulk INSERT performance and data retrieval (SELECT) performance. To begin with, we’ll need a package to perform the encryption operations for us, a sample package specification that would just contain two entry points – one to encrypt and the other to decrypt:
ops$tkyte%ORA11GR2> create or replace package encryption_wrapper
  2  as
  3      function encrypt( p_string in varchar2,
  4                        p_key    in varchar2 )
  5      return raw;
  6
  7      function decrypt( p_raw in raw,
  8                        p_key in varchar2 )
  9      return varchar2;
 10  end;
 11  /
Package created.

Now for our package body, an implementation might start off like this:

ops$tkyte%ORA11GR2> create or replace package body encryption_wrapper
  2  as
  3     g_encrypt_typ     constant PLS_INTEGER default
  4                       DBMS_CRYPTO.ENCRYPT_AES256
  5                       + DBMS_CRYPTO.CHAIN_CBC
  6                       + DBMS_CRYPTO.PAD_PKCS5;
  7
  8  function padkey( p_key in varchar2 ) return raw
  9  is
 10  begin
 11      return utl_raw.cast_to_raw(rpad(p_key,32));
 12  end;


Note: You may have to have EXECUTE on DBMS_CRYPTO granted to you before using it.

The global variable G_ENCRYPT_TYP simply specifies the type of encryption we want – this would be implementation dependent (that is, something you would figure out). Here I’m going with a standard AES with a 256 bit (32 byte) encryption key. I’ve added a convenience function PADKEY to convert a character string key into a RAW and ensure it is 32 bytes long.

Next is our implementation of the ENCRYPT function. It will begin by converting our string into a RAW type using a ‘safe’ character set. Then it will invoke DBMS_CRYPTO to actually encrypt the string (which is now a RAW) and return the value:
 14  function encrypt( p_string in varchar2,
 15                    p_key    in varchar2 )
 16  return raw
 17  is
 18  begin
 19     return DBMS_CRYPTO.ENCRYPT
 20            ( src => UTL_I18N.STRING_TO_RAW (p_string,  'AL32UTF8'),
 21              typ => g_encrypt_typ,
 22              key => padkey( p_key ) );
 23  end;


Lastly, we implement the DECRYPT routine. This simply decrypts our RAW encrypted data using the same key and then returns the VARCHAR2 representation of that output:

 24
 25  function decrypt( p_raw in raw,
 26                    p_key in varchar2 )
 27  return varchar2
 28  is
 29  begin
 30      return utl_i18n.raw_to_char(
 31                dbms_crypto.decrypt
 32                ( src => p_raw,
 33                  typ => g_encrypt_typ,
 34                  key => padkey(p_key) ),
 35                'AL32UTF8' );
 36  end;
 37
 38  end;
 39  /
Package body created.


Now we’ll create a table to test with – a column LAST_NAME to hold the data when it is not encrypted and a column ENCRYPTED_NAME – implemented as a RAW with 2*16 bytes of storage, therefore capable of holding at least 30 bytes of character data. Also, we generate a set of data we can use to test with into a simple table – this is so when we time things later, we’ll be timing just the operation we are performing, not the query against ALL_OBJECTS:
ops$tkyte%ORA11GR2> create table stage 
  2 as 
  3 select object_name from all_objects;
Table created.

ops$tkyte%ORA11GR2> create table t
  2  ( last_name      varchar2(30),
  3    encrypted_name raw(32)
  4  )
  5  /
Table created.

And now we can start inserting – first we’ll do a row by row insert into this table, once with non-encrypted data and again with encrypted data. The non-encrypted insert would look like this:
ops$tkyte%ORA11GR2> declare
  2      l_start number := dbms_utility.get_cpu_time;
  3  begin
  4      for x in (select object_name from stage)
  5      loop
  6          insert into t (last_name) values ( x.object_name );
  7      end loop;
  8      dbms_output.put_line( (dbms_utility.get_cpu_time-l_start) || ' hsecs' );
  9  end;
 10  /
431 hsecs
PL/SQL procedure successfully completed.


As you can see – our code consumed 4.31 CPU seconds of computer time to generate and insert the data. If we perform the same operation using the encryption package:
ops$tkyte%ORA11GR2> truncate table t;
Table truncated.

ops$tkyte%ORA11GR2> declare
  2      l_start number := dbms_utility.get_cpu_time;
  3  begin
  4      for x in (select object_name from stage)
  5      loop
  6          insert into t (encrypted_name)
  7          values ( encryption_wrapper.encrypt
  8                   (x.object_name,
  9                    'Secret Key Secret Key Secret Key'));
 10      end loop;
 11      dbms_output.put_line( (dbms_utility.get_cpu_time-l_start) || ' hsecs' );
 12  end;
 13  /
2502 hsecs
PL/SQL procedure successfully completed.


It takes 25.02 CPU seconds to generate and insert the data. Thus, it takes almost six times more CPU to perform the encryption as opposed to leaving the data unencrypted. Even if we “bulk up” the operation, using an INSERT AS SELECT statement, we’ll see a large disparity:
ops$tkyte%ORA11GR2> truncate table t;
Table truncated.

ops$tkyte%ORA11GR2> declare
  2      l_start number := dbms_utility.get_cpu_time;
  3  begin
  4      insert into t (last_name) select object_name from stage;
  5      dbms_output.put_line( (dbms_utility.get_cpu_time-l_start) || ' hsecs' );
  6  end;
  7  /
8 hsecs
PL/SQL procedure successfully completed.

ops$tkyte%ORA11GR2> truncate table t;
Table truncated.

ops$tkyte%ORA11GR2> declare
  2      l_start number := dbms_utility.get_cpu_time;
  3  begin
  4          insert into t (encrypted_name)
  5          select encryption_wrapper.encrypt
  6                   (object_name,
  7                    'Secret Key Secret Key Secret Key')
  8            from stage;
  9      dbms_output.put_line( (dbms_utility.get_cpu_time-l_start) || ' hsecs' );
 10  end;
 11  /
374 hsecs
PL/SQL procedure successfully completed.


374 hseconds versus 8 seconds is a more striking disparity – an almost 47 times increase in CPU utilization because of encryption when we performed the more efficient bulk operation. Clearly, this increased demand on CPU will have an impact on our modifications to the column. INSERTS, UPDATES, and MERGES will surely be affected, (but probably notDELETEs.

What about data retrieval? To test the effects on data retrieval, we’ll populate both columns at the same time:
ops$tkyte%ORA11GR2> truncate table t;
Table truncated.

ops$tkyte%ORA11GR2> insert into t (last_name, encrypted_name)
  2  select object_name,
  3         encryption_wrapper.encrypt
  4         (object_name,
  5          'Secret Key Secret Key Secret Key')
  6    from stage;
64588 rows created.

ops$tkyte%ORA11GR2> commit;
Commit complete.

And then retrieve them:

ops$tkyte%ORA11GR2> declare
  2      l_start number := dbms_utility.get_cpu_time;
  3  begin
  4          for x in (select last_name from t)
  5          loop
  6                  null;
  7          end loop;
  8      dbms_output.put_line( (dbms_utility.get_cpu_time-l_start) || ' hsecs' );
  9  end;
 10  /
7 hsecs
PL/SQL procedure successfully completed.

ops$tkyte%ORA11GR2> declare
  2      l_start number := dbms_utility.get_cpu_time;
  3  begin
  4          for x in ( select encryption_wrapper.decrypt
  5                   (encrypted_name,
  6                    'Secret Key Secret Key Secret Key')
  7                   from t )
  8          loop
  9                  null;
 10          end loop;
 11      dbms_output.put_line( (dbms_utility.get_cpu_time-l_start) || ' hsecs' );
 12  end;
 13  /
378 hsecs
PL/SQL procedure successfully completed.


As you can see – the decryption overhead added a sizable amount of increased CPU utilization, around 50 times as much CPU was needed in this case (378 seconds versus 7).

When To Use The Manual Approach

So, when should you consider the manual approach of application encryption? If you ask me – the answer is pretty much “almost never”. The only time it would be necessary is if you are using Oracle’s Standard Edition (SE) or lower – which does not have the ability to have the Advanced Security Option (ASO). Many times people will utilize SE as a cost savings approach – but if you find that you have to implement the functional equivalent of ASO yourself – doing the key management, implementing all of the code – and performing the necessary application modifications (this approach is definitely not transparent to the application), you might find the cost of Enterprise Edition justified. In house developed software is not “free” after all.


</quote>

Rating

  (6 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Performance

A reader, March 15, 2011 - 11:30 pm UTC

Hi Tom - Thanks for the insight. Few questions/remarks -
1.What is better (according to you) - TDE or dbms_crypto from the performance standpoint.
2.You have described the manual way of encryption, what is the automatic/system driven way of executing the same. Is it where the encryption key is system generated and reused.

Looking forward to the answers. Thanks
Tom Kyte
March 16, 2011 - 8:29 am UTC

1) definitely transparent data encryption - TDE, simple, transparent, *fast* (manual encryption has a massive performance impact), secure (key management).

I was sort of hoping that was clear from above...


2) I cannot post the entire chapter here - but in the book, I go over it (TDE) as well.

However, it is documented:

http://docs.oracle.com/docs/cd/E11882_01/network.112/e10746/asotrans.htm#ASOAG600

Indexes on the encrypted columns

A reader, March 16, 2011 - 10:10 am UTC

Thanks for the response.
Do you see any problem with indexes on encrypted columns using TDE.
Tom Kyte
March 16, 2011 - 10:43 am UTC

if you are using tablespace encryption - not at all.

if you are using column encryption - there are issues such as you cannot range scan on them, you cannot create function based indexes on them, you cannot do primary/foreign key relations with them.


but, using tablespace encryption - no restrictions at all.

A reader, March 16, 2011 - 11:29 am UTC

Simply superb! Thanks Tom.

Recovering encrypted tablespace.

A reader, March 16, 2011 - 12:16 pm UTC

Tom :

I am restoring and recovering the database to another server .
In this database , one of the tablespace is encrypted .

Restore went fine . But the recovery is complaining that wallet is not open .
I can't open the wallet , as the database is not open .
I can't open the database , as it requires wallet to be open for recovery .

Note : I did copy the wallet file into fileshare .

In short , How I can recover a database to another server that has encypted tablespace ?

Thanks a lot


RMAN-00571: ===========================================================
RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============
RMAN-00571: ===========================================================
RMAN-03002: failure of recover command at 03/16/2011 10:14:16
ORA-00283: recovery session canceled due to errors
RMAN-11003: failure during parse/execution of SQL statement: alter database recover logfile 'C:\FRB\OBPD\ARCHIVELOG\2011_03_14\O1_MF_1_5824_6QWOXK7K_.ARC'
ORA-00283: recovery session canceled due to errors
ORA-28365: wallet is not open

Tom Kyte
March 16, 2011 - 12:41 pm UTC

sys%ORA11GR2> shutdown immediate;
Database closed.
Database dismounted.
ORACLE instance shut down.
sys%ORA11GR2> startup nomount;
ORACLE instance started.

Total System Global Area  535662592 bytes
Fixed Size                  1345376 bytes
Variable Size             322963616 bytes
Database Buffers          205520896 bytes
Redo Buffers                5832704 bytes
sys%ORA11GR2> alter system set encryption wallet open identified by foobar;

System altered.



database need only be started - not mounted, not open - to open the wallet.

TDE - 11.2

N Khan, June 14, 2011 - 11:23 am UTC

Hi Tom,
did'nt realize that database need not be "Mounted" or "Opened" to open the wallet! -
always learn something new/different from your posts -- Thanks a ton for that!

We are using TDE; created a trigger "after startup" that opens the wallet. We are having a weird issue - sometimes the wallet opens (when manually shutting down and starting up a db) and sometimes it does not (especially if the server is rebooted). I have 12 instances running on a server that was re-booted, 6 instances opened the wallets and the rest of them could not open the wallets and remained in "mount" stage.

The wallets are stored under
$ORACLE_BASE/admin/<sid>/wallet directory.


I'm including the alert log info for a successful and failed startup instance:

---------------------------------------------------------------------------
alert log info for instance whose Wallet did not open at startup
---------------------------------------------------------------------------
Starting up:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options.
Using parameter settings in server-side spfile /opt/oracle/product/11.2.0/dbhome_1/dbs/spfilewrngl.ora
System parameters with non-default values:
processes = 150
memory_target = 1600M
control_files = "/ora01/oradata/wrngl/control01.ctl"
control_files = "/ora02/oradata/wrngl/control02.ctl"
db_block_size = 8192
compatible = "11.2.0.0.0"
log_archive_dest_1 = "LOCATION=/OraArchive/oradata/wrngl"
log_archive_format = "wrngl%t_%s_%r.dbf"
undo_tablespace = "UNDOTBS1"
remote_login_passwordfile= "EXCLUSIVE"
db_domain = "XXXXX.edu"
dispatchers = "(PROTOCOL=TCP) (SERVICE=wrnglXDB)"
audit_file_dest = "/opt/oracle/admin/wrngl/adump"
audit_trail = "DB"
db_name = "wrngl"
open_cursors = 300
diagnostic_dest = "/opt/oracle"
Tue Jun 14 07:13:11 2011
PMON started with pid=2, OS id=5223
Tue Jun 14 07:13:11 2011
PSP0 started with pid=3, OS id=5226
Tue Jun 14 07:13:12 2011
VKTM started with pid=4, OS id=5248 at elevated priority
Tue Jun 14 07:13:12 2011
GEN0 started with pid=5, OS id=5252
VKTM running at (1)millisec precision with DBRM quantum (100)ms
Tue Jun 14 07:13:12 2011
DIAG started with pid=6, OS id=5254
Tue Jun 14 07:13:12 2011
DBRM started with pid=7, OS id=5256
Tue Jun 14 07:13:12 2011
DIA0 started with pid=8, OS id=5258
Tue Jun 14 07:13:12 2011
MMAN started with pid=9, OS id=5260
Tue Jun 14 07:13:12 2011
DBW0 started with pid=10, OS id=5262
Tue Jun 14 07:13:12 2011
LGWR started with pid=11, OS id=5264
Tue Jun 14 07:13:12 2011
CKPT started with pid=12, OS id=5266
Tue Jun 14 07:13:12 2011
SMON started with pid=13, OS id=5268
Tue Jun 14 07:13:12 2011
RECO started with pid=14, OS id=5270
Tue Jun 14 07:13:12 2011
MMON started with pid=15, OS id=5272
starting up 1 dispatcher(s) for network address '(ADDRESS=(PARTIAL=YES)(PROTOCOL=TCP))'...
Tue Jun 14 07:13:12 2011
MMNL started with pid=16, OS id=5276
starting up 1 shared server(s) ...
ORACLE_BASE from environment = /opt/oracle
Tue Jun 14 07:13:13 2011
ALTER DATABASE MOUNT
Successful mount of redo thread 1, with mount id 2098368521
Database mounted in Exclusive Mode
Lost write protection disabled
Completed: ALTER DATABASE MOUNT
Tue Jun 14 07:13:18 2011
ALTER DATABASE OPEN
Beginning crash recovery of 1 threads
parallel recovery started with 3 processes
Started redo scan
Completed redo scan
read 95 KB redo, 25 data blocks need recovery
Started redo application at
Thread 1: logseq 352, block 75000
Recovery of Online Redo Log: Thread 1 Group 1 Seq 352 Reading mem 0
Mem# 0: /ora01/oradata/wrngl/wrngl_redo01a.log
Mem# 1: /ora02/oradata/wrngl/wrngl_redo01b.log
Completed redo application of 0.05MB
Completed crash recovery at
Thread 1: logseq 352, block 75191, scn 4792924
25 data blocks read, 25 data blocks written, 95 redo k-bytes read
LGWR: STARTING ARCH PROCESSES
Tue Jun 14 07:13:18 2011
ARC0 started with pid=23, OS id=5535
ARC0: Archival started
LGWR: STARTING ARCH PROCESSES COMPLETE
ARC0: STARTING ARCH PROCESSES
Tue Jun 14 07:13:19 2011
ARC1 started with pid=24, OS id=5601
Tue Jun 14 07:13:19 2011
ARC2 started with pid=25, OS id=5603
ARC1: Archival started
ARC2: Archival started
Tue Jun 14 07:13:19 2011
ARC3 started with pid=26, OS id=5605
ARC1: Becoming the 'no FAL' ARCH
ARC1: Becoming the 'no SRL' ARCH
ARC2: Becoming the heartbeat ARCH
Thread 1 advanced to log sequence 353 (thread open)
Thread 1 opened at log sequence 353
Current log# 2 seq# 353 mem# 0: /ora01/oradata/wrngl/wrngl_redo02a.log
Current log# 2 seq# 353 mem# 1: /ora02/oradata/wrngl/wrngl_redo02b.log
Successful open of redo thread 1
MTTR advisory is disabled because FAST_START_MTTR_TARGET is not set
SMON: enabling cache recovery
Archived Log entry 334 added for thread 1 sequence 352 ID 0x7cbdbb83 dest 1:
ARC3: Archival started
ARC0: STARTING ARCH PROCESSES COMPLETE
[5519] Successfully onlined Undo Tablespace 2.
Undo initialization finished serial:0 start:4294117690 end:4294118240 diff:550 (5 seconds)
Verifying file header compatibility for 11g tablespace encryption..
Verifying 11g file header compatibility for tablespace encryption completed
SMON: enabling tx recovery
Database Characterset is WE8MSWIN1252
No Resource Manager plan active
replication_dependency_tracking turned off (no async multimaster replication found)
Starting background process QMNC
Tue Jun 14 07:13:23 2011
QMNC started with pid=27, OS id=5661
ALTER SYSTEM SET WALLET OPEN IDENTIFIED BY *
Completed Successfully
ALTER SYSTEM SET WALLET OPEN IDENTIFIED BY *
Completed: ALTER DATABASE OPEN
Tue Jun 14 07:13:25 2011
Starting background process CJQ0
Tue Jun 14 07:13:25 2011
CJQ0 started with pid=19, OS id=5710
Tue Jun 14 07:18:25 2011
Starting background process SMCO
Tue Jun 14 07:18:25 2011
SMCO started with pid=20, OS id=10681
Tue Jun 14 07:35:40 2011
Time drift detected. Please check VKTM trace file for more details.

---------------------------------------------------------------------------

alert log info for instance whose Wallet did not open at startup
---------------------------------------------------------------------------

Starting up:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options.
Using parameter settings in server-side spfile /opt/oracle/product/11.2.0/dbhome_1/dbs/spfileabcapps.ora
System parameters with non-default values:
processes = 150
memory_target = 1536M
control_files = "/ora01/oradata/abcapps/control01.ctl"
control_files = "/ora02/oradata/abcapps/control02.ctl"
db_block_size = 8192
compatible = "11.2.0.0.0"
log_archive_dest_1 = "LOCATION=/OraArchive/oradata/abcapps"
log_archive_format = "abcapps%t_%s_%r.dbf"
undo_tablespace = "UNDOTBS1"
remote_login_passwordfile= "EXCLUSIVE"
db_domain = "XXXXX.edu"
dispatchers = "(PROTOCOL=TCP) (SERVICE=abcappsXDB)"
audit_file_dest = "/opt/oracle/admin/abcapps/adump"
audit_trail = "DB"
db_name = "abcapps"
open_cursors = 300
diagnostic_dest = "/opt/oracle"
Tue Jun 14 07:14:56 2011
PMON started with pid=2, OS id=8051
Tue Jun 14 07:14:56 2011
PSP0 started with pid=3, OS id=8053
Tue Jun 14 07:14:57 2011
VKTM started with pid=4, OS id=8068 at elevated priority
VKTM running at (1)millisec precision with DBRM quantum (100)ms
Tue Jun 14 07:14:57 2011
GEN0 started with pid=5, OS id=8072
Tue Jun 14 07:14:57 2011
DIAG started with pid=6, OS id=8074
Tue Jun 14 07:14:57 2011
DBRM started with pid=7, OS id=8076
Tue Jun 14 07:14:57 2011
DIA0 started with pid=8, OS id=8078
Tue Jun 14 07:14:57 2011
MMAN started with pid=9, OS id=8081
Tue Jun 14 07:14:57 2011
DBW0 started with pid=10, OS id=8083
Tue Jun 14 07:14:57 2011
LGWR started with pid=11, OS id=8085
Tue Jun 14 07:14:57 2011
CKPT started with pid=12, OS id=8087
Tue Jun 14 07:14:57 2011
SMON started with pid=13, OS id=8089
Tue Jun 14 07:14:57 2011
RECO started with pid=14, OS id=8092
Tue Jun 14 07:14:57 2011
MMON started with pid=15, OS id=8094
starting up 1 dispatcher(s) for network address '(ADDRESS=(PARTIAL=YES)(PROTOCOL=TCP))'...
Tue Jun 14 07:14:57 2011
MMNL started with pid=16, OS id=8096
starting up 1 shared server(s) ...
ORACLE_BASE from environment = /opt/oracle
Tue Jun 14 07:14:57 2011
ALTER DATABASE MOUNT
Successful mount of redo thread 1, with mount id 1435713585
Database mounted in Exclusive Mode
Lost write protection disabled
Completed: ALTER DATABASE MOUNT
Tue Jun 14 07:15:01 2011
ALTER DATABASE OPEN
Beginning crash recovery of 1 threads
parallel recovery started with 3 processes
Started redo scan
Completed redo scan
read 39 KB redo, 18 data blocks need recovery
Tue Jun 14 07:15:02 2011
kcbztek_get_tbskey: decrypting encrypted key for tablespace 0 without opening the wallet
kcbztek_get_tbskey: decrypting encrypted key for tablespace 0 without opening the wallet
Slave exiting with ORA-28365 exception
Errors in file /opt/oracle/diag/rdbms/abcapps/abcapps/trace/abcapps_p002_8226.trc:
ORA-28365: wallet is not open
Aborting crash recovery due to slave death, attempting serial crash recovery
Beginning crash recovery of 1 threads
Started redo scan
Completed redo scan
read 39 KB redo, 18 data blocks need recovery
Started redo application at
Thread 1: logseq 501, block 43344
Recovery of Online Redo Log: Thread 1 Group 3 Seq 501 Reading mem 0
Mem# 0: /ora01/oradata/abcapps/abcapps_redo03.log
kcbztek_get_tbskey: decrypting encrypted key for tablespace 0 without opening the wallet
kcbztek_get_tbskey: decrypting encrypted key for tablespace 0 without opening the wallet
Aborting crash recovery due to error 28365
Errors in file /opt/oracle/diag/rdbms/abcapps/abcapps/trace/abcapps_ora_8212.trc:
ORA-28365: wallet is not open
Errors in file /opt/oracle/diag/rdbms/abcapps/abcapps/trace/abcapps_ora_8212.trc:
ORA-28365: wallet is not open
ORA-28365 signalled during: ALTER DATABASE OPEN...
Tue Jun 14 07:35:40 2011
Time drift detected. Please check VKTM trace file for more details.

-----------------------------------------------
manually opened the wallet and the database
-----------------------------------------------
Tue Jun 14 08:11:40 2011
ALTER SYSTEM SET WALLET OPEN IDENTIFIED BY *
Completed Successfully
ALTER SYSTEM SET WALLET OPEN IDENTIFIED BY *
alter database open
Beginning crash recovery of 1 threads
parallel recovery started with 3 processes
Started redo scan
Completed redo scan
read 39 KB redo, 18 data blocks need recovery
Started redo application at
Thread 1: logseq 501, block 43344
Recovery of Online Redo Log: Thread 1 Group 3 Seq 501 Reading mem 0
Mem# 0: /ora01/oradata/abcapps/abcapps_redo03.log
Completed redo application of 0.01MB
Completed crash recovery at
Thread 1: logseq 501, block 43422, scn 9205457053
18 data blocks read, 18 data blocks written, 39 redo k-bytes read
Tue Jun 14 08:11:46 2011
LGWR: STARTING ARCH PROCESSES
Tue Jun 14 08:11:46 2011
ARC0 started with pid=23, OS id=24644
ARC0: Archival started
LGWR: STARTING ARCH PROCESSES COMPLETE
ARC0: STARTING ARCH PROCESSES
Tue Jun 14 08:11:47 2011
ARC1 started with pid=24, OS id=24650
Tue Jun 14 08:11:47 2011
ARC2 started with pid=26, OS id=24652
ARC1: Archival started
ARC2: Archival started
Tue Jun 14 08:11:47 2011
ARC3 started with pid=27, OS id=24654
ARC1: Becoming the 'no FAL' ARCH
ARC1: Becoming the 'no SRL' ARCH
ARC2: Becoming the heartbeat ARCH
Thread 1 advanced to log sequence 502 (thread open)
Thread 1 opened at log sequence 502
Current log# 1 seq# 502 mem# 0: /ora01/oradata/abcapps/abcapps_redo01.log
Successful open of redo thread 1
MTTR advisory is disabled because FAST_START_MTTR_TARGET is not set
Tue Jun 14 08:11:47 2011
SMON: enabling cache recovery
Archived Log entry 452 added for thread 1 sequence 501 ID 0x55540ba1 dest 1:
ARC3: Archival started
ARC0: STARTING ARCH PROCESSES COMPLETE
[23788] Successfully onlined Undo Tablespace 2.
Undo initialization finished serial:0 start:2452324 end:2452664 diff:340 (3 seconds)
Verifying file header compatibility for 11g tablespace encryption..
Verifying 11g file header compatibility for tablespace encryption completed
SMON: enabling tx recovery
Database Characterset is WE8MSWIN1252
No Resource Manager plan active
replication_dependency_tracking turned off (no async multimaster replication found)
Starting background process QMNC
Tue Jun 14 08:11:50 2011
QMNC started with pid=25, OS id=24666
Tue Jun 14 08:11:50 2011
ALTER SYSTEM SET WALLET OPEN IDENTIFIED BY *
Error signalled during
ALTER SYSTEM SET WALLET OPEN IDENTIFIED BY *
Completed: alter database open
Tue Jun 14 08:11:52 2011
Starting background process CJQ0
Tue Jun 14 08:11:52 2011
CJQ0 started with pid=32, OS id=24680
Tue Jun 14 08:20:00 2011
Starting background process SMCO
Tue Jun 14 08:20:00 2011
SMCO started with pid=20, OS id=29658

--------------------------------------
Procedure that opens wallet
--------------------------------------
create or replace procedure open_wallet
as
wallet_open exception;
pragma exception_init(wallet_open, -28354);
v_stmt varchar2(100);
v_password varchar2(20);
begin
v_password := 'wallet_password';
v_stmt := 'ALTER SYSTEM SET WALLET OPEN IDENTIFIED BY "'||v_password||'"';
execute immediate v_stmt;
exception
when wallet_open then
null;
end;

-----------------------------------------------
Trigger that invokes open-wallet after startup
------------------------------------------------
create or replace trigger open_tde_wallet
after startup on database
begin
sys.open_wallet;
end;

-----------------------------------------------
Any insight on this is deeply appreciated.

Tom Kyte
June 17, 2011 - 11:48 am UTC

We are using TDE; created a trigger "after startup" that opens the wallet.


why bother encrypting the data? You've sort of defeated the entire purpose. If I steal your database, the fact you encrypted it won't mean squat.


If you want to auto-open the wallet, do this:

http://docs.oracle.com/docs/cd/E11882_01/network.112/e10746/asotrans.htm#ASOAG9543

Deterministic

Moris, February 21, 2018 - 8:09 am UTC

Would it make sense to add Deterministic to the two functions encrypt and decrypt of the above Tom's encryption_wrapper package?
For a massive data encryption.
Pls elaborate.

And secondly what about how is usfull here Result cache??

Tkx

Connor McDonald
February 22, 2018 - 1:51 am UTC

Would it make sense to add Deterministic to the two functions
And secondly what about how is usfull here Result cache??

You could...but the usefulness of doing so is perhaps dependent on the data. Typically, the things we encrypt are widely varied (credit cards, surnames, addresses etc) so the "hit rate" on repeated accesses might be low.

But it depends on the data obviously.

More to Explore

CLOB/BLOB/etc

Complete documentation on Securefiles and Large Objects here