使用3个密码加密文件

时间:2010-09-12 19:35:35

标签: c# .net encryption

这是一个不寻常的问题。我无法使用3个密码加密文件。我试图围绕另外两个CryptoStream包装一个CryptoStream,但是当我将文件写入磁盘时,它似乎已损坏,并且无法完全删除填充。为什么会发生这种情况?

编辑:这是一些示例代码

 public static Stream Encrypt(Stream source, int delcount, params keyPair[] cryptInfo)
    {

        Stream prevStream = source;
        foreach (keyPair et in cryptInfo)
        {
            Rijndael mydale = Rijndael.Create();
            mydale.BlockSize = 256;
            mydale.KeySize = 256;
            mydale.IV = et.IV;
            mydale.Key = et.key;

            CryptoStream mystream = new CryptoStream(prevStream, mydale.CreateEncryptor(), CryptoStreamMode.Write);
            prevStream = mystream;
        }
        return prevStream;

}

这是完整的计划 Program.cs的

class Program
{
    static string opcode = "test";
    static string IDCID = "an ID";
    static string password = "A strong password";
    static void Main(string[] args)
    {
        if (Console.ReadLine() == "encrypt")
        {
            Stream thestream = File.Open(Environment.CurrentDirectory + "\\sample.txt", FileMode.Create, FileAccess.ReadWrite);

            PasswordDeriveBytes mybytes = new PasswordDeriveBytes(Encoding.Unicode.GetBytes(opcode), Encoding.ASCII.GetBytes(opcode));
            byte[] key = mybytes.GetBytes(32);
            mybytes = new PasswordDeriveBytes(Encoding.Unicode.GetBytes((IDCID.Length + password.Length + opcode.Length * 15).ToString()), Encoding.ASCII.GetBytes((IDCID.Length + password.Length + 5 + opcode.Length * 24).ToString()));
            byte[] IV = mybytes.GetBytes(32);
            keyPair mypair = new GlobalGridCore.keyPair(IV, key);
            mybytes = new PasswordDeriveBytes(Encoding.Unicode.GetBytes(password), Encoding.ASCII.GetBytes(password));
            key = mybytes.GetBytes(32);
            mybytes = new PasswordDeriveBytes(Encoding.Unicode.GetBytes((IDCID.Length + password.Length + opcode.Length * 9).ToString()), Encoding.ASCII.GetBytes((IDCID.Length + password.Length + 7 + opcode.Length * 24).ToString()));
            IV = mybytes.GetBytes(32);
            keyPair secondpair = new keyPair(IV, key);
            mybytes = new PasswordDeriveBytes(Encoding.Unicode.GetBytes(IDCID), Encoding.ASCII.GetBytes(IDCID));
            key = mybytes.GetBytes(32);
            mybytes = new PasswordDeriveBytes(Encoding.Unicode.GetBytes((IDCID.Length + password.Length + opcode.Length * 2).ToString()), Encoding.ASCII.GetBytes((IDCID.Length + password.Length + 14 + opcode.Length * 7).ToString()));
            IV = mybytes.GetBytes(32);
            keyPair thirdpair = new keyPair(IV, key);
            keyPair[] list = new keyPair[] { mypair, secondpair, thirdpair };
            thestream = gridCrypto.Encrypt(thestream, 0, list);
            BinaryWriter mywriter = new BinaryWriter(thestream);
            mywriter.Write("ehlo");
            mywriter.Write(new byte[512]);
            mywriter.Flush();
        }
        else
        {
            Stream thestream = File.Open(Environment.CurrentDirectory + "\\sample.txt", FileMode.Open, FileAccess.ReadWrite);

            PasswordDeriveBytes mybytes = new PasswordDeriveBytes(Encoding.Unicode.GetBytes(opcode), Encoding.ASCII.GetBytes(opcode));
            byte[] key = mybytes.GetBytes(32);
            mybytes = new PasswordDeriveBytes(Encoding.Unicode.GetBytes((IDCID.Length + password.Length + opcode.Length * 15).ToString()), Encoding.ASCII.GetBytes((IDCID.Length + password.Length + 5 + opcode.Length * 24).ToString()));
            byte[] IV = mybytes.GetBytes(32);
            keyPair mypair = new GlobalGridCore.keyPair(IV, key);
            mybytes = new PasswordDeriveBytes(Encoding.Unicode.GetBytes(password), Encoding.ASCII.GetBytes(password));
            key = mybytes.GetBytes(32);
            mybytes = new PasswordDeriveBytes(Encoding.Unicode.GetBytes((IDCID.Length + password.Length + opcode.Length * 9).ToString()), Encoding.ASCII.GetBytes((IDCID.Length + password.Length + 7 + opcode.Length * 24).ToString()));
            IV = mybytes.GetBytes(32);
            keyPair secondpair = new keyPair(IV, key);
            mybytes = new PasswordDeriveBytes(Encoding.Unicode.GetBytes(IDCID), Encoding.ASCII.GetBytes(IDCID));
            key = mybytes.GetBytes(32);
            mybytes = new PasswordDeriveBytes(Encoding.Unicode.GetBytes((IDCID.Length + password.Length + opcode.Length * 2).ToString()), Encoding.ASCII.GetBytes((IDCID.Length + password.Length + 14 + opcode.Length * 7).ToString()));
            IV = mybytes.GetBytes(32);
            keyPair thirdpair = new keyPair(IV, key);
            keyPair[] list = new keyPair[] { mypair, secondpair, thirdpair };
            thestream = gridCrypto.Decrypt(thestream, list);
          BinaryReader myreader = new BinaryReader(thestream);
          Console.WriteLine(myreader.ReadString());
          Console.ReadLine();
        }

    }
}

