Help me with XOR encryption

28,599

Solution 1

If you have a character, a char, you can convert it to an integer, an int.

And then you can use the ^ operator to perform XOR on it. You don't appear to be using that operator at the moment, which might be the source of your problem.

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

That kind of thing. Here's a longer version with comments that does the same thing in steps, to make it easier to learn from:

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

The short version is the same but with the intermediate variables removed, substituting expressions directly into where they're used.

Solution 2

// Code
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;
}

// Test
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
}
Share:
28,599
fardjad
Author by

fardjad

Updated on July 08, 2022

Comments

  • fardjad
    fardjad almost 2 years

    I wrote this code in C# to encrypt a string with a key:

    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;
    }
    

    The problem is that I always get error when I want to decrypt an encryted text with this code:

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

    Any clues?

  • pithhelmet
    pithhelmet over 11 years
    The decrypt function fails on a string with a capital letter in it. any updates to this function?
  • Dbloom
    Dbloom over 3 years
    Is it possible to make this method only return alpha numeric values? It works but produces weird characters. And I need them to be human readable for my use case.
  • Daniel Earwicker
    Daniel Earwicker over 3 years
    @Dbloom to narrow the range of characters used without losing information, you need to perform a second conversion to an encoding such as hex or base64. Note that these won’t be at all “human readable” but they will be safe to send in text formats, clipboard operations etc.