How to use PBKDF2 in Oracle 12c? - oracle

We want to save user passwords in Oracle 12c. I found the dbms_crypto-Package but there was no information about PBKDF2.
What's the current state in 2017 to use PBKDF2 in Oracle 12c?

This is a late answer, but to the best of my knowledge Oracle's DBMS_CRYPTO package does not support PBKDF2 natively. That said, you can implement the algorithm yourself; here is one way to do it:
CREATE OR REPLACE FUNCTION pbkdf2
( p_password IN VARCHAR2
, p_salt IN VARCHAR2
, p_count IN INTEGER
, p_key_length IN INTEGER )
RETURN VARCHAR2
IS
l_block_count INTEGER;
l_last RAW(32767);
l_xorsum RAW(32767);
l_result RAW(32767);
BEGIN
l_block_count := CEIL(p_key_length / 20); -- use 20 bytes for SHA1, 32 for SHA256, 64 for SHA512
FOR i IN 1..l_block_count LOOP
l_last := UTL_RAW.CONCAT(UTL_RAW.CAST_TO_RAW(p_salt), UTL_RAW.CAST_FROM_BINARY_INTEGER(i, UTL_RAW.BIG_ENDIAN));
l_xorsum := NULL;
FOR j IN 1..p_count LOOP
l_last := DBMS_CRYPTO.MAC(l_last, DBMS_CRYPTO.HMAC_SH1, UTL_RAW.CAST_TO_RAW(p_password));
-- use HMAC_SH256 for SHA256, HMAC_SH512 for SHA512
IF l_xorsum IS NULL THEN
l_xorsum := l_last;
ELSE
l_xorsum := UTL_RAW.BIT_XOR(l_xorsum, l_last);
END IF;
END LOOP;
l_result := UTL_RAW.CONCAT(l_result, l_xorsum);
END LOOP;
RETURN RAWTOHEX(UTL_RAW.SUBSTR(l_result, 1, p_key_length));
END pbkdf2;
/
This code was originally found here: PBKDF2 in Oracle; I've confirmed that it works on my own system in SHA-1, SHA-256, and SHA-512. Note that p_count is the number of iterations and p_key_length is the length of the key. See this question for more information on the recommended number of iterations and recommended key length for PBKDF2.
Hope this helps.

Your application server should be doing the PBKDF2 before it gets to the database - don't spend your precious, limited Oracle resources on that.
And don't let your DBA's see the passwords in plaintext, either, as they'd have to if Oracle is the one doing the hashing!
I have a variety of PBKDF2 examples in My github repository, including test vectors and, if you absolutely insist on doing it in Oracle, one pure SQL Server implementation that shouldn't be difficult to convert to PL/SQL.

Related

How to encrypt nvarchar column in oracle?

