DES3 encryption: ruby ​​openssl :: cipher vs. oracle dbms_obfuscation_toolkit

I have an outdated application written in PL / SQL that encrypts and decrypts data using 3DES. Now I need to perform similar encryption from a ruby ​​application. Ultimately, the resulting hash must be decrypted by the same PL / SQL application using the existing algorithm.

The problem is that I get different encrypted results in PL / SQL and Ruby, and I don't know why.

First of all, here's how PL / SQL encryption works:

From Oracle docs about DBMS_OBFUSCATION_TOOLKIT http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_obtool.htm

"The Oracle 3DES implementation supports either a two-key or 3-key implementation in External Encryption (CBC) mode."

Functional Signature:

DBMS_OBFUSCATION_TOOLKIT.DES3Encrypt(
input_string      IN     VARCHAR2,
key_string        IN     VARCHAR2,
encrypted_string  OUT    VARCHAR2,
which             IN     PLS_INTEGER  DEFAULT TwoKeyMode
iv_string         IN     VARCHAR2     DEFAULT NULL);

Note the parameter, which: "If = 0, (default), then TwoKeyMode is used. If = 1, then ThreeKeyMode is used." This helped me choose a cipher in the ruby ​​version.

Here's how the application does it:

set serveroutput on;
declare 
        v_encrypted varchar2(100);
begin  
  dbms_obfuscation_toolkit.des3encrypt(
    input_string => 'abcdefgh',       -- data to encrypt
    key_string => '16_byte_string_k', -- 16 byte = 128 bit key needed by DES3Encrypt
    encrypted_string => v_encrypted,
    iv_string => 'xxxxxxxx');         -- initialization vector
    dbms_output.put_line( lower(utl_raw.cast_to_raw(v_encrypted)) );
    -- prints 23ff779e88e2dbe1
end;

Secondly, here is what I'm trying in Ruby:

OpenSSL :: Cipher docs: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/Cipher.html

OpenSSL docs to give me the name of the cipher: From http://www.openssl.org/docs/apps/enc.html "des-ede-cbc Two key triple DES EDE in CBC mode"

require 'openssl'

cipher = OpenSSL::Cipher.new('des-ede-cbc')
cipher.encrypt
input = 'abcdefgh'
cipher.key = '16_byte_string_k'
cipher.iv = 'xxxxxxxx'

# i noticed that cipher.update returns same length hash as PL/SQL
# if called without cipher.final, but you are not supposed to do that
#encrypted = cipher.update(input)
encrypted = cipher.update(input) + cipher.final

hex_representation = encrypted.unpack("H*")

puts hex_representation
# prints a5cfc96485d7203eb929c28ceb9fcd53

As shown in the code, the ruby ​​version computes a different hash value. What for? What needs to be changed to make them consistent?

Points I'm Not Sure About:

  • Does des-ede-cbc really match what Oracle does.
  • utl_raw.cast_to_raw unpack ( "H *" ) .
  • encipher.final - PL/SQL.

. , DES AES . , . , PL/SQL , ruby.

+2
2

!

['des-cbc', 'des', 'des-cfb', 'des-ofb', 'des-ecb',
 'des-ede-cbc', 'des-ede', 'des-ede-cfb', 'des-ede-ofb', 
 'des-ede3-cbc', 'des-ede3', 'des3', 'des-ede3-cfb', 
 'des-ede3-ofb', 'desx'].each do |flavour|
  begin
    c = OpenSSL::Cipher.new flavour
    c.encrypt
    c.key = '16_byte_string_k'
    c.iv = 'xxxxxxxx'
    str = 'abcdefgh'
    enc = c.update(str) + c.final
    puts "#{flavour} gives us #{enc.unpack('H*')}"
  rescue => e
    puts "#{flavour} didn't work because #{e.message}"
  end
end

:

des-cbc gives us ["a5cfc96485d7203eb929c28ceb9fcd53"]
des gives us ["a5cfc96485d7203eb929c28ceb9fcd53"]
des-cfb gives us ["d898369e91589ae8"]
des-ofb gives us ["d898369e91589ae8"]
des-ecb gives us ["de8579b342a528b6143594946045d91a"]
des-ede-cbc gives us ["23ff779e88e2dbe1c009dc3105d8ff88"]
des-ede gives us ["0e589e3d85ac83efbb271a2e4a77cf4e"]
des-ede-cfb gives us ["1618988004b6a948"]
des-ede-ofb gives us ["1618988004b6a948"]
des-ede3-cbc didn't work because key length too short
des-ede3 didn't work because key length too short
des3 didn't work because key length too short
des-ede3-cfb didn't work because key length too short
des-ede3-ofb didn't work because key length too short
desx didn't work because key length too short

des-ede-cbc - , . , ? , , PL/SQL- - - , .

: , . 0 , , PL/SQL-,

['des-cbc', 'des', 'des-cfb', 'des-ofb', 'des-ecb',
 'des-ede-cbc', 'des-ede', 'des-ede-cfb', 'des-ede-ofb', 
 'des-ede3-cbc', 'des-ede3', 'des3', 'des-ede3-cfb', 
 'des-ede3-ofb', 'desx'].each do |flavour|
  begin
    c = OpenSSL::Cipher.new flavour
    c.encrypt
    c.key = '16_byte_string_k'
    c.iv = 'xxxxxxxx'
    c.padding = 0 # This is the important part!
    str = 'abcdefgh'
    enc = c.update(str) + c.final
    puts "#{flavour} gives us #{enc.unpack('H*')}"
  rescue => e
    puts "#{flavour} didn't work because #{e.message}"
  end
end

...
des-ede-cbc gives us ["23ff779e88e2dbe1"]
...

. : http://www.ruby-doc.org/stdlib-2.0.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html

+2

: (IV). IV , Oracle, , , "" .

Oracle IV - "0123456789abcdef", , : https://community.oracle.com/thread/1528090

Ruby :

['des-cbc', 'des', 'des-cfb', 'des-ofb', 'des-ecb',
 'des-ede-cbc', 'des-ede', 'des-ede-cfb', 'des-ede-ofb', 
 'des-ede3-cbc', 'des-ede3', 'des3', 'des-ede3-cfb', 
 'des-ede3-ofb', 'desx'].each do |flavour|
  begin
    c = OpenSSL::Cipher.new flavour
    c.encrypt
    c.key = '16_byte_string_k'
    c.iv = ['0123456789abcdef'].pack('H*') # Required if no IV is set in Oracle!
    c.padding = 0
    str = 'abcdefgh'
    enc = c.update(str) + c.final
    puts "#{flavour} gives us #{enc.unpack('H*')}"
  rescue => e
    puts "#{flavour} didn't work because #{e.message}"
  end
end
0

Source: https://habr.com/ru/post/1615764/


All Articles