What is the DBMS_Crypto.encrypt() equivalent of DBMS_Obfuscation_Toolkit.DES3Encrypt()? - oracle

I am editing some Oracle code that includes DBMS_Obfuscation_Toolkit references. I read that the DBMS_Obfuscation_Toolkit package is de-supported as of Oracle 10.2, and that I should upgrade my code to instead be use DMBS_Crypto.
I have this code...
dbms_obfuscation_toolkit.DES3Encrypt(
input => UTL_I18N.STRING_TO_RAW(v_input, 'AL32UTF8'),
key => UTL_I18N.STRING_TO_RAW(v_key, 'AL32UTF8'),
encrypted_data => v_temp_raw
);
--039053190040155118183231113102022222017082162099111241054160152245207112101203096142122226097245
v_temp := UTL_RAW.CAST_TO_VARCHAR2(v_temp_raw);
...which expects length v_input to be evenly-divisible by 8, and yields a 96 character result ("039053...").
The DBMS_Obfuscation_Toolkit documentation says that "Oracle's implementation of 3DES" defaults to the 2-key implementation, "in outer cipher-block-chaining (CBC) mode". But when I attempt to write a DBMS_Crypto.encrypt() equivalent...
--050127133161074179059208056044163133102098061207107114089045105193049199029095204025170130139068
v_temp := UTL_RAW.CAST_TO_VARCHAR2(
DBMS_Crypto.encrypt(
src => UTL_I18N.STRING_TO_RAW(v_input, 'AL32UTF8'), -- Cleartext
typ => DBMS_Crypto.ENCRYPT_3DES_2key + DBMS_Crypto.CHAIN_CBC + DBMS_Crypto.PAD_NONE,
key => UTL_I18N.STRING_TO_RAW(v_key, 'AL32UTF8') -- Key
)
);
...I get back a different 96 character result ("050127...").
For the purposes of above, v_input ('Trees sway into 25MPH winds! ') and v_key ('STACKOVERFLOW123456PSRV235KGNKNVEFHEF3404757543MNVOVCNALADNC6579') are the same.
To get the same result with DBMS_Crypto.encrypt(), what parameters should I be passing? What is the DBMS_Crypto.encrypt() equivalent of DBMS_Obfuscation_Toolkit.DES3Encrypt()?

You need to supply a matching initialization vector (IV). If there was no original IV, then use DBMS_CRYPTO.LEGACY_DEFAULT_IV = 0123456789ABCDEF:
declare
v_input char(32) :=
'Trees sway into 25MPH winds! ';
v_temp_raw raw(32);
v_key varchar2(64) :=
'STACKOVERFLOW123456PSRV235KGNKNVEFHEF3404757543MNVOVCNALADNC6579';
begin
sys.dbms_obfuscation_toolkit.DES3Encrypt(
input => UTL_I18N.STRING_TO_RAW ( v_input, 'AL32UTF8' ),
key => UTL_I18N.STRING_TO_RAW ( v_key, 'AL32UTF8' ),
encrypted_data => v_temp_raw
);
dbms_output.put_line ( v_temp_raw );
v_temp_raw := sys.DBMS_Crypto.encrypt (
src => UTL_I18N.STRING_TO_RAW ( v_input , 'AL32UTF8' ),
typ => DBMS_Crypto.ENCRYPT_3DES_2key + DBMS_Crypto.CHAIN_CBC + DBMS_Crypto.PAD_NONE,
key => UTL_I18N.STRING_TO_RAW ( v_key , 'AL32UTF8' ),
iv => hextoraw ( '0123456789ABCDEF' )
);
dbms_output.put_line ( v_temp_raw );
end;
/
2735BE289B76B7E7716616DE1152A2636FF136A098F5CF7065CB608E7AE261F5
2735BE289B76B7E7716616DE1152A2636FF136A098F5CF7065CB608E7AE261F5

Related

Oracle AQ between 2 databases wont propagate