I have a table containing nvarchar datatype columns (contains text in different languages). I want to encrypt data before inserting into table and decrypt the same while fetching records.
Please suggest how i can achieve this.
Encryption and decryption should be done through a private key.
Hoping, my question is clear. Please confirm if i need to provide more information.
Note that it is probably wiser to crypt and decrypt your data directly in your application rather than in the database.
You can use Oracle's DBMS_CRYPTO package. There is an example in the middle of the documentation page.
First you need to make a package to access the cipher type from SQL expression. Let's say you want AES256 in CBC mode with padding:
CREATE PACKAGE pkg_so_42979606
AS
FUNCTION cipher_type RETURN PLS_INTEGER;
END pkg_so_42979606;
/
CREATE PACKAGE BODY pkg_so_42979606
AS
ctype CONSTANT PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_AES256
+ DBMS_CRYPTO.CHAIN_CBC
+ DBMS_CRYPTO.PAD_PKCS5;
FUNCTION cipher_type RETURN PLS_INTEGER
IS
BEGIN
RETURN ctype;
END;
END pkg_so_42979606;
/
Then you will need a key. You can ask Oracle to generate one. To easily handle it I'll move it in Base64. Let's draw one:
DECLARE
key_bytes_raw RAW(32);
key_char NVARCHAR2(64);
BEGIN
key_bytes_raw := DBMS_CRYPTO.RANDOMBYTES(32);
key_char := UTL_I18N.RAW_TO_CHAR(UTL_ENCODE.BASE64_ENCODE(key_bytes_raw), 'AL32UTF8');
DBMS_OUTPUT.PUT_LINE('Key: ' || key_char);
END;
/
Key: pMV3D4xhyfNxp3YyfLWzAErGcKkIjK3X6uc/WIeVTls=
Thus the cipher key I'll use is pMV3D4xhyfNxp3YyfLWzAErGcKkIjK3X6uc/WIeVTls=.
Now I'll use a test table
CREATE TABLE so_42979606 (
id NUMBER PRIMARY KEY,
data NVARCHAR2(2000));
You can insert encrypted data:
INSERT INTO so_42979606
VALUES (1,
DBMS_CRYPTO.ENCRYPT(UTL_I18N.STRING_TO_RAW('My clear data', 'AL32UTF8'),
pkg_so_42979606.cipher_type(),
UTL_ENCODE.BASE64_DECODE(UTL_I18N.STRING_TO_RAW('pMV3D4xhyfNxp3YyfLWzAErGcKkIjK3X6uc/WIeVTls=', 'AL32UTF8'))));
And retrieve the encrypted data in clear.
SELECT id, UTL_I18N.RAW_TO_NCHAR(DBMS_CRYPTO.DECRYPT(data,
pkg_so_42979606.cipher_type(),
UTL_ENCODE.BASE64_DECODE(UTL_I18N.STRING_TO_RAW('pMV3D4xhyfNxp3YyfLWzAErGcKkIjK3X6uc/WIeVTls=', 'AL32UTF8'))),
'AL32UTF8') data
FROM so_42979606;
ID DATA
-- ----------------------
1 My clear data

Oracle BLOB to base64 CLOB

