Reputation: 1037
So I have this stored procedure in Microsof SQL Server that takes 2 parameters (password and salt) and produces a base64binary. i would like to transfer this logic in Oracle
...
set @source = hashbytes('sha2_256',@password + @Salt)
set @encrypted=( select cast(N'' as xml).value('xs:base64Binary(sql:variable("@source"))', 'varchar(max)'))
...
SAMPLE DATA:
@password=1234567890123456
and @salt=TESTTEST
@source will be 0xC1DB209FD3B6873B0F35C2FB103CCC5E9C585C26F79048D575318AA70E17F07F
and @encrypted will be wdsgn9O2hzsPNcL7EDzMXpxYXCb3kEjVdTGKpw4X8H8=
Trying to implement this i saw hash2 in oracle is a bit complicated so i thought ill try and at least do the base64binary part.
I tried this (and a few others) which i found in other questions here in SO
function to_base64(t in varchar2) return varchar2 is
begin
return utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(t)));
end to_base64;
but passing the @source value i get from the first step in MS SQL, I get different encoding string..
Is there something similar in Oracle? How should I do it?
Upvotes: 2
Views: 399
Reputation: 191435
You can use dbms_crypto.hash()
to hash the password+salt value; you need to convert that to raw
first, and the result is also raw
.
Then convert that raw
hashed value to base64, which is still raw
; and then finally convert that to varchar2
.
declare
l_password varchar2(30) := '1234567890123456';
l_salt varchar2(30) := 'TESTTEST';
l_raw raw(256);
l_hash raw(256);
l_base64_raw raw(256);
l_base64 varchar2(256);
begin
l_raw := utl_i18n.string_to_raw(data => l_password || l_salt, dst_charset => 'AL32UTF8');
l_hash := dbms_crypto.hash(src => l_raw, typ => dbms_crypto.hash_sh256);
dbms_output.put_line(l_hash);
l_base64_raw := utl_encode.base64_encode(l_hash);
dbms_output.put_line(l_base64_raw);
l_base64 := utl_raw.cast_to_varchar2(l_base64_raw);
dbms_output.put_line(l_base64);
end;
/
C1DB209FD3B6873B0F35C2FB103CCC5E9C585C26F79048D575318AA70E17F07F
776473676E394F32687A73504E634C3745447A4D58707859584362336B456A566454474B707734583848383D
wdsgn9O2hzsPNcL7EDzMXpxYXCb3kEjVdTGKpw4X8H8=
PL/SQL procedure successfully completed.
Or as a function, simplified slightly:
create or replace function hash_base64 (p_password varchar2, p_salt varchar2)
return varchar2
is
l_raw raw(256);
l_hash raw(256);
l_base64 varchar2(256);
begin
l_raw := utl_i18n.string_to_raw(data => p_password || p_salt, dst_charset => 'AL32UTF8');
l_hash := dbms_crypto.hash(src => l_raw, typ => dbms_crypto.hash_sh256);
l_base64 := utl_raw.cast_to_varchar2(r => utl_encode.base64_encode(l_hash));
return l_base64;
end;
/
select hash_base64 ('1234567890123456', 'TESTTEST') from dual;
HASH_BASE64('1234567890123456','TESTTEST')
--------------------------------------------------
wdsgn9O2hzsPNcL7EDzMXpxYXCb3kEjVdTGKpw4X8H8=
I think the problem with what you were doing was that you were passing in the source
value as a string, and then casting that string to raw
; i.e. you were passing the string value 'C1DB2...'
and casting that to raw
, rather than passing that raw
value.
So you'd effectively do something like:
declare
l_base64 varchar2(256);
begin
l_base64 := utl_raw.cast_to_varchar2(
utl_encode.base64_encode(
utl_raw.cast_to_raw('C1DB209FD3B6873B0F35C2FB103CCC5E9C585C26F79048D575318AA70E17F07F')));
dbms_output.put_line(l_base64);
end;
/
which gets
QzFEQjIwOUZEM0I2ODczQjBGMzVDMkZCMTAzQ0NDNUU5QzU4NUMyNkY3OTA0OEQ1NzUzMThBQTcwRTE3RjA3Rg==
or maybe you included the 0x
prefix, which gets:
MHhDMURCMjA5RkQzQjY4NzNCMEYzNUMyRkIxMDNDQ0M1RTlDNTg1QzI2Rjc5MDQ4RDU3NTMxOEFBNzBFMTdGMDdG
Rather than casting that string to raw
, you can just pass it as a raw
literal:
declare
l_base64 varchar2(256);
begin
l_base64 := utl_raw.cast_to_varchar2(
utl_encode.base64_encode('C1DB209FD3B6873B0F35C2FB103CCC5E9C585C26F79048D575318AA70E17F07F'));
dbms_output.put_line(l_base64);
end;
/
wdsgn9O2hzsPNcL7EDzMXpxYXCb3kEjVdTGKpw4X8H8=
Upvotes: 3