2

3DES を使用してデータを暗号化および復号化する、PL/SQL で記述されたレガシー アプリケーションがあります。次に、Ruby アプリから同様の暗号化を実行する必要があります。最終的に、結果のハッシュは、既存のアルゴリズムを使用して同じ PL/SQL アプリケーションで復号化する必要があります。

問題は、PL/SQL と Ruby で異なる暗号化結果を取得していることです。その理由はわかりません。

まず、PL/SQL 暗号化の仕組みは次のとおりです。

DBMS_OBFUSCATION_TOOLKIT に関する Oracle のドキュメントから http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_obtool.htm

「Oracle の 3DES の実装は、外部暗号ブロック連鎖 (CBC) モードで、2 キーまたは 3 キーの実装をサポートしています。」

関数シグネチャ:

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);

「= 0 (デフォルト) の場合、TwoKeyMode が使用されます。= 1 の場合、ThreeKeyMode が使用されます。」というパラメーターについて注意してください。これは、Ruby バージョンの暗号を選択するのに役立ちました。

アプリケーションがその呼び出しを行う方法は次のとおりです。

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;

次に、Ruby で試しているのは次のとおりです。

OpenSSL::Cipher ドキュメント: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/Cipher.html

私に暗号名を与えるOpenSSLドキュメント: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

コードに示されているように、Ruby バージョンは異なるハッシュ値を計算します。なんで?それらを一貫させるために何を変更する必要がありますか?

よくわからない点:

  • des-ede-cbc が実際に Oracle と同じであるかどうか。
  • utl_raw.cast_to_raw と unpack("H*") が暗号化されたバイナリ データに対して同じことを行うかどうか。
  • 正確に cipher.final が追加するものと、そのデータを PL/SQL に追加する同等の方法があるかどうか。

: DES は安全ではなく、AES が取って代わったことを認識しています。私のユースケースでは、これらのハッシュが解読不能である必要はありません。重要な要件は、PL/SQL アプリが Ruby アプリによって生成されたハッシュを復号化できるように、ハッシュの一貫性を保つことです。

4

2 に答える 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 のバージョンは何らかの理由で切り詰められているに違いありません。

編集:いいえ、それは paddingです。暗号でパディングを 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"]
...

ここで、入力文字列の長さが異なる 2 つのアルゴリズムを比較する必要があります。ここでパディング方法のドキュメントを見てください: http://www.ruby-doc.org/stdlib-2.0.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html

于 2013-10-31T23:40:03.047 に答える
0

1 つの重要な違いを除いて、同じ問題がありました。データベース プロシージャは、パスワードを暗号化するときに初期化ベクトル (IV) を指定しませんでした。ruby で IV を省略しても、Oracle プロシージャ コールで省略した場合と同じ結果にはならなかったため、どちらも異なる「デフォルト」の IV を使用しているように見えました。

デフォルトの Oracle IV は「0123456789abcdef」であり、16 進数でデコードされたものです

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
于 2016-04-26T08:32:44.253 に答える