Can I convert an oracle BLOB to Base64 CLOB in One go?
like:
CREATE TABLE test
(
image BLOB,
imageBase64 CLOB
);
INSERT INTO test(image)
VALUES (LOAD_FILE('/full/path/to/new/image.jpg'));
UPDATE test SET imageBase64 = UTL_ENCODE.base64_encode(image);
commit;
I know I can add functions/Stored proc to do the work. Performance aspect is very important,so I am asking if there is a way to overcome the 32K limitation by directly pushing the data into a CLOB.
This function got from here should do the job.
CREATE OR REPLACE FUNCTION base64encode(p_blob IN BLOB)
RETURN CLOB
-- -----------------------------------------------------------------------------------
-- File Name : http://oracle-base.com/dba/miscellaneous/base64encode.sql
-- Author : Tim Hall
-- Description : Encodes a BLOB into a Base64 CLOB.
-- Last Modified: 09/11/2011
-- -----------------------------------------------------------------------------------
IS
l_clob CLOB;
l_step PLS_INTEGER := 12000; -- make sure you set a multiple of 3 not higher than 24573
BEGIN
FOR i IN 0 .. TRUNC((DBMS_LOB.getlength(p_blob) - 1 )/l_step) LOOP
l_clob := l_clob || UTL_RAW.cast_to_varchar2(UTL_ENCODE.base64_encode(DBMS_LOB.substr(p_blob, l_step, i * l_step + 1)));
END LOOP;
RETURN l_clob;
END;
/
Then the update can look like
UPDATE test SET imageBase64 = base64encode(image);
Note that maybe the function should be optimized with the function DBMS_LOB.APPEND instead of that concatenation operator. Try that if you have performance problems.
Provided that stored procs would despite be a viable alternative for you, here's one possible solution to your problem ...
First, let's make that nice base64encode() function of Tim Hall's into a procedure ...
create or replace procedure base64encode
( i_blob in blob
, io_clob in out nocopy clob )
is
l_step pls_integer := 22500; -- make sure you set a multiple of 3 not higher than 24573
l_converted varchar2(32767);
l_buffer_size_approx pls_integer := 1048576;
l_buffer clob;
begin
dbms_lob.createtemporary(l_buffer, true, dbms_lob.call);
for i in 0 .. trunc((dbms_lob.getlength(i_blob) - 1 )/l_step) loop
l_converted := utl_raw.cast_to_varchar2(utl_encode.base64_encode(dbms_lob.substr(i_blob, l_step, i * l_step + 1)));
dbms_lob.writeappend(l_buffer, length(l_converted), l_converted);
if dbms_lob.getlength(l_buffer) >= l_buffer_size_approx then
dbms_lob.append(io_clob, l_buffer);
dbms_lob.trim(l_buffer, 0);
end if;
end loop;
dbms_lob.append(io_clob, l_buffer);
dbms_lob.freetemporary(l_buffer);
end;
The "trick" here is to directly use the persistent LOB locators in calls to procedures/functions. Why "persistent"? Because if you create a function that returns a LOB, then there's a temporary LOB created in background and this means some TEMP disk/memory usage and LOB content copying involved. For large LOBs this may imply a performance hit. In order to satisfy your requirement of making this the most performing possible, you should avoid this TEMP space usage. Hence, for this approach, a stored procedure instead of a function must be used.
Then, of course, the procedure must be fed with persistent LOB locators. You have to do that, again, with a stored procedure, where you e.g. insert an empty LOB (effectively creating a new LOB locator) to a table first, and then supplying that newly created LOB locator to the base64 encoding routine ...
create or replace procedure load_and_encode_image
( i_file_name in varchar2 )
is
l_input_bfile bfile := bfilename('DIR_ANYTHING', i_file_name);
l_image_base64_lob test.imageBase64%type;
l_image_raw test.image%type;
begin
insert into test(image, imageBase64)
values (empty_blob(), empty_clob())
returning image, imageBase64
into l_image_raw, l_image_base64_lob;
begin
dbms_lob.fileopen(l_input_bfile);
dbms_lob.loadfromfile(
dest_lob => l_image_raw,
src_lob => l_input_bfile,
amount => dbms_lob.getlength(l_input_bfile)
);
dbms_lob.fileclose(l_input_bfile);
exception
when others then
if dbms_lob.fileisopen(l_input_bfile) = 1 then
dbms_lob.fileclose(l_input_bfile);
end if;
raise;
end;
base64encode(
i_blob => l_image_raw,
io_clob => l_image_base64_lob
);
end;
Note: Of course, if you base64-encode only small files (the actual size depends on your PGA settings, I guess; a question for a DBA, this is), then the function-based approach may be equally performing than this procedure-based one. Base64-encoding a 200MB file on my laptop took 55 seconds with the function+update approach, 14 seconds with the procedure approach. Not exactly a speed demon, so choose what suits your needs.
Note: I believe this procedure-based approach may be further speeded up by reading the file to inmemory chunks in loop, base64-encoding the chunks to another inmemory chunks and appending them both to the target persistent LOBs. That way you should make the workload even easier by avoiding re-reading the full test.image LOB contents by the base64encode() procedure.
I solved this same problem at work by using a Java stored procedure. There is no chunking/contatenation of VARCHAR2s involved in such an approach, since the ability to encode/decode base64 is natively built into Java, simply writing an Oracle function that thinly wraps the Java method works well and is high-performance since as soon as you've executed it a few times, the HotSpot JVM compiles the Java proc into low-level code (high performance just like a C stored function). I'll edit this answer later and add the details about that Java code.
But to step back just one step, question why are you storing this data as both a BLOB and base64 encoded (CLOB)? Is it because you have clients that want to consume the data in the latter format? I'd really prefer to only store the BLOB format. One reason why is that the base64 encoded version can be double the size of the original binary BLOB, so storing them both means possibly 3x the storage.
One solution, the one I implemented at work, to create your own Java stored function base64_encode() that encodes binary --> base64 and then use that function to encode base64 on the fly at query time (it's not expensive). From the application/client side, you would query something like SELECT base64_encode(image) FROM test WHERE ...
If the application code can't be touched (ie COTS application) or if your developers aren't thrilled about using a function, you could abstract this for them (since you are using 11g+) by using a VIRTUAL (computed) column on the table which contains the computed base64_encode(image). It would function like a view, in that it wouldn't physically store the encoded CLOBs, but would generate them at query time. To any client, they would not be able to tell they are not reading a physical column. The other benefit is that if you ever update the jpg (BLOB), the virtual CLOB is immediately and automatically updated. If you ever have to insert/update/delete a huge batch of BLOBs, you'd save 66% of the redo/archivelog volume from not having to process all the CLOBs.
Lastly, for performance, make very sure you are using SecureFile LOBs (both for BLOBs and CLOBs). They really are much faster and better in just about every way.
UPDATE - I found my code, at least the version that uses a Java Stored Procedure to do the opposite (converting a base64 encoded CLOB to its binary BLOB version). It would not be that difficult to write the inverse.
--DROP FUNCTION base64_decode ;
--DROP java source base64;
-- This is a PLSQL java wrapper function
create or replace
FUNCTION base64_decode (
myclob clob)
RETURN blob
AS LANGUAGE JAVA
NAME 'Base64.decode (
oracle.sql.CLOB)
return oracle.sql.BLOB';
/
-- The Java code that base64 decodes a clob and returns a blob.
create or replace and compile java source named base64 as
import java.sql.*;
import java.io.*;
import oracle.sql.*;
import sun.misc.BASE64Decoder;
import oracle.jdbc.driver.*;
public class Base64 {
public static oracle.sql.BLOB decode(oracle.sql.CLOB myBase64EncodedClob)
{
BASE64Decoder base64 = new BASE64Decoder();
OutputStream outstrm = null;
oracle.sql.BLOB myBlob = null;
ByteArrayInputStream instrm = null;
try
{
if (!myBase64EncodedClob.equals("Null"))
{
Connection conn = new OracleDriver().defaultConnection();
myBlob = oracle.sql.BLOB.createTemporary(conn, false,oracle.sql.BLOB.DURATION_CALL);
outstrm = myBlob.getBinaryOutputStream();
ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
InputStream in = myBase64EncodedClob.getAsciiStream();
int c;
while ((c = in.read()) != -1)
{
byteOutStream.write((char) c);
}
instrm = new ByteArrayInputStream(byteOutStream.toByteArray());
try // Input stream to output Stream
{
base64.decodeBuffer(instrm, outstrm);
}
catch (Exception e)
{
e.printStackTrace();
}
outstrm.close();
instrm.close();
byteOutStream.close();
in.close();
conn.close();
}
}
catch (Exception e)
{
e.printStackTrace();
}
return myBlob;
} // Public decode
} // Class Base64
;
/
The easiest way that I found, that works with special characters (in your case you don't have this problem), is using dbms_lob.converttoclob.
Create encapsulated Procedure:
CREATE OR REPLACE FUNCTION blob2clob(blob_i IN BLOB) RETURN CLOB IS
l_clob CLOB;
l_dest_offset NUMBER := 1;
l_src_offset NUMBER := 1;
l_amount INTEGER := dbms_lob.lobmaxsize;
l_clob_csid NUMBER := nls_charset_id('WE8ISO8859P15'); --dbms_lob.default_csid;
l_lang_context INTEGER := dbms_lob.default_lang_ctx;
l_warning INTEGER;
BEGIN
---------------------------
-- Create Temporary BLOB --
---------------------------
dbms_lob.createtemporary(lob_loc => l_clob,
cache => TRUE);
--------------------------
-- Convert CLOB to BLOB --
--------------------------
dbms_lob.converttoclob(dest_lob => l_clob,
src_blob => blob_i,
amount => l_amount,
dest_offset => l_dest_offset,
src_offset => l_src_offset,
blob_csid => l_clob_csid,
lang_context => l_lang_context,
warning => l_warning);
--
RETURN l_clob;
END blob2clob;
Then you can use:
blob2clob(utl_encode.base64_encode(image))

one way encryption oracle

is there a way to do one way encryption for password in oracle? i'm passing in password from a textfield and would like to call a stored procedure in oralce and inside that stored procedure, it would encrypt the password. Thank you
Encryption is, by definition, two-way. You would never encrypt a password. I expect that you really want to hash the password. And you wouldn't want to just hash the password, you'd really want to combine the password with some sort of random salt and hash that.
You'd use the dbms_crypto.hash function to compute the hash and the dbms_random.string function to generate the salt. Something like
DECLARE
l_salt varchar2(50);
l_user varchar2(50);
l_pwd varchar2(50);
l_string_to_hash varchar2(150);
l_hash raw(150);
BEGIN
l_salt := dbms_random.string( 'P', 50 );
l_string_to_hash := l_user || l_pwd || l_salt;
l_hash := dbms_crypto.hash( utl_i18n.string_to_raw( l_string_to_hash, 'AL32UTF8' ),
dbms_crypto.hash_sh1 );
END;
See also this askTom discussion (which starts off using the older dbms_obfuscation_toolkit package rather than the dbms_crypto package) for more background on why you'd use a hash, the benefits of salting the password, etc.

What's the difference between pls_integer and binary_integer?

I've inherited some code which is going to be the base for some additional work. Looking at the stored procs, I see quite a lot of associative-arrays.
Some of these are indexed by binary_integers, some by pls_integers. Are there any differences between the two?
I had a look at the documentation, but apart from this line:
The PL/SQL data types PLS_INTEGER and BINARY_INTEGER are identical. For simplicity, this document uses PLS_INTEGER to mean both PLS_INTEGER and BINARY_INTEGER.
I couldn't find any difference between the two. So what's the difference? Are both around for historical/compatibility reasons?
I'm using Oracle 10gR2
Historical reasons. They used to be different before 10g:
On 8i and 9i, PLS_INTEGER was noticeably faster than BINARY_INTEGER.
When it comes to declaring and manipulating integers, Oracle offers lots of options, including:
INTEGER - defined in the STANDARD package as a subtype of NUMBER, this datatype is implemented in a completely platform-independent fashion, which means that anything you do with NUMBER or INTEGER variables should work the same regardless of the hardware on which the database is installed.
BINARY_INTEGER - defined in the STANDARD package as a subtype of INTEGER. Variables declared as BINARY_INTEGER can be assigned values between -231+1 .. 231-1, aka -2,147,483,647 to 2,147,483,647. Prior to Oracle9i Database Release 2, BINARY_INTEGER was the only indexing datatype allowed for associative arrays (aka, index-by tables), as in:
TYPE my_array_t IS TABLE OF VARCHAR2(100)
INDEX BY BINARY_INTEGER
PLS_INTEGER - defined in the STANDARD package as a subtype of BINARY_INTEGER. Variables declared as PLS_INTEGER can be assigned values between -231+1 .. 231-1, aka -2,147,483,647 to 2,147,483,647. PLS_INTEGER operations use machine arithmetic, so they are generally faster than NUMBER and INTEGER operations. Also, prior to Oracle Database 10g, they are faster than BINARY_INTEGER. In Oracle Database 10g, however, BINARY_INTEGER and PLS_INTEGER are now identical and can be used interchangeably.
binary_integer and pls_integer both are same. Both are PL/SQL datatypes with range -2,147,648,467 to 2,147,648,467.
Compared to integer and binary_integer pls_integer very fast in excution. Because pls_intger operates on machine arithmetic and binary_integer operes on library arithmetic.
pls_integer comes from oracle10g.
binary_integer allows indexing integer for assocative arrays prior to oracle9i.
Clear example:
SET TIMING ON
declare
num integer := 0;
incr integer := 1;
limit integer := 100000000;
begin
while num < limit loop
num := num + incr;
end loop;
end;
PL/SQL procedure successfully completed.
Elapsed: 00:00:20.23
ex:2
declare
num binary_integer := 0;
incr binary_integer := 1;
limit binary_integer := 100000000;
begin
while num < limit loop
num := num + incr;
end loop;
end;
/
PL/SQL procedure successfully completed.
Elapsed: 00:00:05.81
ex:3
declare
num pls_integer := 0;
incr pls_integer := 1;
limit pls_integer := 100000000;
begin
while num < limit loop
num := num + incr;
end loop;
end;
/
Another difference between pls_integer and binary_integer is that when calculations involving a pls_integer overflow the PL/SQL engine will raise a run time exception. But, calculations involving a binary_integer will not raise an exception even if there is an overflow.

oracle stored procedures encryption key

How to update stored procedures encryption key in oracle 11g.
(val IN varchar) RETURN varchar AS
outstr varchar(10);
descr varchar(255);
BEGIN
-- Encryption Key For Encryption
secret_code := '123456788765432112345678';
--create instance of OLE object on an instance of SQL Server;
success = 0
EXEC rc = sp_OACreate 'CAPICOM.EncryptedData', object OUT
if rc <> 0
begin
exec sp_oageterrorinfo object, src out, descr out end
method_call := 'SetSecret("' + Secret_code + '")'
RETURN (outstr);
END;
I am not sure what are you looking for.
Check this
and also you may review this too
Stored procedures can be WRAPPED which is a form of encryption. But you can't update the key as it is hard-coded into the wrapping algorithm.
This might make you think they are susceptible to be cracked. They are and unwrappers are available.

Resources