好的,我是C语言的新手,我已经用C#编程了大约10年了,所以仍然习惯于整个语言。我在学习方面一直做得很好,但是我仍然有一些建议,目前我正在尝试编写使用的RC4实现在Xbox 360上加密KeyVault /帐户数据。

但是我遇到了麻烦,代码可以工作,但是输出的数据不正确,我提供了我正在使用的原始c#代码,我知道可以工作,并且提供了C项目中的代码段,所有帮助/指针将不胜感激:)

原始C#代码:

public struct RC4Session
{
    public byte[] Key;
    public int SBoxLen;
    public byte[] SBox;
    public int I;
    public int J;
}


    public static RC4Session RC4CreateSession(byte[] key)
    {
        RC4Session session = new RC4Session
        {
            Key = key,
            I = 0,
            J = 0,
            SBoxLen = 0x100,
            SBox = new byte[0x100]
        };
        for (int i = 0; i < session.SBoxLen; i++)
        {
            session.SBox[i] = (byte)i;
        }
        int index = 0;
        for (int j = 0; j < session.SBoxLen; j++)
        {
            index = ((index + session.SBox[j]) + key[j % key.Length]) % session.SBoxLen;
            byte num4 = session.SBox[index];
            session.SBox[index] = session.SBox[j];
            session.SBox[j] = num4;
        }
        return session;
    }


    public static void RC4Encrypt(ref RC4Session session, byte[] data, int index, int count)
    {
        int num = index;
        do
        {
            session.I = (session.I + 1) % 0x100;
            session.J = (session.J + session.SBox[session.I]) % 0x100;
            byte num2 = session.SBox[session.I];
            session.SBox[session.I] = session.SBox[session.J];
            session.SBox[session.J] = num2;
            byte num3 = data[num];
            byte num4 = session.SBox[(session.SBox[session.I] + session.SBox[session.J]) % 0x100];
            data[num] = (byte)(num3 ^ num4);
            num++;
        }
        while (num != (index + count));
    }


现在这是我自己的c版本:

    typedef struct rc4_state {
         int s_box_len;
         uint8_t* sbox;
         int i;
         int j;
     } rc4_state_t;
     unsigned char* HMAC_SHA1(const char* cpukey, const unsigned char* hmac_key) {
         unsigned char* digest = malloc(20);

         digest = HMAC(EVP_sha1(), cpukey, 16, hmac_key, 16, NULL, NULL);

         return digest;
     }
     void rc4_init(rc4_state_t* state, const uint8_t *key, int keylen)
     {
         state->i = 0;
         state->j = 0;
         state->s_box_len = 0x100;
         state->sbox = malloc(0x100);

         // Init sbox.
         int i = 0, index = 0, j = 0;
         uint8_t buf;
         while(i < state->s_box_len) {
             state->sbox[i] = (uint8_t)i;
             i++;
         }
         while(j < state->s_box_len) {
             index = ((index + state->sbox[j]) + key[j % keylen]) % state->s_box_len;
             buf = state->sbox[index];
             state->sbox[index] = (uint8_t)state->sbox[j];
             state->sbox[j] = (uint8_t)buf;
             j++;
         }
     }

   void rc4_crypt(rc4_state_t* state, const uint8_t *inbuf, uint8_t **outbuf, int buflen)
     {
         int idx = 0;
         uint8_t num, num2, num3;

         *outbuf = malloc(buflen);
         if (*outbuf) {  // do not forget to test for failed allocation
             while(idx != buflen) {
                 state->i = (int)(state->i + 1) % 0x100;
                 state->j = (int)(state->j + state->sbox[state->i]) % 0x100;
                 num = (uint8_t)state->sbox[state->i];
                 state->sbox[state->i] = (uint8_t)state->sbox[state->j];
                 state->sbox[state->j] = (uint8_t)num;
                 num2 = (uint8_t)inbuf[idx];
                 num3 = (uint8_t)state->sbox[(state->sbox[state->i] + (uint8_t)state->sbox[state->j]) % 0x100];
                 (*outbuf)[idx] = (uint8_t)(num2 ^ num3);
                 printf("%02X", (*outbuf)[idx]);
                 idx++;
             }
         }
         printf("\n");
     }


