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

我在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#代码和接受的答案毕竟是正确的。

让我们分开,我们,一步一步。

 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#中的byte基本相同
  2. 无符号长度的值介于0-65536之间。 Int应该做的伎俩。
  3. 缓冲区有一个后增量
  4. 字节分配(+ = 0xC9)将溢出。 如果它溢出则在这种情况下被截断为8位。
  5. 缓冲区由ptr传递,因此调用方法中的指针将保持不变。
  6. 这只是基本的C代码,没有C ++。 假设人们不在此处使用运算符重载,这是非常安全的。

这里唯一的“困难”是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; } } 

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

 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 

这基本上与您的移植代码相同。 这意味着在未来的某个地方出现了其他问题......所以,让我们破解密码缓冲器吧? 🙂

如果我们假设没有使用第一个字节(如你所说)并且'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方法还是之前更改了指针?

最后,我认为这里唯一的好答案是缺少解决这个问题的关键信息。

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

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

港口看起来正确。

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

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

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

使用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 ...

     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 ...或方向的反向已被certificate具有任何可能的幻数。 蛮力方法的分析代码放在post的后面。

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

然而, 可行性分析测试所有256*256=65536情况,两个方向, original => expectedexpected => original ,没有成功。

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

因此,我们只能说出语言或代码预期行为是相同的 ,但由于假设被打破, 因此无法实现预期的结果


分析代码

 public void CryptoBuffer(byte[] buffer, ushort magicShort) { var magicBytes=BitConverter.GetBytes(magicShort); var count=buffer.Length; for(var i=0; i subject, byte[] expected, byte[] original, ushort? magicShort=default(ushort?) ) { Func 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(); } 

这是一个演示

http://codepad.org/UrX0okgu

显示原始代码,给定输入A5 03 18 01产生D8 72 7B 01 ; 所以

  1. 只有当缓冲区从第二个开始发送时,才能正确判断第一个字节未被解码(显示我们的调用)

  2. 输出不匹配(你错过了其他的电话吗?)

所以你的翻译是正确的,但你对原始代码所做的不是。