I am trying to write a proof of concept to test sending/receiving messages between 2 Oracle database using AQ.
Source database : 12.1.0.2 SRCDB
Destination database: 19.14.0.0, DESTDB
We want to send a message from SRCDB to DESTDB, such that when DESTDB gets the message it automatically invokes a PLSQL stored procedure to dequeue and process.
So, start on the SRCDB I do the following:
CREATE OR REPLACE TYPE the_mesg AS OBJECT ( mesg VARCHAR2(20) );
/
`
BEGIN
DBMS_AQADM.CREATE_QUEUE_TABLE(
queue_table => 'the_que_tab',
queue_payload_type => 'the_mesg',
multiple_consumers => TRUE -- Mesg only consumed once ???
);
END;
/
-- create queue
BEGIN
DBMS_AQADM.CREATE_QUEUE(
queue_name => 'the_que',
queue_table => 'the_que_tab' );
END;
/
-- Add remote subscriber
DECLARE
reginfo SYS.AQ$_REG_INFO;
reginfolist SYS.AQ$_REG_INFO_LIST;
BEGIN
DBMS_AQADM.ADD_SUBSCRIBER(
queue_name => 'the_que',
subscriber => SYS.AQ$_AGENT( name => 'the)_sub',
address => 'the_remuser.the_que#destdb',
protocol => 0 ),
queue_to_queue => FALSE );
END;
/
-- Add propogation schedule
BEGIN
DBMS_AQADM.SCHEDULE_PROPAGATION(
queue_name => 'the_que',
latency => 0,
start_time => SYSDATE,
next_time => 'SYSDATE',
destination => 'destdb',
destination_queue => 'the_remuser.the_que' );
DBMS_LOCK.SLEEP(10);
END;
/
-- start queue
BEGIN
DBMS_AQADM.START_QUEUE(
queue_name => 'the_que',
enqueue => TRUE,
dequeue => TRUE );
DBMS_LOCK.SLEEP(10);
END;
/
-- propagation schedule
BEGIN
DBMS_AQADM.ENABLE_PROPAGATION_SCHEDULE(
queue_name => 'the_que',
destination => 'destdb',
destination_queue => 'the_remuser.the_que');
END;
/
-- Create send mesg wrapper procedure
CREATE OR REPLACE PROCEDURE send_mesg ( p_msg IN VARCHAR2 ) AS
l_enq_options SYS.DBMS_AQ.enqueue_options_t;
l_mesg_props SYS.DBMS_AQ.message_properties_t;
l_mesg_handle RAW(16);
l_mesg the_mesg;
BEGIN
l_mesg := the_mesg( p_msg );
DBMS_AQ.enqueue (
queue_name => 'the_que',
enqueue_options => l_enq_options,
message_properties => l_mesg_props,
payload => l_mesg,
msgid => l_mesg_handle );
COMMIT;
END;
/
-- Send mesg
EXEC send_mesg ( 'hello' );
Here, the queue's enqueue/dequeue settings are enabled, and there is an entry for the message in the queue table.
Then on the destdb:
CREATE OR REPLACE TYPE the_mesg AS OBJECT (
mesg VARCHAR2(20)
);
/
BEGIN
DBMS_AQADM.CREATE_QUEUE_TABLE(
queue_table => 'the_que',
queue_payload_type => 'the_mesg' );
END;
/
BEGIN
DBMS_AQADM.CREATE_QUEUE(
queue_name => 'the_que',
queue_table => 'the_que_tab' );
END;
/
DECLARE
reginfo SYS.AQ$_REG_INFO;
reginfolist SYS.AQ$_REG_INFO_LIST;
BEGIN
reginfo := SYS.AQ$_REG_INFO( 'the_remuser.the_que',
1,
'PLSQL://recv_mesg',
HEXTORAW('FF') );
reginfolist := SYS.AQ$_REG_INFO_LIST ( reginfo );
DBMS_AQ.REGISTER ( reg_list => reginfolist,
reg_count => 1 );
END;
/
BEGIN
DBMS_AQADM.START_QUEUE( queue_name => 'the_que',
dequeue => TRUE );
END;
/
CREATE TABLE mesg_table_aq_demo
(
cdate DATE DEFAULT SYSDATE,
mesg VARCHAR2(32) NOT NULL
);
CREATE OR REPLACE PROCEDURE recv_mesg
(
context IN RAW,
reginfo IN SYS.AQ$_REG_INFO,
descr IN SYS.AQ$_DESCRIPTOR,
payload IN RAW,
payload1 IN NUMBER
)
IS
l_deq_options DBMS_AQ.dequeue_options_t;
l_mesg_props DBMS_AQ.message_properties_t;
l_mesg_handle RAW(16);
l_mesg the_mesg;
no_messages EXCEPTION;
PRAGMA EXCEPTION_INIT ( no_messages, -25228 );
BEGIN
l_deq_options.msgid := descr.msg_id;
l_deq_options.consumer_name := descr.consumer_name;
LOOP
DBMS_AQ.dequeue ( queue_name => 'the_que',
dequeue_options => l_deq_options,
message_properties => l_mesg_props,
payload => l_mesg,
msgid => l_mesg_handle );
INSERT INTO mesg_table_aq_demo ( cdate, mesg )
VALUES ( SYSDATE, l_mesg.mesg );
COMMIT;
END LOOP;
EXCEPTION
WHEN no_messages THEN
NULL;
WHEN OTHERS THEN
RAISE;
END;
/
When I run this by enqueuing a message on the SRCDB the message is not propagated to the DESTDB.
No errors, although sometimes (as a result of desperate hacking) I see the following on the source user_queue_schedules:
ORA-25226: dequeue failed, queue SRCUSER.THE_QUE is not enabled for dequeue
Even though it looks like it is.
What am I doing wrong?

ORA-29913-Error executing call, after migrating the database to Exadata

I have a scheduler job which calls the procedure PR_DELETE_AUDIT_LOG. This code was working fine until the Oracle database was migrated to Exadata. Now whenever the job is executed we get the following errors as shown below.
ORA-29913: Error executing call
ORA-06512: in "ABC.PR_DELETE_AL_IMPORTLOG", AT LINE 49
ORA-06512: in "ABC.PR_DELETE_AL_IMPORTLOG", AT LINE 34
ORA-06512: in "ABC.PR_DELETE_AL_IMPORTLOG", AT LINE 34
The code for the job and the procedures are as follows.
DELETE_AL_IMPORTLOG_JOB
BEGIN
DBMS_SCHEDULER.CREATE_JOB (
job_name => 'ABC.DELETE_AL_IMPORTLOG_JOB',
job_type => 'STORED_PROCEDURE',
job_action => 'ABC.PR_DELETE_AL_IMPORTLOG',
number_of_arguments => 0,
start_date => NULL,
repeat_interval => 'FREQ=DAILY;BYTIME=000000',
end_date => NULL,
enabled => FALSE,
auto_drop => FALSE,
comments => '');
DBMS_SCHEDULER.SET_ATTRIBUTE(
name => 'ABC.DELETE_AL_IMPORTLOG_JOB',
attribute => 'store_output', value => TRUE);
DBMS_SCHEDULER.SET_ATTRIBUTE(
name => 'ABC.DELETE_AL_IMPORTLOG_JOB',
attribute => 'logging_level', value => DBMS_SCHEDULER.LOGGING_OFF);
DBMS_SCHEDULER.enable(
name => 'ABC.DELETE_AL_IMPORTLOG_JOB');
END;
/
PR_DELETE_AL_IMPORTLOG
CREATE OR REPLACE EDITIONABLE PROCEDURE "ABC"."PR_DELETE_AL_IMPORTLOG"
AS
V_DELETION_DATE DATE;
CURSOR CUR_OLD_FILES
IS SELECT FNAME
FROM EXT_TAB_AL_IMPORTLOG_FILE_LIST
WHERE REGEXP_LIKE(FNAME,'AL_\d{2}-\d{2}-\d{2}_\d{8}_\d{6}.txt')
AND TO_DATE(SUBSTR(FNAME, -19,15),'YYYYMMDD_HH24MISS') < V_DELETION_DATE;
BEGIN
SELECT ADD_MONTHS
( TRUNC
( SYSDATE
, DECODE( STARTZEITPUNKTABF
, 1 ,'DD'
, 2 ,'MM'
, 3 ,'Q'
, 4 ,'YY'
,'DD'
)
)
, DECODE(PERIODEABF,2,-DAUERABF,3,-DAUERABF*12,0)) - DECODE(PERIODEABF,1,DAUERABF,0)
INTO V_DELETION_DATE
FROM LOESCHREGEL
WHERE VERWENDUNGSZWECK_ID = 'CLALL';
FOR REC_OLD_FILES IN CUR_OLD_FILES
LOOP
UTL_FILE.FREMOVE('ABC_AL_IMPORTLOG', REC_OLD_FILES.FNAME);
dbms_output.put_line('Deleted file '||REC_OLD_FILES.FNAME);
END LOOP;
EXCEPTION
WHEN OTHERS
THEN
DECLARE
V_PROCEDURE_NAME VARCHAR2(30) := $$PLSQL_UNIT;
V_SUBJECT VARCHAR2(255) := 'Error on DB procedure '||V_PROCEDURE_NAME||' on '||to_char(sysdate,'dd.mm.yyyy hh24:mi:ss');
V_BODY VARCHAR2(10000) := 'Hi all,'||chr(10)||chr(10)||'Procedure '||V_PROCEDURE_NAME||' returned the following error:'||chr(10)||SQLERRM;
BEGIN
SEND_MAIL ( 'GENERIC_DB_ERROR', V_SUBJECT,V_BODY);
RAISE;
END;
END PR_DELETE_AL_IMPORTLOG;
/
DDL for Table EXT_TAB_AL_IMPORTLOG_FILE_LIST
CREATE TABLE ABC.EXT_TAB_AL_IMPORTLOG_FILE_LIST
( FNAME VARCHAR2(255 CHAR )
)
ORGANIZATION EXTERNAL
( TYPE ORACLE_LOADER
DEFAULT DIRECTORY COLEIN_AUDITLOG
ACCESS PARAMETERS
( RECORDS DELIMITED BY NEWLINE
PREPROCESSOR COLEIN_PROCESS:'AL_ImportLog_list_files.sh'
noLOGFILE
nobadfile
nodiscardfile
FIELDS TERMINATED BY WHITESPACE
)
LOCATION
( 'lsOutput.log'
)
)
REJECT LIMIT UNLIMITED ;
where is the problem?
The error seems to come from a value of ext_tab_al_importlog_file_list.fname that doesn't match the expected filename format. You might want to check the values to see which one is invalid and how it got there.
If you are using Oracle 12.2 or later, change the cursor to use an on conversion error clause:
select fname
from ext_tab_al_importlog_file_list
where regexp_like(fname, 'AL_\d{2}-\d{2}-\d{2}_\d{8}_\d{6}.txt')
and to_date(substr(fname, -19, 15) default null on conversion error, 'YYYYMMDD_HH24MISS') < v_deletion_date;
If not, you could try adding some more filters:
select fname
from ext_tab_al_importlog_file_list
where regexp_like(fname, 'AL_\d{2}-\d{2}-\d{2}_\d{8}_\d{6}.txt')
and to_date(substr(fname, -19, 15), 'YYYYMMDD_HH24MISS') < v_deletion_date
and to_number(substr(fname,-10,2)) < 24
and to_number(substr(fname,-8,2)) < 60
and to_number(substr(fname,-6,2)) < 60;
This worked in my quick test, but combining filters with a conversion function is risky because there is no guarantee that Oracle will apply the filtering conditions in any particular order.
You can find the invalid values using either of the following:
select fname
from ext_tab_al_importlog_file_list
where regexp_like(fname, 'AL_\d{2}-\d{2}-\d{2}_\d{8}_\d{6}.txt')
and to_date(substr(fname, -19, 15) default null on conversion error, 'YYYYMMDD_HH24MISS') is null;
select fname
from ext_tab_al_importlog_file_list
where regexp_like(fname, 'AL_\d{2}-\d{2}-\d{2}_\d{8}_\d{6}.txt')
and ( to_number(substr(fname,-10,2)) >= 24
or to_number(substr(fname,-8,2)) >= 60
or to_number(substr(fname,-6,2)) >= 60 );

Oracle - Generate Package.Procedure call

Good morning guys,
do you know an easy way to automatically generate an Oracle package.procedure call?
After have defined the package
Create Or Replace Package PKG1
As
Procedure PRC1
(
P_VAL1_I In NUMBER,
P_Return_Set_O Out Sys_Refcursor,
);
End;
I'd like to generate via a script the call
DECLARE
var_P_RETURN_SET_O SYS_REFCURSOR;
BEGIN
PKG1.PRC1(P_VAL1_I => 0, P_Return_Set_O => var_P_RETURN_SET_O );
END;
Of Course I'll replace later the input parameter(s).
Any idea/suggestion?
Here the answer to myself .. was not that difficult .. simply run a pl/sql that build the procedure call .
Declare
l_Package varchar2(255) :=upper('xxxxxxxxx');
l_Proc varchar2(255) :=upper('xxxxxxxxxxxx');
Begin
Dbms_Output.Put_Line('DECLARE');
For Var_Out In (
select ObjArg.Argument_Name,Data_type
FROM sys.user_objects UsrObj
Inner Join sys.user_arguments ObjArg On UsrObj.object_id= ObjArg.object_id
Where UsrObj.object_name = l_Package
And ObjArg.ObjecT_Name= l_Proc
AND UsrObj.object_type = 'PACKAGE'
And ObjArg.In_Out='OUT'
)
Loop
Dbms_Output.Put_Line('L_'||Var_Out.Argument_Name ||' '||Var_Out.Data_type||';');
end Loop;
Dbms_Output.Put_Line('BEGIN');
Dbms_Output.Put_Line(l_Package||'.'||l_Proc);
Dbms_Output.Put_Line('(');
For PArams In (
select ObjArg.Argument_Name,Data_type,ObjArg.In_Out
FROM sys.user_objects UsrObj
Inner Join sys.user_arguments ObjArg On UsrObj.object_id= ObjArg.object_id
Where UsrObj.object_name = l_Package
And ObjArg.ObjecT_Name= l_Proc
AND UsrObj.object_type = 'PACKAGE'
)
Loop
IF PArams.In_Out='OUT' Then
Dbms_Output.Put_Line(PArams.Argument_Name || '=> L_'||PArams.Argument_Name);
ELSE
Dbms_Output.Put_Line(PArams.Argument_Name || '=> xxx');
End If;
end Loop;
Dbms_Output.Put_Line(');');
Dbms_Output.Put_Line('END');
End;
Result ..
DECLARE
L_P_RETURN_SET_O REF CURSOR;
L_P_EXECUTION_STATUS_O NUMBER;
BEGIN
PKG.PROC
(
P_PARAM_I=> xxx
P_RETURN_SET_O=> L_P_RETURN_SET_O
);
END;
The code is not perfect ..but it works ...
Did you try:
variable rc refcursor;
exec PKG1.PRC1(0, :rc);
print rc;
You can create job which will call your procedure on specified intervals.
For instance:
BEGIN
DBMS_SCHEDULER.CREATE_JOB
(
job_name => 'JOB_NAME'
,start_date => SYSDATE
,repeat_interval => 'FREQ=DAILY;BYHOUR=05;BYMINUTE=00;BYSECOND=00'
,end_date => NULL
,job_class => 'DEFAULT_JOB_CLASS'
,job_type => 'PLSQL_BLOCK'
,job_action => 'BEGIN
PKG1.PRC1(P_VAL1_I => 0, P_Return_Set_O => var_P_RETURN_SET_O );
END;
,comments => 'JOB_NAME'
);
DBMS_SCHEDULER.ENABLE(name => 'JOB_NAME');
END;
This job will run daily at 5 a.m .
I hope it will solve your problem!

How do I call a function from within a PL/SQL process within Oracle APEX 4.2

I've created a new function called GET_FILENAME inside my Oracle APEX database. I'd like to call this function from within a APEX PL/SQL code block and pass it the filename. Below is the function I created in my APEX DB with SQL Dev.
create or replace function get_filename
(p_path IN VARCHAR2)
RETURN varchar2
IS
v_file VARCHAR2(100);
BEGIN
-- Parse string for UNIX system
IF INSTR(p_path,'/') > 0 THEN
v_file := SUBSTR(p_path,(INSTR(p_path,'/',-1,1)+1),length(p_path));
-- Parse string for Windows system
ELSIF INSTR(p_path,'\') > 0 THEN
v_file := SUBSTR(p_path,(INSTR(p_path,'\',-1,1)+1),length(p_path));
-- If no slashes were found, return the original string
ELSE
v_file := p_path;
END IF;
RETURN v_file;
END;
APEX side of things....
Below is the code I'd like to put in when calling the process.
TO_DATE(SUBSTR(GET_FILENAME(file_date),21,8),'YYYY-MM-DD')
Below is the apex process code and the comments are where I'd like to put it in.
BEGIN
APEX_COLLECTION.ADD_MEMBER
(
p_collection_name => 'PARSE_COL_HEAD',
p_c001 => 'C031',
p_c002 => 'FILE_DATE');
FOR UPLOAD_ROW IN (SELECT SEQ_ID FROM APEX_COLLECTIONS
WHERE COLLECTION_NAME = 'SPREADSHEET_CONTENT')
LOOP
APEX_COLLECTION.UPDATE_MEMBER_ATTRIBUTE (
p_collection_name => 'SPREADSHEET_CONTENT',
p_seq => UPLOAD_ROW.SEQ_ID,
p_attr_number => '31',
p_attr_value => :P25_FILE_NAME -- I want to call the process here
);
END LOOP;
END;
I don't normally answer my own question. But this was easier than I thought :). Below is the code I used to get this working....
BEGIN
APEX_COLLECTION.ADD_MEMBER
(
p_collection_name => 'PARSE_COL_HEAD',
p_c001 => 'C031',
p_c002 => 'FILE_DATE');
FOR UPLOAD_ROW IN (SELECT SEQ_ID FROM APEX_COLLECTIONS
WHERE COLLECTION_NAME = 'SPREADSHEET_CONTENT')
LOOP
APEX_COLLECTION.UPDATE_MEMBER_ATTRIBUTE (
p_collection_name => 'SPREADSHEET_CONTENT',
p_seq => UPLOAD_ROW.SEQ_ID,
p_attr_number => '31',
p_attr_value => TO_DATE(SUBSTR(GET_FILENAME(:P25_FILE_NAME),21,8),'YYYY-MM-DD')
);
END LOOP;
END;

Encrypt/Decrypt Password in Oracle Function

Due to previously poorly designed structure, the current database that I have to work with stores users' password as text.
Now, I am building a front end part that has to use those passwords and I certainly don't want to be sending passwords unencrypted.
My idea is to write an Oracle function to encrypt and decrypt text password and use those functions in the stored procedures that will return encrypted data.
What would be the best approach in Oracle to do so?
If you want to write your own functions to encrypt and decrypt data, you would simply want to call the DBMS_CRYPTO encrypt and decrypt methods with appropriate parameters (i.e. pick your encryption algorithm, your key, etc.).
Of course, if you write your own routines, assuming that you store the key in the database or somewhere the database has access to, you're not doing much for security. It's bad to send passwords unencrypted over the network but it is generally much worse to store unencrypted passwords in the database (or encrypted passwords if there is a decrypt method in the database that has access to the key to decrypt the data). It's generally a lot easier to steal data from a database than it is to sniff data getting sent over the network in order to find a password.
The right answer, of course, would be to rearchitect the system so that you don't store the passwords at all. You should be storing password hashes (which you can also generate using the DBMS_CRYPTO package) which are non-reversible.
Take a look at DBMS_CRYPTO
It has methods to encrypt and decrypt data built in. Better than writing your own.
http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_crypto.htm
Or you could use the password hashing algorithm pbkdf2 like this http://mikepargeter.wordpress.com/2012/11/26/pbkdf2-in-oracle/
I verified the outcome with the rfc https://www.ietf.org/rfc/rfc6070.txt and it works fine.
Check this link for minimal iterations and key_size: PBKDF2 recommended key size?
Note that the result is double the length, because it is hex-encoded.
we store these columns in the db
PASSWORD_HASH VARCHAR2(512 BYTE),
PASSWORD_SALT VARCHAR2(256 BYTE),
PASSWORD_ITERATIONS NUMBER(10),
PASSWORD_HASH_METHOD VARCHAR2(30 BYTE),
PASSWORD_CHANGED_DT DATE
the hash, salt and iterations are to feed the pbkdf2 algorithm
the hash_method is for migration purposes
and the changed_dt is to expire passwords
Here's a packaged function (successful implementation) for encrypting passwords using (DBMS_CRYPTO)-
CREATE OR REPLACE
PACKAGE BODY encrypt_paswd
AS
G_CHARACTER_SET VARCHAR2(10) := 'AL32UTF8';
G_STRING VARCHAR2(32) := '12345678901234567890123456789012';
G_KEY RAW(250) := utl_i18n.string_to_raw
( data => G_STRING,
dst_charset => G_CHARACTER_SET );
G_ENCRYPTION_TYPE PLS_INTEGER := dbms_crypto.encrypt_aes256
+ dbms_crypto.chain_cbc
+ dbms_crypto.pad_pkcs5;
------------------------------------------------------------------------
--Encrypt a password
--Salt the password
------------------------------------------------------------------------
FUNCTION encrypt_val( p_val IN VARCHAR2 ) RETURN RAW
IS
l_val RAW(32) := UTL_I18N.STRING_TO_RAW( p_val, G_CHARACTER_SET );
l_encrypted RAW(32);
BEGIN
l_val := utl_i18n.string_to_raw
( data => p_val,
dst_charset => G_CHARACTER_SET );
l_encrypted := dbms_crypto.encrypt
( src => l_val,
typ => G_ENCRYPTION_TYPE,
key => G_KEY );
RETURN l_encrypted;
END encrypt_val;
END encrypt_paswd;
This uses encrypt_aes256 -"Advanced Encryption Standard. Block cipher. Uses 256-bit key size." , chain_cbc- "Cipher Block Chaining. Plaintext is XORed with the previous ciphertext block before it is encrypted." and pad_pkcs5 - "Provides padding which complies with the PKCS #5: Password-Based Cryptography Standard".
In addition to this You can create a similar function to decrypt. like -
FUNCTION decrypt_val( p_val IN RAW ) RETURN VARCHAR2
IS
l_decrypted RAW(32);
l_decrypted_string VARCHAR2(32);
l_user VARCHAR2(32);
BEGIN
SELECT user
INTO l_user
FROM dual;
if l_user = 'ADMIN' -- you can restrict usage of decrypt to certain db users only.
then
l_decrypted := dbms_crypto.decrypt
( src => p_val,
typ => G_ENCRYPTION_TYPE,
key => G_KEY );
l_decrypted_string := utl_i18n.raw_to_char
( data => l_decrypted,
src_charset => G_CHARACTER_SET );
RETURN l_decrypted_string;
else
RAISE_APPLICATION_ERROR(-20101, 'You are not authorized to use this function - decrypt_val()');
end if;
RETURN 'Unknown';
END decrypt_val;
You may also consider wrapping the package before compiling it in the database using wrap iname=package_name.pkb and then compiling the resulting plb.
user this code definitely work
create or replace PACKAGE "PKG_LOGI_PWD_REG"
AS
function ENCRYPT_VAL( P_VAL in varchar2 ) return varchar2;
function DECRYPT_VAL( P_VAL in raw ) return varchar2;
end;
/
create or replace PACKAGE BODY "PKG_LOGI_PWD_REG"
as
FUNCTION decrypt_val( p_val IN RAW ) RETURN VARCHAR2
IS
l_decrypted RAW(32);
l_decrypted_string VARCHAR2(32);
L_USER varchar2(32);
L_CHARACTER_SET varchar2(10);
L_STRING varchar2(32);
L_KEY raw(250);
L_ENCRYPTION_TYPE PLS_INTEGER;
BEGIN
L_KEY := UTL_I18N.STRING_TO_RAW
( data => '98345678901234567890123456789012',
DST_CHARSET => 'AL32UTF8' );
L_ENCRYPTION_TYPE := dbms_crypto.encrypt_aes256
+ DBMS_CRYPTO.CHAIN_CBC
+ DBMS_CRYPTO.PAD_PKCS5;
l_decrypted := dbms_crypto.decrypt
( SRC => P_VAL,
TYP => L_ENCRYPTION_TYPE,
key => L_KEY );
l_decrypted_string := utl_i18n.raw_to_char
( data => l_decrypted ,
src_charset => 'AL32UTF8' );
RETURN l_decrypted_string;
end DECRYPT_VAL;
FUNCTION encrypt_val( p_val IN VARCHAR2 ) RETURN VARCHAR2
is
L_VAL RAW(32);
L_ENCRYPTED raw(32);
L_CHARACTER_SET varchar2(10);
L_STRING varchar2(32);
L_KEY RAW(250);
L_ENCRYPTION_TYPE PLS_INTEGER;
begin
L_KEY := UTL_I18N.STRING_TO_RAW
( data => '98345678901234567890123456789012',
DST_CHARSET => 'AL32UTF8' );
L_ENCRYPTION_TYPE := dbms_crypto.encrypt_aes256
+ DBMS_CRYPTO.CHAIN_CBC
+ DBMS_CRYPTO.PAD_PKCS5;
L_VAL := utl_i18n.string_to_raw
( data => p_val,
dst_charset => 'AL32UTF8' );
L_ENCRYPTED := dbms_crypto.encrypt
( SRC => L_VAL,
TYP => L_ENCRYPTION_TYPE,
key => L_KEY );
return L_ENCRYPTED;
EXCEPTION when OTHERS then
RETURN SQLCODE||'-'||SQLERRM;
end ENCRYPT_VAL;
end PKG_LOGI_PWD_REG;
/

Resources