将包含C中的无符号字符指针的代码移植到C#

时间:2013-03-04 21:37:56

标签: c# c encryption

我在C中有这个代码,我需要移植到C#:

void CryptoBuffer(unsigned char *Buffer, unsigned short length)
{
    unsigned short i;
    for(i=0; i < length; i++)
    {
        *Buffer ^= 0xAA;
        *Buffer++ += 0xC9;
    }
}

我试过了:

public void CryptoBuffer(byte[] buffer, int length)
{
    for(int i = 0; i < length; i++)
    {
        buffer[i] ^= 0xAA;
        buffer[i] += 0xC9;
    }
}

但结果与预期结果不符。

根据这个例子,这个:

A5 03 18 01...

应该成为这个:

A5 6F 93 8B...

它还说第一个字节没有加密,所以这就是A5保持不变的原因。

编辑以澄清:规范只是说你应该跳过第一个字节,它没有详细说明,所以我猜你只是将序列从第1位传递到最后位置跳过第一个字节。

但我对C#端口的结果是:

A5 72 7B 74...

这个端口是正确的还是我错过了什么?

编辑2 :为了进一步澄清,这是一个封闭的协议,所以我不能详细说明,这就是为什么我提供了足够的信息来帮助我移植代码,C代码是给我的那个,这就是规范所说的那样。 真正的问题是规范中的“0xAA”是错误的,这就是输出不是预期的原因。这里提供的C#代码和接受的答案都是正确的。

7 个答案:

答案 0 :(得分:9)

让我们一步一步地分解它。

void CryptoBuffer(unsigned char *Buffer, unsigned short length)
{
    unsigned short i;
    for(i=0; i < length; i++)
    {
        *Buffer ^= 0xAA;
        *Buffer++ += 0xC9;
    }
}

无论其他一些评论如何,这个 你通常在C / C ++中做这些事情。关于这段代码并没有什么特别之处,它并不过分复杂,但我认为将其分解以向您展示会发生什么是很好的。

注意事项:

  1. unsigned char与c#
  2. 中的byte基本相同
  3. 无符号长度的值介于0-65536之间。 Int应该做到这一点。
  4. 缓冲区有一个后增量
  5. 字节分配(+ = 0xC9)将溢出。如果它溢出则在这种情况下被截断为8位。
  6. 缓冲区由ptr传递,因此调用方法中的指针将保持不变。
  7. 这只是基本的C代码,没有C ++。假设人们不在此处使用运算符重载,这是非常安全的。
  8. 这里唯一的“困难”是Buffer ++。细节可以在Sutter的“Exceptional C ++”一书中阅读,但是一个小例子也解释了这一点。幸运的是,我们有一个完美的例子供我们使用。上述代码的文字翻译为:

    void CryptoBuffer(unsigned char *Buffer, unsigned short length)
    {
        unsigned short i;
        for(i=0; i < length; i++)
        {
            *Buffer ^= 0xAA;
            unsigned char *tmp = Buffer;
            *tmp += 0xC9;
            Buffer = tmp + 1;
        }
    }
    

    在这种情况下,临时变量可以简单地解决,这导致我们:

    void CryptoBuffer(unsigned char *Buffer, unsigned short length)
    {
        unsigned short i;
        for(i=0; i < length; i++)
        {
            *Buffer ^= 0xAA;
            *Buffer += 0xC9;
            ++Buffer;
        }
    }
    

    现在将此代码更改为C#非常简单:

    private void CryptoBuffer(byte[] Buffer, int length)
    {
        for (int i=0; i<length; ++i) 
        {
            Buffer[i] = (byte)((Buffer[i] ^ 0xAA) + 0xC9);
        }
    }
    

    这与您的移植代码基本相同。这意味着在某个地方出现了其他问题......所以,让我们破解加密缓冲区吗? : - )

    如果我们假设没有使用第一个字节(如你所说)并且'0xAA'和/或'0xC9'是错误的,我们可以简单地尝试所有组合:

    static void Main(string[] args)
    {
        byte[] orig = new byte[] { 0x03, 0x18, 0x01 };
        byte[] target = new byte[] { 0x6F, 0x93, 0x8b };
    
        for (int i = 0; i < 256; ++i)
        {
            for (int j = 0; j < 256; ++j)
            {
                bool okay = true;
                for (int k = 0; okay && k < 3; ++k)
                {
                    byte tmp = (byte)((orig[k] ^ i) + j);
                    if (tmp != target[k]) { okay = false; break; }
                }
                if (okay)
                {
                    Console.WriteLine("Solution for i={0} and j={1}", i, j);
                }
            }
        }
        Console.ReadLine();
    }
    

    我们去了: oops 没有解决方案。这意味着cryptobuffer没有做你认为它正在做的事情,或者这里缺少部分C代码。 F.ex.他们真的将'Buffer'传递给CryptoBuffer方法,还是他们之前更改了指针?

    总结说,我认为这里唯一的好答案是缺少解决这个问题的重要信息。

