错误的XOR解密

时间:2014-03-03 17:11:39

标签: c# xor

我制作了一个用随机密钥对文本进行编码的程序。当使用密钥时,即使我只使用一个字母来编码

,解码器的结果也完全错误

这是用于加密/解密的函数以及生成具有确定长度的随机密钥的函数:

string XOR_String(string text, string key)
{
    var result = new StringBuilder();

    for (int c = 0; c < text.Length; c++)
        result.Append((char)((uint)text[c] ^ (uint)key[c % key.Length]));

    return result.ToString();
}

private static string RandomString(int Size)
{
    Random random = new Random();
    string input = "abcdefghijklmnopqrstuvwxyz0123456789";
    var chars = Enumerable.Range(0, Size)
                           .Select(x => input[random.Next(0, input.Length)]);
    return new string(chars.ToArray());
}

解密:

private void button1_Click(object sender, EventArgs e)
{
  openFileDialog1.FileName = "data.txt";
  openFileDialog1.Title = "Open file";
  openFileDialog1.InitialDirectory = System.Environment.GetFolderPath(Environment.SpecialFolder.Personal);

  if (openFileDialog1.ShowDialog() == DialogResult.OK)
  {
      file = openFileDialog1;

      fs = new System.IO.FileStream(file.FileName, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite);
      reader = new System.IO.StreamReader(fs);
      file_contents = reader.ReadToEnd();

      if (textBox1.Text != "")
      {
          data = XOR_String(file_contents, textBox1.Text);
          reader.Close();
      }
  }
}

加密:

private void button2_Click(object sender, EventArgs e)
{
    System.IO.FileInfo file_info = new System.IO.FileInfo(file.FileName);
    long file_info_length = file_info.Length;
    int file_length = checked((int)file_info_length);
    String key = RandomString(file_length);
    textBox1.Text = key;
    data = XOR_String(file_contents, key);
    System.IO.File.WriteAllText(file.FileName, data);
    reader.Close();
}

4 个答案:

答案 0 :(得分:5)

您确实意识到C#/ .Net / CLR世界中的字符串是UTF-16编码的Unicode,对吗?

http://en.wikipedia.org/wiki/UTF-16

只有Basic Basiclingling Plance中代码点的那些字符(范围U + 0000- U + D7FF和U + E000-U + FFFF)才表示为单个16位字符。

您对字符的随机异或会导致随机内容不会往返:它将是无效的UTF-16或代理对

那是你的问题。

如果你想编码这样的东西,试试这个:

  • 使用所选的编码从要编码的字符串中创建byte[]
  • 异或。
  • 使用Convert.ToBase64String()将生成的byte[]密文转换为Base64编码的字符串。

要解码它,请颠倒过程:

  • 使用Convert.FromBase64String()将Base64编码的字符串转换为byte[]
  • XOR
  • 使用您在首先使用的相同编码将生成的明文byte[]转换回C#/ .Net字符串。

编辑注意:

只是为了好玩......

  • 测试用例:

    MyNotVerySecureCrypto crypto = new MyNotVerySecureCrypto("cat" ) ;
    
    string plainText  = "The quick brown fox jumped over the lazy dog." ;
    string cipherText = crypto.Encrypt(plainText) ;
    string plainText1 = crypto.Decrypt(cipherText) ;
    
    Debug.Assert(plainText.Equals(plainText1,StringComparison.Ordinal));
    
  • 测试此代码:

    public class MyNotVerySecureCrypto
    {
      private byte[]   Key      { get ; set ; }
      private Encoding Encoding { get ; set ; }
    
      public MyNotVerySecureCrypto( string key , Encoding encoding )
      {
        this.Encoding = encoding ;
        this.Key      = Encoding.GetBytes(key).Where( b => b != 0 ).ToArray() ;
        return ;
      }
      public MyNotVerySecureCrypto( string key ) : this ( key , Encoding.UTF8 )
      {
        return ;
      }
    
      public string Encrypt( string plainText )
      {
        int i = 0 ;
        byte[] octets = Encoding
                        .GetBytes(plainText)
                        .Select( b => (byte) (b^Key[(++i)%Key.Length]) )
                        .ToArray()
                        ;
        string cipherText = Convert.ToBase64String(octets) ;
        return cipherText ;
      }
    
      public string Decrypt( string cipherText )
      {
        int i = 0 ;
        byte[] octets = Convert
                        .FromBase64String(cipherText)
                        .Select( b => (byte) (b^Key[(++i)%Key.Length]) )
                        .ToArray()
                        ;
        string plainText = Encoding.GetString( octets ) ;
        return plainText ;
      }
    
    }
    

答案 1 :(得分:1)

您确定数据中的每个字符都只有一个字节长吗?只有ASCII字符长度为一个字节,UTF字符可以占用多个字节。在那种情况下,你会遇到麻烦。您可以使用以下内容来读取ASCII字符串

  

StreamReader reader = new StreamReader(fileStream,new   ASCIIEncoding());

答案 2 :(得分:0)

在使用XOR对文本进行加密之前,将文本转换为Base64。

使用此方法尤其有助于在PHP和PHP之间交换XORed数据。 C#。

答案 3 :(得分:0)

    public static byte[] EncryptOrDecrypt(byte[] text, byte[] key)
    {
        byte[] xor = new byte[text.Length];
        for (int i = 0; i < text.Length; i++)
        {
            xor[i] = (byte)(text[i] ^ key[i % key.Length]);
        }
        return xor;
    }

    static void Main(string[] args){
        string input;
        byte[] inputBytes;

        string inputKey;
        byte[] key;

        do
        {
            input = System.Console.ReadLine();
            inputBytes = Encoding.Unicode.GetBytes(input);

            inputKey = System.Console.ReadLine();
            key = Encoding.Unicode.GetBytes(inputKey);

            //byte[] key = { 0, 0 }; if key is 0, encryption will not happen

            byte[] encryptedBytes = EncryptOrDecrypt(inputBytes, key);
            string encryptedStr = Encoding.Unicode.GetString(encryptedBytes);

            byte[] decryptedBytes = EncryptOrDecrypt(encryptedBytes, key);
            string decryptedStr = Encoding.Unicode.GetString(decryptedBytes);

            System.Console.WriteLine("Encrypted string:");
            System.Console.WriteLine(encryptedStr);
            System.Console.WriteLine("Decrypted string:");
            System.Console.WriteLine(decryptedStr);

        } while (input != "-1" && inputKey != "-1");
        //test:
        //pavle
        //23
        //Encrypted string:
        //BRD_W
        //Decrypted string:
        //pavle
    }