cryptDriver.cs

abstract class gridCrypto
{
    /// <summary>
    /// Decrypts the input stream to the output stream
    /// </summary>
    /// <param name="source">I</param>
    /// <param name="dest">O</param>
    /// <param name="cryptInfo">U</param>
    public static Stream Decrypt(Stream source, params keyPair[] cryptInfo)
    {
        Stream prevStream = source;
        foreach (keyPair et in cryptInfo)
        {
            Rijndael mydale = Rijndael.Create();
            mydale.BlockSize = 256;
            mydale.KeySize = 256;
            mydale.IV = et.IV;
            mydale.Key = et.key;
            CryptoStream mystream = new CryptoStream(prevStream, mydale.CreateDecryptor(), CryptoStreamMode.Read);
            prevStream = mystream;
        }
        return prevStream;
    }
   /// <summary>
   /// Encrypts the input stream and securely deletes the input file with the specified number of passes. The source stream MUST have length
   /// </summary>
   /// <param name="source">The source stream (to be deleted)</param>
   /// <param name="dest">The destination stream</param>
   /// <param name="delcount">The number of passes to erase the file</param>
   /// <param name="cryptInfo">Crypto stuff</param>
    public static Stream Encrypt(Stream source, int delcount, params keyPair[] cryptInfo)
    {

        Stream prevStream = source;
        foreach (keyPair et in cryptInfo)
        {
            Rijndael mydale = Rijndael.Create();
            mydale.BlockSize = 256;
            mydale.KeySize = 256;
            mydale.IV = et.IV;
            mydale.Key = et.key;

            CryptoStream mystream = new CryptoStream(prevStream, mydale.CreateEncryptor(), CryptoStreamMode.Write);
            prevStream = mystream;
        }
        return prevStream;
        //int cpos = 0;
        //while (cpos < delcount)
        //{
        //    source.Position = 0;
        //    while (source.Position < source.Length)
        //    {
        //        if (source.Length - source.Position > 512)
        //        {
        //            Random mrand = new Random();

        //            byte[] thearray = new byte[512];
        //            mrand.NextBytes(thearray);
        //            source.Write(thearray, 0, thearray.Length);
        //        }
        //        else
        //        {
        //            Random mrand = new Random();

        //            byte[] thearray = new byte[source.Length-source.Position];
        //            mrand.NextBytes(thearray);
        //            source.Write(thearray, 0, thearray.Length);
        //            source.Flush();
        //        }
        //    }
        //    cpos += 1;
        //}
    }
}
class keyPair
{
    public byte[] IV;
    public byte[] key;
    public keyPair(byte[] InitializationVector, byte[] Key)
    {
        IV = InitializationVector;
        key = Key;
    }
}

删除文件的代码已注释掉,并且未在程序中使用。

6 个答案:

答案 0 :(得分:1)

如果我理解正确,您的密码必须在解密时以相反的顺序使用。

在Program.cs的解密部分尝试:

  keyPair[] list = new keyPair[] { thirdpair, secondpair, mypair };
  thestream = gridCrypto.Decrypt(thestream, list);

答案 1 :(得分:1)

你没有处理你的流。将其插入加密测试代码:

thestream.Dispose();

或(最好)使用using语句打开文件:

using (Stream stream = File.Open(...))
{
}

最后,它有效。

在使用流时,您应该(几乎)总是使用using语句,以确保它们正确关闭。在加密流的情况下,关闭流也会写入最后一个块。

我有点惊讶你不需要反转键的顺序......但是密钥创建代码非常模糊,我真的不想进一步探索它:(

答案 2 :(得分:0)

你确定new CryptoStream构造函数不会产生任何线程吗?

您确定当prevStream = mystream新创建的mystream实际写完了吗?

也许您需要首先“刷新”流,并确保在将其分配给旧对象之前已完成调用。我不知道图书馆,但这对我来说似乎是一种竞争条件。

答案 3 :(得分:0)

为什么不将它们加密为字节数组,然后通过另一种算法运行这些字节。

如果您设计得很好,那么您可以使用n个加密算法,如果需要,可以将其中一个嵌入到另一个中。

但是,如果你想要走你的路线那么你可能想把它分解成单独的测试步骤,看看问题可能在哪里。

所以,你先用一种算法加密,然后立即解密,再用两次,然后三次。

您应该对此进行单元测试,以便您可以使用短消息然后长消息进行测试,以确保您没有消息大小的问题。

答案 4 :(得分:0)

我认为问题在于您不使用加密发生的CryptoStream的Write方法。 您只是初始化它们,它们设置您要写入的流而不是从中读取。看看此示例:

http://msdn.microsoft.com/en-us/library/k1f992c1.aspx

说:

    // Create or open the specified file.
        FileStream fStream = File.Open(FileName, FileMode.OpenOrCreate);

        // Create a new Rijndael object.
        Rijndael RijndaelAlg = Rijndael.Create();

        // Create a CryptoStream using the FileStream 
        // and the passed key and initialization vector (IV).
        CryptoStream cStream = new CryptoStream(fStream,
            RijndaelAlg.CreateEncryptor(Key, IV),
            CryptoStreamMode.Write);

        // Create a StreamWriter using the CryptoStream.
        StreamWriter sWriter = new StreamWriter(cStream);

        try
        {
            // Write the data to the stream 
            // to encrypt it.
            sWriter.WriteLine(Data);
        }
        .....

我个人总是使用TransfromBlock,因为我知道我的输入和输出字节是什么。

答案 5 :(得分:0)

这是服务器上的文件系统问题。它在服务器管理员在服务器上运行FSRepair后修复(它恰好是一个损坏的虚拟硬盘,而不是程序中的错误)。