如何解密已由des.exe加密的C#文件? [英] How can I decrypt a file in C# which has been encrypted by des.exe?

查看:100
本文介绍了如何解密已由des.exe加密的C#文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个文件,已通过 des.exe 加密



可以使用以下命令对文件进行加密和解密:

  des -E -k foo sample.txt sample.txt.enc 
des -D -k foo sample.txt.enc sample.txt.dec

我尝试使用以下方法解密:

  public byte [] Decrypt(FileInfo file,string key)
{
byte [] keyAsBytes = LibDesPasswordConvertor.PasswordToKey(key);
byte [] initializeVector = keyAsBytes;

var cryptoProvider =新的DESCryptoServiceProvider();
cryptoProvider.Mode = CipherMode.CBC;
cryptoProvider.Padding = PaddingMode.None;

使用(FileStream fs = file.OpenRead())
使用(var memStream =新的MemoryStream())
使用(var解密器= cryptoProvider.CreateDecryptor(keyAsBytes,initializeVector) )
使用(var cryptoStream = new CryptoStream(memStream,解密器,CryptoStreamMode.Write))
{
fs.CopyTo(cryptoStream);
fs.Flush();
cryptoStream.FlushFinalBlock();

返回memStream.ToArray();
}
}

公共静态类LibDesPasswordConvertor
{
公共静态字节[] PasswordToKey(字符串密码)
{
如果(string.IsNullOrWhiteSpace(password))
{
throw new ArgumentException( password);
}

var key = new byte [8];

for(int i = 0; i {
var c =(int)password [i];
if(((i%16)< 8)
{
key [i%8] ^ =(byte)(c<< 1);
}
else
{
//反转位,例如11010010-> 01001011
c =(((c<< 4)& 0xf0)|(((c>> 4)& 0x0f)));
c =(((c< 2)& 0xcc)|(((c>> 2)& 0x33)));
c =(((c< 1)& 0xaa)|(((c> 1)& 0x55)));
key [7-(i%8)] ^ =(byte)c;
}
}

AddOddParity(key);

var target = new byte [8];
var passwordBuffer = Encoding.ASCII.GetBytes(password).Concat(new byte [8])。Take(password.Length +(8-(password.Length%8))%8).ToArray();

using(var des = DES.Create())
using(var cryptoor = des.CreateEncryptor(key,key))
{
for(int x = 0; x< passwordBuffer.Length / 8; ++ x)
{
cryptoor.TransformBlock(passwordBuffer,8 * x,8,target,0);
}
}

AddOddParity(target);

的回报目标;
}


私有静态无效AddOddParity(byte [] buffer)
{
for(int i = 0; i {
buffer [i] = _oddParityTable [buffer [i]];
}
}

私有静态字节[] _oddParityTable = {
1,1,2,2,4,4,7,7,8,8, 11,11,13,13,14,14,
16,16,19,19,21,21,22,22,25,25,26,26,28,28,31,31,
32、32、35、35、37、37、38、38、41、41、42、42、44、44、47、47,$ b 49、49、50、50、52、52, 55、55、56、56、59、59、61、61、62、62,
64、64、67、67、69、69、70、70、73、73、74、74、76, 76,79,79,
81,81,82,82,84,84,87,87,88,88,91,91,93,93,94,94,
97,97, 98,98,100,100,103,103,104,104,107,107,109,109,110,110,
112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,
128,128,131,131,133,133,134,134,137,137,138,138,140,​​140,​​143,143,
145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,
161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,
176,176,179,179,181,181,182,182,185,185,186,186,188,18 8191191,
193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,
208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,
224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,
241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254};
}

但是当我执行时:

  const字符串KEY = foo; 
var utf8Bytes = Decrypt(new FileInfo(@ PATH-TO\sample.txt.enc),KEY);

我得到:

 1D  z+ aSample.y   0F 01

原始文本:

 这是一个示例。 

加密:

 ñGYjlûg†¼64©‹Bø
é¯Kœ|


解决方案

令我惊讶的是,您已经正确导出了密钥。那就是问题的根源,所以荣誉已经解决了这一部分。当您看到解密中存在明文的一部分时,密钥正确就变得很清楚-如果密钥错误就不会出现。






仔细查看源代码和一些文档,我发现可能是全零的IV,而不是重用密钥字节(从密码学角度来看,这都是非常错误的。)



此外,与SSLeay一样,ECB和CBC模式使用PKCS#7兼容填充,而不是不使用填充。






最后,如果关闭流,将自动调用 FlushFinalBlock 通过退出try-with-resources。因此,如果事后获得数组,则应该获得正确的值-当然,在正确展开填充之后。如果调用 Flush ,则将已经调用 FlushFinalBlock ,并且两次调用都会使事情变得一团糟。 / p>

只需删除刷新调用并在 CryptoStream 关闭后检索数组






DES和密钥派生( des_string_to_key des_string_to_2keys )是完全不安全的。使用全零的IV是错误的。



如果将其用作传输模式,则将使用填充预言符,并且甚至不需要解密攻击者。密文不受完整性保护。



如果您使用上述例程对任何内容进行保密或保护,那么您就在自欺欺人。这是80年代的技术,我认为当时真正的密码学家也不会发现它是安全的。



基本上,如果攻击者的年龄超过8岁,则您处于麻烦。


I have a file which has been encrypted by des.exe.

A file can be encrypted and decrypted using the following commands:

des -E -k "foo" sample.txt sample.txt.enc
des -D -k "foo" sample.txt.enc sample.txt.dec

I have attempted to decrypt using the following:

public byte[] Decrypt(FileInfo file, string key)
{
  byte[] keyAsBytes = LibDesPasswordConvertor.PasswordToKey(key);
  byte[] initializationVector = keyAsBytes;

  var cryptoProvider = new DESCryptoServiceProvider();  
  cryptoProvider.Mode = CipherMode.CBC;
  cryptoProvider.Padding = PaddingMode.None;  

  using (FileStream fs = file.OpenRead())
  using (var memStream = new MemoryStream())
  using (var decryptor = cryptoProvider.CreateDecryptor(keyAsBytes, initializationVector))
  using (var cryptoStream = new CryptoStream(memStream, decryptor, CryptoStreamMode.Write))
  {
    fs.CopyTo(cryptoStream);
    fs.Flush();
    cryptoStream.FlushFinalBlock();

    return memStream.ToArray();
  }
}

public static class LibDesPasswordConvertor
{
  public static byte[] PasswordToKey(string password)
  {
    if (string.IsNullOrWhiteSpace(password)) 
    { 
      throw new ArgumentException("password"); 
    }

    var key = new byte[8];

    for (int i = 0; i < password.Length; i++)
    {
      var c = (int)password[i];
      if ((i % 16) < 8)
      {
        key[i % 8] ^= (byte)(c << 1);
      }
      else
      {
        // reverse bits e.g. 11010010 -> 01001011
        c = (((c << 4) & 0xf0) | ((c >> 4) & 0x0f));
        c = (((c << 2) & 0xcc) | ((c >> 2) & 0x33));
        c = (((c << 1) & 0xaa) | ((c >> 1) & 0x55));
        key[7 - (i % 8)] ^= (byte)c;
      }
    }

    AddOddParity(key);

    var target = new byte[8];
    var passwordBuffer = Encoding.ASCII.GetBytes(password).Concat(new byte[8]).Take(password.Length + (8 - (password.Length % 8)) % 8).ToArray();

    using(var des = DES.Create())
    using(var encryptor = des.CreateEncryptor(key, key))
    {
      for (int x = 0; x < passwordBuffer.Length / 8; ++x)
      {
        encryptor.TransformBlock(passwordBuffer, 8 * x, 8, target, 0);
      }
    }

    AddOddParity(target);

    return target;
  }


  private static void AddOddParity(byte[] buffer)
  {
    for (int i = 0; i < buffer.Length; ++i)
    {
      buffer[i] = _oddParityTable[buffer[i]];
    }
  }

  private static byte[] _oddParityTable = {
          1,  1,  2,  2,  4,  4,  7,  7,  8,  8, 11, 11, 13, 13, 14, 14,
         16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
         32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
         49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
         64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
         81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
         97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110,
        112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,
        128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143,
        145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,
        161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,
        176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191,
        193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,
        208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,
        224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,
        241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254};
}

But when I execute:

const string KEY = "foo";  
var utf8Bytes = Decrypt(new FileInfo(@"PATH-TO\sample.txt.enc"), KEY);

I get:

�1D���z+�a Sample.y���0F�01

Original text:

This is a Sample.

Encrypted:

ñGYjl¦ûg†¼64©‹Bø
é¯Kœ|

解决方案

To my surprise you've already derived the key correctly. That was the meat of the problem, so Kudos for solving that part already. That the key is correct becomes clear when you see that part of the plaintext is present in the decryption - it wouldn't if the key was wrong.


Looking into the source and some docs from times past, I found a likely IV of all zeros instead of reusing the key bytes (both are very wrong, in cryptographic terms).

Furthermore, as always for SSLeay, the ECB and CBC modes use PKCS#7 compatible padding, rather than no padding.


Finally, FlushFinalBlock will be automatically called if you close the stream, e.g. by exiting the try-with-resources. So if you get the array afterwards then you should get the right values - after you unpad correctly, of course. If you call Flush then FlushFinalBlock will already be called, and calling it twice will make a mess out of things.

Simply removing the flush calls and retrieving the array after the CryptoStream is closed is the way to go.


Both DES and the key derivation (des_string_to_key and des_string_to_2keys) that Young copied from MIT are completely insecure. Using an all zero IV is wrong.

If you use this as transport mode than padding oracles will apply, and decryption is not even necessary for an attacker. The ciphertext is not integrity protected.

If you use the above routines to keep anything confidential or secure you're fooling yourself. This is 80s technology, and I think that real cryptographers wouldn't find it secure back then either.

Basically if your attacker is over 8 years old, you're in trouble.

这篇关于如何解密已由des.exe加密的C#文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