如何使用System.Security.Cryptography.DES在C#中复制Oracle DBMS_OBFUSCATION_TOOLKIT.DESEncrypt()?

wfauudbj  于 2023-08-03  发布在  Oracle
关注(0)|答案(1)|浏览(107)

我需要在C#中复制由遗留存储过程(我无法修改)生成的相同输出,该存储过程在内部使用DBMS_OBFUSCATION_TOOLKIT.DESEncrypt加密ASCII密码(我确信只有ASCII字符)。
我的C#代码只在输入字符串长度不超过8字节时才得到与oracle相同的结果。
我将问题缩小到oracle的DESEncrypt不会产生与System.Security.Cryptography.DES相同的输出,至少就我使用它的方式而言。
我想出了这个Oracle示例代码来说明预期的行为:

declare
   key raw(8);
   src raw(16);
   encrypted raw(16);
begin
   key := UTL_RAW.cast_to_raw('MYCRYKEY');   
   src := utl_raw.cast_to_raw('123456789~~~~~~~');

   encrypted := DBMS_OBFUSCATION_TOOLKIT.DESEncrypt(
      input => src, 
      key => UTL_RAW.cast_to_raw('MYCRYKEY'));
  
      
   dbms_output.put_line('KEY       = ' || key); 
   dbms_output.put_line('SRC       = ' || src); 
   dbms_output.put_line('ENCRYPTED = ' || encrypted); 

end;

字符串
上面的代码打印了加密密钥字节、输入字节和结果加密字节的HEX转储,如oracle所见:

KEY       = 4D594352594B4559
SRC       = 3132333435363738397E7E7E7E7E7E7E
ENCRYPTED = F2E238B83939CBC1C33331A198463076


因此,我试图通过在NUnit测试用例中检查这些值来复制相同的结果:

static string ToHex(byte[] bytes)
  {
    return BitConverter.ToString(bytes).Replace("-", "");
  }
  
  [Test]
  public void DESTest()
  {
    byte[] key = Encoding.ASCII.GetBytes("MYCRYKEY");
    byte[] src = Encoding.ASCII.GetBytes("123456789~~~~~~~");

    using DES des = DES.Create();

    des.Key = key;
    des.Mode = CipherMode.ECB;
    des.Padding = PaddingMode.None;
    using ICryptoTransform crypt = des.CreateEncryptor();

    byte[] encrypted = crypt.TransformFinalBlock(src, 0, src.Length);

    // these are OK
    Assert.That(ToHex(key), Is.EqualTo("4D594352594B4559"));
    Assert.That(ToHex(src), Is.EqualTo("3132333435363738397E7E7E7E7E7E7E"));

    // this one fails
    Assert.That(ToHex(encrypted), Is.EqualTo("F2E238B83939CBC1C33331A198463076"));
  }


输入字节是相同的,但输出在八个字节之后不同:这是最后一个Assert(失败的Assert)产生的消息:

String lengths are both 32. Strings differ at index 17.
Expected: "F2E238B83939CBC1C33331A198463076"
But was:  "F2E238B83939CBC1C4388144A4F16DA6"
----------------------------^


我尝试了des.Modedes.Padding的各种组合,但我只设法让事情变得更糟:至少在上面的设置中,只要输入字符串长到8字节,我就会得到相同的oracle结果,其他尝试也会失败。
有没有人知道Oracle是怎么得到这个字符串的(我不是加密Maven)?

ru9i0ody

ru9i0ody1#

如果CBC被用作模式并且零向量(8乘以0x00值)被应用为IV,则可以再现密文:

byte[] key = Encoding.ASCII.GetBytes("MYCRYKEY");
byte[] src = Encoding.ASCII.GetBytes("123456789~~~~~~~");

using DES des = DES.Create();

des.Mode = CipherMode.CBC;                                // Fix 1: Apply CBC
des.Padding = PaddingMode.None;
des.Key = key;
des.IV = new byte[8];                                     // Fix 2: Apply an zero IV
using ICryptoTransform crypt = des.CreateEncryptor();

byte[] encrypted = crypt.TransformFinalBlock(src, 0, src.Length);

// these are OK
Assert.That(ToHex(key), Is.EqualTo("4D594352594B4559"));
Assert.That(ToHex(src), Is.EqualTo("3132333435363738397E7E7E7E7E7E7E"));

// this one fails before the fix and works after the fix
Assert.That(ToHex(encrypted), Is.EqualTo("F2E238B83939CBC1C33331A198463076"));

字符串
DESENCRYPT的文档中,我找不到任何关于该模式的参考,只有相关的DES3ENCRYPT。在那里描述了CBC被用作模式(然而在这里也缺少使用哪个IV)。
可能已经知道了,但为了安全起见,应该再次提到:DES已弃用且不安全。此外,使用静态IV(如零IV是一个漏洞)。

相关问题