用法(c#):

         byte[] cpukey = new byte[16]
        {
            ...
        };
        byte[] hmac_key = new byte[16]
        {
            ...
        };

        byte[] buf = new System.Security.Cryptography.HMACSHA1(cpukey).ComputeHash(hmac_key);
        MessageBox.Show(BitConverter.ToString(buf).Replace("-", ""), "");


用法(c):

const char cpu_key[16] = { 0xXX, 0xXX, 0xXX };
const unsigned char hmac_key[16] = { ... };
unsigned char* buf = HMAC_SHA1(cpu_key, hmac_key);

uint8_t buf2[20];
uint8_t buf3[8] = { 0x1E, 0xF7, 0x94, 0x48, 0x22, 0x26, 0x89, 0x8E }; // Encrypted Xbox 360 data
uint8_t* buf4;

// Allocated 8 bytes out.
buf4 = malloc(8);
int num = 0;
while(num < 20) {
    buf2[num] = (uint8_t)buf[num]; // convert const char
    num++;
}

rc4_state_t* rc4 = malloc(sizeof(rc4_state_t));

rc4_init(rc4, buf2, 20);
rc4_crypt(rc4, buf3, &buf4, 8);


现在我已经弄清楚了HMACsha1,我为此使用了openssl,并且我确认我得到了正确的hmac /解密密钥,只是rc4不起作用,我试图解密应该==“ Xbox 360”的Kyevault的一部分。 “ 58626F7820333630”

当前输出为:“ 0000008108020000”我在编译中未收到任何错误,再次提供任何帮助将是非常棒的^。^

多亏了约翰的帮助,我才得以解决它,这在C#版本中是一个错误,谢谢约翰!

最佳答案

正如我在评论中指出的那样,您的主要问题似乎涉及如何管理输出缓冲区。此后,您已经修改了该问题以解决此问题,但是无论如何我还是在这里进行描述,并提供其他一些解决方案。最后讨论剩余的问题。

函数rc4_crypt()为其自身分配输出缓冲区,但是它没有机制将指向已分配空间的指针传递回其调用方。在预期如何管理输出缓冲区方面,您修改后的用法还与rc4_crypt()不一致。

解决问题的方法主要有三种。


函数rc4_crypt()目前不返回任何内容,因此您可以让它继续分配缓冲区本身,并对其进行修改以返回指向分配的输出缓冲区的指针。
您可以将outbuf参数的类型修改为uint8_t **以使rc4_crypt()间接设置调用者的指针值。
您可以依靠调用方来管理输出缓冲区,并使rc4_crypt()只是通过传递给它的指针写入输出。


可能对您来说棘手的只有#2;它看起来像这样:

void rc4_crypt(rc4_state_t* state, const uint8_t *inbuf, uint8_t **outbuf, int buflen) {
    *outbuf = malloc(buflen);
    if (*outbuf) {  // do not forget to test for failed allocation
        // ...
        (*outbuf)[idx] = (uint8_t)(num2 ^ num3);
        // ...
    }
}


您将像这样使用它:

rc4_crypt(rc4, buf3, &buf4, 8);


...无需为buf4分配任何内存。

在任何情况下,调用方都有责任在不再需要输出缓冲区时将其释放。当它自己执行分配时,这一点更加清楚。如果rc4_crypt()将负责分配,则应记录该要求。



剩下的问题似乎严格是输出问题。您显然是依靠rc4_crypt()中的打印语句来报告加密数据。无论通过打印语句进行调试,我都没有问题,但是您确实需要小心打印实际要检查的数据。在这种情况下,您不需要。在从输出缓冲区打印字节之前,请在加密循环的末尾更新联合缓冲区索引idx。结果,在每次迭代中,您不会打印刚刚计算出的加密字节值,而是打印一个不确定值,该值恰好位于输出缓冲区的下一个位置。

idx++移至循环的最末端以解决此问题,或将其从while循环更改为for循环,并在循环控制语句的第三项中递增idx。实际上,我强烈建议for循环而不是while循环,在这种情况下,前者非常适合代码的结构(如下所示);我敢说,如果以这种方式构造循环,就不会犯这个错误。

关于c - 弄清楚为什么我的RC4实现无法产生正确的结果,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41025926/

10-11 21:58