How to encrypt nvarchar column in oracle? - 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

Related

Oracle update BLOB column with encrypted value set NULL value when blob is more than 3000-4000 char

In a Oracle 11g database I have a table with a blob column in which I want to put encrypted datas.
I have this function in my database :
create or replace FUNCTION encryptmyBLOB(content IN BLOB, key in VARCHAR2)
RETURN BLOB AS
CRYPTED BLOB;
encryption_type PLS_INTEGER :=
SYS.DBMS_CRYPTO.ENCRYPT_AES128
+ SYS.DBMS_CRYPTO.CHAIN_CBC
+ SYS.DBMS_CRYPTO.PAD_PKCS5;
BEGIN
dbms_lob.createtemporary(CRYPTED,true);
SYS.DBMS_CRYPTO.ENCRYPT(
dst => CRYPTED,
src => content,
typ => encryption_type,
key => SYS.DBMS_CRYPTO.Hash (UTL_I18N.STRING_TO_RAW (key, 'WE8ISO8859P15'), SYS.DBMS_CRYPTO.HASH_MD5),
iv => utl_raw.cast_to_raw('/myIV'));
return CRYPTED;
end if;
END;
and my application send query with params like this :
UPDATE mytable SET myColumn=encryptmyBLOB(:SERIAL,:ENCRYPT_KEY) WHERE ...
This works well when the SERIAL param contain less than approximately 4000 bytes but when SERIAL contain more data I get a database error.
ORA-01461: can bind a LONG value only for insert into a LONG column
I don't understand what I am doing wrong. I suspect that my application Oracle driver send a LONG value in my SERIAL param instead of a BLOB value but I can't confirm it and the UPDATE is correctly done if I bypass my function.
Can anyone point me in the right direction?
Many thanks.
The error is pretty clear: You column is not a BLOB-column.
You should change the datatype to BLOB, because LONG/LONG RAW is deprecated:
https://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm#CNCPT613
If you can't change the type of the column, you could check the size of your BLOB 'content' within you function:
DECLARE
myBlob BLOB;
mySize NUMBER;
BEGIN
myBlob := utl_raw.cast_to_raw('1234567890');
mySize := dbms_lob.getlength(myBlob);
dbms_output.put_line('Size: ' || mySize);
myBlob := utl_raw.cast_to_raw('12345678901234567890');
mySize := dbms_lob.getlength(myBlob);
dbms_output.put_line('Size: ' || mySize);
END;

Oracle equivalent of stored procedure that returns an inline table?

Example in T-SQL (SQL Server - taken from here):
CREATE PROC proc_authors
#au_lname VARCHAR(40)
AS
SELECT
au_id, au_fname, au_lname, city, state
FROM authors
WHERE au_lname = #au_lname
go
Is it possible in Oracle to create a stored procedure that returns an inline table (without declaring a type - like the above)? If not, what would be the closest alternative? i.e. declare inline type, then use it. The idea is to minimize number of DB permissions that are granted.
Please include sample code as part of your answer.
Reasoning behind using stored procedure vs function - we have legacy software that can only execute stored procedures, or raw queries. It appears that only stored procedures in there have support for parameterized execution, which is what we are after.
try this with ref cursor
PROCEDURE proc_get_tada(ip_user IN VARCHAR2,
op_error_code OUT NUMBER,
op_cursor OUT SYS_REFCURSOR,) AS
BEGIN
OPEN op_cursor FOR
SELECT * FROM your_table yt where yt.user = ip_user;
EXCEPTION
WHEN OTHERS THEN
op_error_code := -1;
END proc_get_tada;
you will get collection of all data from you table you can iterate in java or calling program.
Maybe you are searching for something like this:
create table author
(
au_id number,
au_name varchar2(100)
);
insert into author (au_id, au_name) values(1, 'ME');
create or replace function getAuthor(auName varchar2)
return author%rowtype
is
retval author%rowtype;
begin
select * into retval from author where au_name=auName;
return retval;
end;
declare
auth author%rowtype;
begin
auth := getAuthor('ME');
dbms_output.put_line(auth.au_id);
end;

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.

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.

Making a sha1-hash of a row in Oracle

