2015-04-17 38 views
0

有相当多的类似的问题对SO有关这一点,但“无”符合我的问题。数据解密的C#长无效

我一个创建填充有加密的随机字节的文件。然后在这个文件的特定位置我写几个加密字节。当我尝试读取该字节段时,我得到“解密的数据长度无效”。

这是加密和解密方法

private static readonly byte[] SALT = new byte[] { 0x26, 0xdc, 0xff, 0x00, 0xad, 0xed, 0x7a, 0xee, 0xc5, 0xfe, 0x07, 0xaf, 0x4d, 0x08, 0x22, 0x3c }; 
     //TODO: The SALT needs to be derived and unique for each user! 

     internal byte[] Encrypt(byte[] plain) 
     { 
      string password = Properties.Settings.Default.PasswordOne; 
      MemoryStream memoryStream; 
      CryptoStream cryptoStream; 
      Rijndael rijndael = Rijndael.Create(); 
      Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, SALT); 
      rijndael.Key = pdb.GetBytes(32); 
      rijndael.IV = pdb.GetBytes(16); 
      memoryStream = new MemoryStream(); 
      cryptoStream = new CryptoStream(memoryStream, rijndael.CreateEncryptor(), CryptoStreamMode.Write); 
      cryptoStream.Write(plain, 0, plain.Length); 
      cryptoStream.Close(); 
      return memoryStream.ToArray(); 
     } 

     internal byte[] Decrypt(byte[] cipher) 
     { 
      string password = Properties.Settings.Default.PasswordOne; 
      MemoryStream memoryStream; 
      CryptoStream cryptoStream; 
      Rijndael rijndael = Rijndael.Create(); 
      Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, SALT); 
      rijndael.Key = pdb.GetBytes(32); 
      rijndael.IV = pdb.GetBytes(16); 
      memoryStream = new MemoryStream(); 
      cryptoStream = new CryptoStream(memoryStream, rijndael.CreateDecryptor(), CryptoStreamMode.Write); 
      cryptoStream.Write(cipher, 0, cipher.Length); 
      cryptoStream.Close(); 
      return memoryStream.ToArray(); 
     } 

(在SO上某一点发现)我用这个

private void InsertDEFT2NameLength(FileSystemEncryption fse, string Deft2FileName, FileStream fs, StreamWriter sw) 
     { 

      string deft2NameLength = "0";          // init the length 
      if (DrivesLog != null) DrivesLog("Converting DEFT2 Name to Bytes"); 
      byte[] bdeft2Name = GetBytes(Deft2FileName);      // convert filename to bytes 
      if (DrivesLog != null) DrivesLog("Encrypting DEFT2 Name"); 
      byte[] ebdeft2Name = fse.Encrypt(bdeft2Name);      // Encrypt 
      if (DrivesLog != null) DrivesLog("Getting Length of Encrypted DEFT2 Name"); 
      long ebdeft2NameLength = ebdeft2Name.LongLength;     // Get Length of the Encrypted Bytes as a long 
      if (DrivesLog != null) DrivesLog("Converting DEFT2 Name Length to String"); 
      string sebdeft2NameLength = ebdeft2NameLength.ToString() + "!";  // Convert Length to string Add Exclamation so we know when we have read the full length 
      if (DrivesLog != null) DrivesLog("Converting DEFT2 Name Length to Bytes"); 
      byte[] bsebdeft2NameLength = GetBytes(sebdeft2NameLength);   // Convert length string to bytes 
      if (DrivesLog != null) DrivesLog("Encrypting DEFT2 Name Length"); 
      byte[] ebsebdeft2NameLength = fse.Encrypt(bsebdeft2NameLength);  // Encrypt 
      if (DrivesLog != null) DrivesLog("Converting Encrypted DEFT2 Name Length to String"); 
      deft2NameLength = GetString(ebsebdeft2NameLength);     // Convert to string 

      if (DrivesLog != null) DrivesLog("Seeking to Correct Location"); 
      long startPos = GenerateDEFT2LengthStartPosition(); 
      fs.Seek(startPos, SeekOrigin.Current); // Seek to correct location 
      if (DrivesLog != null) DrivesLog("New Position " + startPos.ToString("N0")); 
      if (DrivesLog != null) DrivesLog("Writing Encrypted Name Length to New Position"); 
      sw.Write(deft2NameLength);           // Write the Encrypted length 
      fs.Flush();               // Flush the buffer immediately 
     } 

我试图重新读取保存的第一个文件中的新数据在该位置处使用此方法的加密数据:

private long ReadDEFT2Len(string DEFT, long lenPos, FileSystemEncryption fse) 
     { 
      if (DrivesLog != null) DrivesLog("Reading DEFT2 Name Length"); 
      StringBuilder sb = new StringBuilder(); 

      FileStream fs = null; 
      StreamReader sr = null; 

      try 
      { 
       fs = new FileStream(DEFT, FileMode.Open, FileAccess.Read, FileShare.Read); 
       sr = new StreamReader(fs, Encoding.Unicode); 

       char[] C = new char[101]; 
       fs.Seek(lenPos, SeekOrigin.Begin); 
       sr.Read(C, 0, 100); 

       string sC = new string(C); 
       byte[] bsC = GetBytes(sC); 

       byte[] dRes = fse.Decrypt(bsC); // This is where the Exception is thrown. 
       foreach(char ic in GetString(dRes)) 
       { 
        if (ic == '!') break; 
        sb.Append(ic.ToString()); 
       } 

       sr.Close(); 
       fs.Close(); 

       if (DrivesLog != null) DrivesLog("DEFT2 Name Length = " + sb.ToString()); 
       return long.Parse(sb.ToString()); 
      } 
      catch (Exception ex) 
      { 
       if (DrivesLog != null) DrivesLog("ERROR Reading DEFT2 Name Length " + ex.Message); 
       if (sr != null) sr.Close(); 
       if (fs != null) fs.Close(); 
       return -1; 
      } 

     } 

我已保存和使用Unicode加载编码,这不是问题..关于为什么抛出这个异常以及如何解决它的任何想法?

+0

您是否已经完成了一些基本的调试,比如以独立的方式测试所有方法?你是否检查过一个完整的加密解密周期,没有任何随机文件写入等?你有没有试过为代码的其他部分使用一些静态数据? –

回答

1

的Rijndael的密码仅适用于特定的块大小(16,24,或32字节)。你在这里得到一个例外,因为你解密的数据长度不是块大小的确切倍数。

+0

它解决了长度问题 - 现在我有填充问题:D –

+0

@ArtjomB Rijndael只适用于填充。如果你尝试使用NoPadding,那么在加密阶段你会得到一个异常,除非你自己将数据填充到块大小的确切倍数。 – RogerN

+0

@RogerN你说得对。我读错了你的答案。不过,说例外与其他词语意味着什么几乎没有资格作为答案。 –

相关问题