答案 1 :(得分:5)

您提供的示例与C示例中的代码不一致,C和C#代码产生相同的结果。

答案 2 :(得分:3)

移植看起来正确;你能解释为什么03应该成为6F吗?事实上,结果似乎与03年的“预期”值相差无疑,对我来说有点怀疑。

答案 3 :(得分:1)

端口看起来正确。

在这种情况下,我要做的是拿出一张纸和一支笔,用二进制写出字节,做XOR,然后加法。现在将其与C和C#代码进行比较。

答案 4 :(得分:1)

在C#中,您溢出字节,因此它被截断为0x72。这是在二进制和十六进制中转换0x03的数学运算:

   00000011   0x003
^  10101010   0x0AA
=  10101001   0x0A9
+  11001001   0x0C9
= 101110010   0x172

答案 5 :(得分:0)

使用C中的原始方法,我们首先假设序列以对称方式解密/加密,并调用CryptoBuffer

  • 最初在a5 03 18 01 ...

    上调用
    a5 03 18 01 ... => d8 72 7b 74 ... 
    

    然后在d8 72 7b 74 ...

    d8 72 7b 74 ... => 3b a1 9a a7 ...
    
  • 最初在a5 6f 93 8b ...

    上调用
    a5 6f 93 8b ... => d8 8e 02 ea ...
    

    然后在d8 8e 02 ea ...

    d8 8e 02 ea ... => 3b ed 71 09 ... 
    

我们知道这不可行。

当然,您可能有非对称解密方法;但首先,我们需要a5 03 18 01 ... => a5 6f 93 8b ...或者方向的反向用任何可能的幻数证明。使用强力方法的分析代码放在帖子的后面。

我将幻数作为测试变量。通过再现性分析,我们发现原始序列可以在连续变化的幻数上每256次调用再现一次。好的,我们已经完成了它仍然可以在这里。

但是,可行性分析会对256*256=65536original => expected两个方向的所有expected => original个案件进行测试,而且没有。

现在我们知道无法将加密序列解密为预期结果。

因此,我们只能说两种语言或代码的预期行为相同,但预期结果不可能因为假设被打破。


分析代码

public void CryptoBuffer(byte[] buffer, ushort magicShort) {
    var magicBytes=BitConverter.GetBytes(magicShort);
    var count=buffer.Length;

    for(var i=0; i<count; i++) {
        buffer[i]^=magicBytes[1];
        buffer[i]+=magicBytes[0];
    }
}

int Analyze(
    Action<byte[], ushort> subject,
    byte[] expected, byte[] original,
    ushort? magicShort=default(ushort?)
    ) {
    Func<byte[], String> LaHeX= // narrowing bytes to hex statement
        arg => arg.Select(x => String.Format("{0:x2}\x20", x)).Aggregate(String.Concat);

    var temporal=(byte[])original.Clone();
    var found=0;

    for(var i=ushort.MaxValue; i>=0; --i) {
        if(found>255) {
            Console.WriteLine(": might found more than the number of square root; ");
            Console.WriteLine(": analyze stopped ");
            Console.WriteLine();
            break;
        }

        subject(temporal, magicShort??i);

        if(expected.SequenceEqual(temporal)) {
            ++found;
            Console.WriteLine("i={0:x2}; temporal={1}", i, LaHeX(temporal));
        }

        if(expected!=original)
            temporal=(byte[])original.Clone();
    }

    return found;
}

void PerformTest() {
    var original=new byte[] { 0xa5, 0x03, 0x18, 0x01 };
    var expected=new byte[] { 0xa5, 0x6f, 0x93, 0x8b };

    Console.WriteLine("--- reproducibility analysis --- ");
    Console.WriteLine("found: {0}", Analyze(CryptoBuffer, original, original, 0xaac9));
    Console.WriteLine();

    Console.WriteLine("--- feasibility analysis --- ");
    Console.WriteLine("found: {0}", Analyze(CryptoBuffer, expected, original));
    Console.WriteLine();

    // swap original and expected
    var temporal=original;
    original=expected;
    expected=temporal;

    Console.WriteLine("--- reproducibility analysis --- ");
    Console.WriteLine("found: {0}", Analyze(CryptoBuffer, original, original, 0xaac9));
    Console.WriteLine();

    Console.WriteLine("--- feasibility analysis --- ");
    Console.WriteLine("found: {0}", Analyze(CryptoBuffer, expected, original));
    Console.WriteLine();
}

答案 6 :(得分:0)

这是一个演示

http://codepad.org/UrX0okgu

显示原始代码,如果输入A5 03 18 01,则生成D8 72 7B 01;所以

  1. 规则只有当缓冲区从第2个开始发送时才会解码第一个字节是正确的(告诉我们看电话)

  2. 输出不匹配(您是否错过了其他来电?)

  3. 因此,您的翻译是正确的,但您对原始代码所做的事情的期望并非如此。