I'm having a problem with making a sha1-hash of a row in a select on an Oracle database. I've done it in MSSQL as follows:
SELECT *,HASHBYTES('SHA1',CAST(ID as varchar(10)+
TextEntry1+TextEntry2+CAST(Timestamp as varchar(10)) as Hash
FROM dbo.ExampleTable
WHERE ID = [foo]
However, I can't seem to find a similar function to use when working with Oracle.
As far as my googling has brought me, I'm guessing dbms_crypto.hash_sh1 has something to do with it, but I haven't been able to wrap my brain around it yet...
Any pointers would be greatly appreciated.
The package DBMS_CRYPTO is the correct package to generate hashes. It is not granted to PUBLIC by default, you will have to grant it specifically (GRANT EXECUTE ON SYS.DBMS_CRYPTO TO user1).
The result of this function is of datatype RAW. You can store it in a RAW column or convert it to VARCHAR2 using the RAWTOHEX or UTL_ENCODE.BASE64_ENCODE functions.
The HASH function is overloaded to accept three datatypes as input: RAW, CLOB and BLOB. Due to the rules of implicit conversion, if you use a VARCHAR2 as input, Oracle will try to convert it to RAW and will most likely fail since this conversion only works with hexadecimal strings.
If you use VARCHAR2 then, you need to convert the input to a binary datatype or a CLOB, for instance :
DECLARE
x RAW(20);
BEGIN
SELECT sys.dbms_crypto.hash(utl_raw.cast_to_raw(col1||col2||to_char(col3)),
sys.dbms_crypto.hash_sh1)
INTO x
FROM t;
END;
you will find additional information in the documentation of DBMS_CRYPTO.hash
The DBMS_crypto package does not support varchar2. It works with raw type so if you need a varchar2 you have to convert it. Here is a sample function showing how to do this :
declare
p_string varchar2(2000) := 'Hello world !';
lv_hash_value_md5 raw (100);
lv_hash_value_sh1 raw (100);
lv_varchar_key_md5 varchar2 (32);
lv_varchar_key_sh1 varchar2 (40);
begin
lv_hash_value_md5 :=
dbms_crypto.hash (src => utl_raw.cast_to_raw (p_string),
typ => dbms_crypto.hash_md5);
-- convert into varchar2
select lower (to_char (rawtohex (lv_hash_value_md5)))
into lv_varchar_key_md5
from dual;
lv_hash_value_sh1 :=
dbms_crypto.hash (src => utl_raw.cast_to_raw (p_string),
typ => dbms_crypto.hash_sh1);
-- convert into varchar2
select lower (to_char (rawtohex (lv_hash_value_sh1)))
into lv_varchar_key_sh1
from dual;
--
dbms_output.put_line('String to encrypt : '||p_string);
dbms_output.put_line('MD5 encryption : '||lv_varchar_key_md5);
dbms_output.put_line('SHA1 encryption : '||lv_varchar_key_sh1);
end;
Just to put it here, if someone will search for.
In Oracle 12 you can use standard_hash(<your_value>, <algorythm>) function.
With no parameter <algorythm> defined, it will generate SHA-1 hash (output datatype raw(20))
You can define this function in your favorite package, I defined in utils_pkg.
FUNCTION SHA1(STRING_TO_ENCRIPT VARCHAR2) RETURN VARCHAR2 AS
BEGIN
RETURN LOWER(TO_CHAR(RAWTOHEX(SYS.DBMS_CRYPTO.HASH(UTL_RAW.CAST_TO_RAW(STRING_TO_ENCRIPT), SYS.DBMS_CRYPTO.HASH_SH1))));
END SHA1;
Now to call it
SELECT UTILS_PKG.SHA1('My Text') AS SHA1 FROM DUAL;
The response is
SHA1
--------------------------------------------
5411d08baddc1ad09fa3329f9920814c33ea10c0
You can select a column from some table:
SELECT UTILS_PKG.SHA1(myTextColumn) FROM myTable;
Enjoy!
Oracle 19c:
select LOWER(standard_hash('1234')) from dual;
which is equivalent to
select LOWER(standard_hash('1234','SHA1')) from dual;
will return an SHA1 hash.
For alternative algorithms see: https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/STANDARD_HASH.html

Resources