5

I am trying to port the following C++ function to C#:

QString Engine::FDigest(const QString & input)
{
    if(input.size() != 32) return "";

    int idx[] = {0xe, 0x3, 0x6, 0x8, 0x2},
        mul[] = {2, 2, 5, 4, 3},
        add[] = {0x0, 0xd, 0x10, 0xb, 0x5},
        a, m, i, t, v;

    QString b;
    char tmp[2] = { 0, 0 };

    for(int j = 0; j <= 4; j++)
    {
        a = add[j];
        m = mul[j];
        i = idx[j];

        tmp[0] = input[i].toAscii();
        t = a + (int)(strtol(tmp, NULL, 16));
        v = (int)(strtol(input.mid(t, 2).toLocal8Bit(), NULL, 16));

        snprintf(tmp, 2, "%x", (v * m) % 0x10);
        b += tmp;
    }

    return b;
}

Some of this code is easy to port however I'm having problems with this part:

tmp[0] = input[i].toAscii();
t = a + (int)(strtol(tmp, NULL, 16));
v = (int)(strtol(input.mid(t, 2).toLocal8Bit(), NULL, 16));

snprintf(tmp, 2, "%x", (v * m) % 0x10);

I have found that (int)strtol(tmp, NULL, 16) equals int.Parse(tmp, "x") in C# and snprintf is String.Format, however I'm not sure about the rest of it.

How can I port this fragment to C#?

2
  • Have updated my answer with potentially useful info Commented Nov 8, 2011 at 10:39
  • I'm assuming QString is a QT class? I added the tag. Commented Nov 8, 2011 at 10:51

2 Answers 2

4

Edit I have a suspicion that your code actually does a MD5 digest of the input data. See below for a snippet based on that assumption.

Translation steps

A few hints that should work well1

Q: tmp[0] = input[i].toAscii();

bytes[] ascii = ASCIIEncoding.GetBytes(input);
tmp[0] = ascii[i];

Q: t = a + (int)(strtol(tmp, NULL, 16));

t = a + int.Parse(string.Format("{0}{1}", tmp[0], tmp[1]),
               System.Globalization.NumberStyles.HexNumber);

Q: v = (int)(strtol(input.mid(t, 2).toLocal8Bit(), NULL, 16));

No clue about the toLocal8bit, would need to read Qt documentation...

Q: snprintf(tmp, 2, "%x", (v * m) % 0x10);

{
    string tmptext = ((v*m % 16)).ToString("X2");
    tmp[0] = tmptext[0];
    tmp[1] = tmptext[1];
}

What if ... it's just MD5?

You could try this directly to see whether it achieves what you need:

using System;

public string FDigest(string input)
{
   MD5 md5 = System.Security.Cryptography.MD5.Create();
   byte[] ascii = System.Text.Encoding.ASCII.GetBytes (input);
   byte[] hash  = md5.ComputeHash (ascii);

   // Convert the byte array to hexadecimal string
   StringBuilder sb = new StringBuilder();
   for (int i = 0; i < hash.Length; i++)
       sb.Append (hash[i].ToString ("X2")); // "x2" for lowercase
   return sb.ToString();
}

1 explicitly not optimized, intended as quick hints; optimize as necessary

Sign up to request clarification or add additional context in comments.

3 Comments

I added an md5 implementation using System.Security since I have a suspicion (after googling the original code) that it might be MD5. Note: this is nothing more than a suspicion (I don't readily recognize the code for hash functions))
for sure its not MD5 since im computing MD5 before this function and input of this function is MD5 hash, but thanks for some hints.
Can we get rid of the tiny text please?
0

A few more hints:

t is a two byte buffer and you only ever write to the first byte, leaving a trailing nul. So t is always a string of exactly one character, and you're processing a hex number one character at a time. So I think

tmp[0] = input[i].toAscii();
t = a + (int)(strtol(tmp, NULL, 16));

this is roughly int t = a + Convert.ToInt32(input.substring(i, 1), 16); - take one digit from input and add its hex value to a which you've looked up from a table. (I'm assuming that the toAscii is simply to map the QString character which is already a hex digit into ASCII for strtol, so if you have a string of hex digits already this is OK.)

Next

v = (int)(strtol(input.mid(t, 2).toLocal8Bit(), NULL, 16));

this means look up two characters from input from offset t, i.e. input.substring(t, 2), then convert these to a hex integer again. v = Convert.ToInt32(input.substring(t, 2), 16); Now, as it happens, I think you'll only actually use the second digit here anyway since the calculation is (v * a) % 0x10, but hey. If again we're working with a QString of hex digits then toLocal8Bit ought to be the same conversion as toAscii - I'm not clear why your code has two different functions here.

Finally convert these values to a single digit in tmp, then append that to b

snprintf(tmp, 2, "%x", (v * m) % 0x10);
b += tmp;

(2 is the length of the buffer, and since we need a trailing nul only 1 is ever written) i.e.

int digit = (v * m) % 0x10;
b += digit.ToString("x");

should do. I'd personally write the mod 16 as a logical and, & 0xf, since it's intended to strip the value down to a single digit.

Note also that in your code i is never set - I guess that's a loop or something you omitted for brevity?

So, in summary

int t = a + Convert.ToInt32(input.substring(i, 1), 16);
int v = Convert.ToInt32(input.substring(t, 2), 16);
int nextDigit = (v * m) & 0xf;
b += nextDigit.ToString("x");

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.