我有一个用 PL/SQL 编写的遗留应用程序,它使用 3DES 加密和解密数据。现在我需要从 ruby 应用程序执行类似的加密。最终,生成的哈希将需要由同一个 PL/SQL 应用程序使用其现有算法进行解密。
问题是我在 PL/SQL 和 Ruby 中获得了不同的加密结果,我不知道为什么。
首先是 PL/SQL 加密的工作原理:
来自 Oracle 关于 DBMS_OBFUSCATION_TOOLKIT 的文档 http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_obtool.htm
“Oracle 的 3DES 实现支持 2 密钥或 3 密钥实现,采用外部密码块链接 (CBC) 模式。”
函数签名:
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 CBC 模式下的两键三重 DES EDE”
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 应用程序生成的哈希值。