2015-04-17 75 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你說得對。我讀錯了你的答案。不過,說例外與其他詞語意味着什麼幾乎沒有資格作爲答案。 –

相關問題