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

问题描述 投票:0回答:1

我需要在 c# 中复制由遗留存储过程(我无法修改)生成的相同输出,该存储过程在内部使用 DBMS_OBFUSCATION_TOOLKIT.DESEncrypt 来加密 ASCII 密码(我确信只有 ascii 字符)。

仅当输入字符串长度不超过 8 个字节时,我的 C# 代码才能获得与 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;

上面的代码打印了加密密钥字节、输入字节以及生成的加密字节的十六进制转储,如 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"));
  }

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

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

我尝试了 des.Mode 和 des.Padding 的各种组合,但我只会让事情变得更糟:至少使用上述设置,只要输入字符串长达 8 个字节,我就会得到相同的 oracle 结果,其他尝试较短的字符串也会失败。

有谁知道 Oracle 正在做什么来获取该字符串(我不是加密专家)?

谢谢你

c# oracle plsql des
1个回答
0
投票

如果使用 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
Assert.That(ToHex(encrypted), Is.EqualTo("F2E238B83939CBC1C33331A198463076"));
© www.soinside.com 2019 - 2024. All rights reserved.