2016-02-11 40 views
1

我已經得到所說的誤差試圖實現DES加密和解密(雖然我的代碼允許不同的實現)C#壞PKCS7填充

我已經做了很多的研究這一點,並發現了幾個類似的當問題,這裏關於Stack Overflow,但是他們提供的答案是確保密鑰和IV在加密和解密過程中是相同的,我似乎已經實現了這一點,所以似乎問題的根源在於其他地方。

以下是我的代碼,該異常被線#164拋出

namespace xNFCE 
{ 
    public class Crypto 
    { 

     public enum cryptype 
     { 
      DES, 
      THREEDES, 
      AES 
     }; 

     // Variables for the file input, output and the password to encrypt the file 
     string _input, _output; 
     byte[] _password; 
     cryptype _type; 

     /// <summary> 
     /// Initializes a new instance of the <see cref="xNFCE.Crypto"/> class. 
     /// </summary> 
     /// <param name="input">Input.</param> 
     /// <param name="output">Output.</param> 
     /// <param name="password">Password.</param> 
     public Crypto(string input, string output, string password, cryptype type = cryptype.AES) 
     { 
      // Set the properties for the encryption 
      _input = input; 
      _output = output; 
      _password = hash(password); 
      _type = type; 
     } 


     /// <summary> 
     /// Run the appropriate encryption function 
     /// </summary> 
     public void Encrypt() 
     { 
      switch (_type) 
      { 
       case cryptype.DES: 
        DESenc(); 
        break; 
       case cryptype.THREEDES: 
        // TODO Implement 
        throw new NotImplementedException(); 
       case cryptype.AES: 
        // TODO Implement 
        throw new NotImplementedException(); 
      } 
     } 


     /// <summary> 
     /// Run the appropriate decryption function 
     /// </summary> 
     public void Decrypt() 
     { 
      switch (_type) 
      { 
       case cryptype.DES: 
        DESdec(); 
        break; 
       case cryptype.THREEDES: 
        // TODO Implement 
        throw new NotImplementedException(); 
       case cryptype.AES: 
        // TODO Implement 
        throw new NotImplementedException(); 
      } 
     } 


     /// <summary> 
     /// Hash the password and return it as a byte array 
     /// </summary> 
     /// <param name="pwd">Pwd.</param> 
     byte[] hash(String pwd) 
     { 
      // System.Text provides .GetBytes() this converts a string to the series of bytes 
      // Convert the password string to an array of bytes 
      byte[] bytes = Encoding.ASCII.GetBytes(pwd); 
      // Create an instance of Managed SHA256 
      SHA256Managed hashman = new SHA256Managed(); 
      // Hash the array of bytes 
      byte[] hash = hashman.ComputeHash(bytes); 
      return hash; 
     } 

     /// <summary> 
     /// This function is called when the user wants to encrypt a file 
     /// </summary> 
     void DESenc() 
     { 
      // Create file streams for the input and output of the files 
      FileStream fileInput = new FileStream(_input, FileMode.Open, FileAccess.Read); 
      // Append the xNFCE extension to the output 
      FileStream fileEncrypted = new FileStream(_output + GlobalValues.fextension, FileMode.Create, FileAccess.Write); 

      // Declare an insrance of the DESCryptoServiceProvider class 
      // This represents the actual encryption and decryption technology that is used on the files 
      // Other cryptographic techniques can be used here 
      // TODO implement other encryption techniques 
      DESCryptoServiceProvider DES = new DESCryptoServiceProvider(); 

      // Each cryptographic technique takes a different syze key, DES takes a 64Bit key which is 8 Bytes (8 Characters) 
      // If we do not provide a key and IV here, they are randomly generated, meaning we cannot decrypt the file 
      // Take the first 8 bytes from the password 
      DES.Key = _password.Take(8).ToArray(); 
      DES.IV = _password.Take(8).ToArray(); 

      // Cretae an instance of the CryptoStream class by using the cryptographic prover to obtain an encrypting object 
      // and the existing output filestream as part of the constructor. 
      ICryptoTransform desencrypt = DES.CreateEncryptor(); 
      CryptoStream cryptostream = new CryptoStream(fileEncrypted, desencrypt, CryptoStreamMode.Write); 

      // Read in the input file and write to the output file while passing through the crypto stream object using the password provided 
      byte[] bytearrayinput = new byte[fileInput.Length - 1]; 
      fileInput.Read(bytearrayinput, 0, bytearrayinput.Length); 
      cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length); 
     } 


     /// <summary> 
     /// This function is called when the user wants to decrypt a file 
     /// </summary> 
     void DESdec() 
     { 
      // This function has two key differences from the encrypt function 
      // CreateDecryptor is used instead of CreateEncryptor to create the crypto stream object 
      // When the decrypted text is written to the destination file, the CryptoStream object is now the source isntead of the destination stream 
      DESCryptoServiceProvider DES = new DESCryptoServiceProvider(); 
      // Take the first 8 bytes from the password 
      DES.Key = _password.Take(8).ToArray(); 
      DES.IV = _password.Take(8).ToArray(); 

      // Create the file stream to read the encrypted file back 
      FileStream fileInput = new FileStream(_input, FileMode.Open, FileAccess.Read); 
      // Create a DES decryptor 
      ICryptoTransform desdecrypt = DES.CreateDecryptor(); 
      // Create a crypto stream set to read and do a decryption transform on incoming bytes 
      CryptoStream cryptostream = new CryptoStream(fileInput, desdecrypt, CryptoStreamMode.Read); 

      // Print the contents of the decrypted file 
      FileInfo fi = new FileInfo(_output); 
      string writename = Path.Combine(fi.DirectoryName, Path.GetFileNameWithoutExtension(_output)); 
      StreamWriter fsDecrypted = new StreamWriter(writename); 
      fsDecrypted.Write(new StreamReader(cryptostream).ReadToEnd()); 
      fsDecrypted.Flush(); 
      fsDecrypted.Close(); 
     } 

    } 
} 

注:我使用Xamarin.Android爲這一點,但我不認爲這是相關

謝謝! :)

+2

不要使用DES,它是不安全的,甚至3DES不應該在新的工作中使用,使用AES。也不要使用相同的密鑰和iv值,iv不需要保密,通常也不是,密鑰確實需要保密。這就是「在互聯網上進行大量研究,存在大量不良信息的問題,你需要知道信息源是知情的。」 – zaph

回答

2

問題是加密文件將是空的,所以你隨後嘗試解密一個空的字符串,將失敗。

該文件爲空,因爲CryptoStream從不刷新到磁盤。

這關係到你是不是處置的任何東西,你需要回去,並添加一個using() {}子句任何實現IDisposable(這樣做了CryptoStream將正確沖洗它)的事實。

作爲最低

using (CryptoStream cryptostream = new CryptoStream(fileEncrypted, desencrypt, CryptoStreamMode.Write)) 
{ 
    // Read in the input file and write to the output file while passing through the crypto stream object using the password provided 
    byte[] bytearrayinput = new byte[fileInput.Length - 1]; 
    fileInput.Read(bytearrayinput, 0, bytearrayinput.Length); 

    cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length); 
} 

會導致你的程序的行爲預期。 (但仍然在別處泄漏)。

(不要使用密鑰相同的值和iv)

+0

謝謝!這樣做可以阻止異常被拋出,儘管輸出文件似乎是輸入文件大小的兩倍,是不可讀的。懷疑這是與這個問題有關。 再次感謝! – JLangford

+0

編輯:有什麼替代方法是沒有使用鍵和iv的相同值嗎?我只希望用戶必須輸入一個密碼,我應該採取散列的不同部分? – JLangford