【问题标题】:Help me with XOR encryption帮助我进行 XOR 加密
【发布时间】:2011-02-01 17:23:35
【问题描述】:

我在C# 中写了这段代码来用一个密钥加密一个字符串:

private static int Bin2Dec(string num)
{
    int _num = 0;

    for (int i = 0; i < num.Length; i++)
        _num += (int)Math.Pow(2, num.Length - i - 1) * int.Parse(num[i].ToString());

    return _num;
}

private static string Dec2Bin(int num)
{
    if (num < 2) return num.ToString();

    return Dec2Bin(num / 2) + (num % 2).ToString();
}

public static string StrXor(string str, string key)
{
    string _str = "";
    string _key = "";
    string _xorStr = "";
    string _temp = "";

    for (int i = 0; i < str.Length; i++)
    {
        _temp = Dec2Bin(str[i]);    

        for (int j = 0; j < 8 - _temp.Length + 1; j++)
            _temp = '0' + _temp;

        _str += _temp;
    }

    for (int i = 0; i < key.Length; i++)
    {
        _temp = Dec2Bin(key[i]);

        for (int j = 0; j < 8 - _temp.Length + 1; j++)
            _temp = '0' + _temp;

        _key += _temp;
    }    

    while (_key.Length < _str.Length) _key += _key;

    if (_key.Length > _str.Length) _key = _key.Substring(0, _str.Length);

    for (int i = 0; i < _str.Length; i++)
        if (_str[i] == _key[i]) { _xorStr += '0'; } else { _xorStr += '1'; }

    _str = "";

    for (int i = 0; i < _xorStr.Length; i += 8)
    {
        char _chr = (char)0;
        _chr = (char)Bin2Dec(_xorStr.Substring(i, 8)); //ERROR : (Index and length must refer to a location within the string. Parameter name: length)
        _str += _chr;
    }

    return _str;
}

问题是当我想用这段代码解密加密文本时总是出错:

string enc_text = ENCRYPT.XORENC("abc","a"); // enc_text = " ♥☻"
string dec_text = ENCRYPT.XORENC(enc_text,"a"); // ArgumentOutOfRangeException

有什么线索吗?

【问题讨论】:

  • 我只能说是吧? :) 也许这是一个教育练习,但您不需要将字符转换为字符串,手动对它们进行异或然后将它们转换回字符串。正如您的 Dec2Bin 和 Bin2Dec 函数所证明的那样,char 可以通过强制转换与 int 相互转换,因此只需从两个字符串中获取 char,应用 '^' xor 运算符并放入新字符串。
  • 如果您指定遇到的错误会有所帮助:)
  • 另外,您可能希望使用 StringBuilders 而不是 Strings。字符串是不可变的(不能更改),所以像 _str += _temp;每次都会生成一个新字符串,这使得这种方法不必要地繁重/昂贵。使用 StringBuilder 和 .Append(temp)。
  • @Michael Stum:事实证明,StringBuilder 实际上可以更慢,或者与使用串联差不多。 StringBuilder 仅适用于大字符串。
  • @siride 它可能会更慢,但这主要是为了琐碎的连接(我认为是 3-4 个字符串)。在他的情况下,循环是不确定的,因为它取决于输入字符串的长度,所以使用 SB 是一个更安全的选择(当然,如果使用像 str.Length 这样的合理缓冲区大小来初始化它)

标签: c# encryption encryption-symmetric


【解决方案1】:
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
}

【讨论】:

    【解决方案2】:

    这里有一些简单的加解密代码

    class CEncryption
    {
        public static string Encrypt(string strIn, string strKey)
        {
            string sbOut = String.Empty;
            for (int i = 0; i < strIn.Length; i++)
            {
                sbOut += String.Format("{0:00}", strIn[i] ^ strKey[i % strKey.Length]);
            }
    
            return sbOut;
        }
    
        public static string Decrypt(string strIn, string strKey)
        {
            string sbOut = String.Empty;
            for (int i = 0; i < strIn.Length; i += 2)
            {
                byte code = Convert.ToByte(strIn.Substring(i, 2));
                sbOut += (char)(code ^ strKey[(i/2) % strKey.Length]);
            }
    
            return sbOut;
        }
     }
    

    【讨论】:

    • 解密函数在包含大写字母的字符串上失败。这个功能有什么更新吗?
    【解决方案3】:

    如果您有一个字符 char,您可以将其转换为整数 int

    然后您可以使用^ 运算符对其执行异或。您目前似乎没有使用该运算符,这可能是您的问题的根源。

    string EncryptOrDecrypt(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();
    }
    

    那种东西。这是一个带有 cmets 的较长版本,它分步执行相同的操作,以便更容易学习:

    string EncryptOrDecrypt(string text, string key)
    {
        var result = new StringBuilder();
    
        for (int c = 0; c < text.Length; c++)
        {
            // take next character from string
            char character = text[c];
    
            // cast to a uint
            uint charCode = (uint)character;
    
            // figure out which character to take from the key
            int keyPosition = c % key.Length; // use modulo to "wrap round"
    
            // take the key character
            char keyChar = key[keyPosition];
    
            // cast it to a uint also
            uint keyCode = (uint)keyChar;
    
            // perform XOR on the two character codes
            uint combinedCode = charCode ^ keyCode;
    
            // cast back to a char
            char combinedChar = (char)combinedCode;
    
            // add to the result
            result.Append(combineChar);
        }
    
        return result.ToString();
    }
    

    简短版本相同,但删除了中间变量,将表达式直接替换到使用它们的位置。

    【讨论】:

    • 是否可以让这个方法只返回字母数字值?它可以工作,但会产生奇怪的字符。而且我需要它们对我的用例来说是可读的。
    • @Dbloom 要在不丢失信息的情况下缩小使用的字符范围,您需要执行第二次转换为十六进制或 base64 等编码。请注意,这些内容根本不是“人类可读的”,但可以安全地以文本格式发送、剪贴板操作等。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-16
    • 1970-01-01
    • 1970-01-01
    • 2017-11-03
    • 1970-01-01
    • 2014-10-11
    相关资源
    最近更新 更多