我制作了一个用随机密钥对文本进行编码的程序。当使用密钥时,即使我只使用一个字母来编码
,解码器的结果也完全错误这是用于加密/解密的函数以及生成具有确定长度的随机密钥的函数:
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();
}
答案 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[]
。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
}