1

I have to do a XOR to calculate an decryption key.

My expected key is "0123456789ABCDEFFEDCBA9876543210" and my sample inputs are

("8D10DA193E98524379264ADFFD043632" and "C339F7EB7339FAC87FAF0478B500422") . Second sample is ( "00000000000000000000000000000000" and "0123456789ABCDEFFEDCBA9876543210")

So here is the thing when I XOR my first sample Iam getting this as a result " 7123456789ABCDEFFEDCBA9876543210" and for my second sample I am getting "123456789ABCDEFFEDCBA9876543210" the leading zero is getting cut off.

I have tried various things but here is the code I settled on:

static void Main(string[] args)
        {
            const string bdk1 = "8D10DA193E98524379264ADFFD043632";
            const string bdk2 = "C339F7EB7339FAC87FAF0478B500422";

            //const string bdk1 = "00000000000000000000000000000000";
            //const string bdk2 = "0123456789ABCDEFFEDCBA9876543210";

            const string expected = "0123456789ABCDEFFEDCBA9876543210";

            BigInteger b1 = BigInteger.Parse(bdk1, NumberStyles.HexNumber);
            BigInteger b2 = BigInteger.Parse(bdk2, NumberStyles.HexNumber);

            BigInteger actual = b1 ^ b2;
            string stringRet = actual.ToString("X");//.PadLeft(expected.Length, '0');

            Console.WriteLine("Expected: " + expected);
            Console.WriteLine("Actual  : " + stringRet);

            Console.ReadLine(); 
        }
    }
Waddaulookingat
  • 337
  • 3
  • 16
  • ToString() does not bother writing leading zeros, unless you force it to.. – Hans Passant Oct 03 '17 at 22:27
  • 1
    Because you're doing it as a number. Except what you have _isn't_ a number, it's a stream of data, that is, **bytes**. You need to get bytes and XOR those... – Clockwork-Muse Oct 03 '17 at 22:30
  • @Clockwork-Muse Incorrect, it's a **hex** value. _[The style parameter makes this method overload useful when value contains the string representation of a hexadecimal value](https://msdn.microsoft.com/en-us/library/dd268285(v=vs.110).aspx)_ –  Oct 03 '17 at 22:43
  • It's hex, yeah, but that doesn't mean it's a number. Furthermore, continuing down this route is going to have serious problems if any of the input strings have multiple leading zeroes. Which is a thing with a stream of bytes, but not numbers. – Clockwork-Muse Oct 03 '17 at 22:52

3 Answers3

4

I suggest you break the problem down, and since this is a data-driven task, use a data-centric design. So start with a class that represents a byte array as a hexadecimal string.

class HexString
{
    private byte[] _data;
}

You need to be able to construct this from both a byte array and a string, so add constructors for both. Our raw storage is byte[] so the first constructor is trivial. The second constructor uses a bit of LINQ-fu to do the conversion:

public class HexString
{
    private byte[] _data;

    public HexString(byte[] data)
    {
        _data = data;
    }

    public HexString(string data)
    {
        if ((data.Length & 1)!= 0) throw new ArgumentException("Hex string must have an even number of digits.");

        _data = Enumerable.Range(0, data.Length)
            .Where(x => x % 2 == 0)
            .Select(x => Convert.ToByte(data.Substring(x, 2), 16))
            .ToArray();
    }
}

It's useless if you can't read it, so override ToString() so you can output it through the console. In this sample I use a little trick and the BitConverter:

    public override string ToString()
    {
        string hex = BitConverter.ToString(_data);
        return hex.Replace("-","");
    }

And you need to be able to XOR it, so overload the XOR operator. Note that the value in question is a bytestream, not a number, so we will XOR each byte one at a time, using LINQ's Zip() method to combine the arrays:

    static public HexString operator ^(HexString LHS, HexString RHS)
    {
        return new HexString
            (
                LHS._data.Zip
                    ( 
                        RHS._data, 
                        (a, b) => (byte)(a ^ b)
                    )
                .ToArray()
            );
    } 

With all that done, your main program becomes very short (as it should be):

public class Program
{
    static public void Main()
    {
        HexString bdk1 = new HexString("8D10DA193E98524379264ADFFD043632");
        HexString bdk2 = new HexString("8C339F7EB7339FAC87FAF0478B500422");

        const string expected = "0123456789ABCDEFFEDCBA9876543210";

        HexString actual = bdk1 ^ bdk2;

        Console.WriteLine("Expected: " + expected);
        Console.WriteLine("Actual  : " + actual);

        Console.ReadLine(); 
    }

Output:

Expected: 0123456789ABCDEFFEDCBA9876543210
Actual  : 0123456789ABCDEFFEDCBA9876543210

See the complete solution on DotNetFiddle.

John Wu
  • 50,556
  • 8
  • 44
  • 80
  • Brilliant John ...I was going along the lines of converting a HEX to bit's and trying that. Overloading the ^ never occurred to me. Learned something new today, the zip operator and a valuable lesson, when stuck on a problem try to think around the problem. – Waddaulookingat Oct 04 '17 at 00:19
0

You're converting a number (of type BitInteger) to a string. Of course it won't have any leading zeroes. Nor will any other number, if you convert it to string.

If you for some reason really need a leading zero, the only way to have it will be to pad the remaining string length of your convert result with "0"'s.

Or use this ToString overload:

number.ToString("X" + totalLengthYouNeed);
AgentFire
  • 8,944
  • 8
  • 43
  • 90
  • 1
    Hey, OP isn't really dealing with a number, so I don't see this as a viable solution. – Clockwork-Muse Oct 03 '17 at 22:30
  • totalLengthYouNeed is expected.Length – Baccata Oct 03 '17 at 22:33
  • AgentFire; Yes I have to have leading 0, it's an decryption key I cannot be sure what's in the front. I have to take it at face value. Plus like like the other comment said I am not dealing with a number – Waddaulookingat Oct 03 '17 at 22:33
  • @Clockwork-Muse Incorrect, it's a **hex** value. _[The style parameter makes this method overload useful when value contains the string representation of a hexadecimal value](https://msdn.microsoft.com/en-us/library/dd268285(v=vs.110).aspx)_ –  Oct 03 '17 at 22:43
  • Sure it's hex. But the data represented isn't actually a number, it's a stream of bytes (which are traditionally represented in hex). This isn't something you're supposed to be doing math on. And `"0000000000"` != `0` (which passing through `BigInteger` would do). – Clockwork-Muse Oct 03 '17 at 22:50
0

This is similar to combining Guids. You could try converting the strings to byte arrays, and then xor the byte arrays together. The below is for Guids, if it helps. A little modification would probably get you where you need to be.

private Guid xorCombineGuids(Guid g1, Guid g2)
{
    var g1Bytes = g1.ToByteArray();
    var g2Bytes = g2.ToByteArray();
    int length = g1.ToByteArray().Count();
    byte[] xoredGuidBytes = new byte[length];
    for (int i = 0; i < g1.ToByteArray().Count(); i++)
    {
        xoredGuidBytes[i] = (byte)(g1Bytes[i] ^ g2Bytes[i]);
    }
    return new Guid(xoredGuidBytes);
}

I'll also point you to: How can I convert a hex string to a byte array?

Joe
  • 233
  • 1
  • 5