我当时正在研究一种加密算法,不知道如何将以下代码更改为更简单的代码,以及如何反转此代码。

typedef struct
{
    unsigned low : 4;
    unsigned high : 4;
} nibles;

static void crypt_enc(char *data, int size)
{
    char last = 0;

    //...

    // Pass 2
    for (i = 0; i < size; i++)
    {
        nibles *n = (nibles *)&data[i];

        n->low = last;
        last = n->high;
        n->high = n->low;
    }
    ((nibles *)&data[0])->low = last;
}

data是此代码的输入和输出。

最佳答案

您将每个字节的两个半字节都设置为相同的东西,因为最后将高半字节设置为与低半字节相同。我假设这是一个错误,您的意图是转移数据中的所有半字节,从一个字节传送到另一个字节,然后四处滚动。当然,ABCDEF(小位从低到高顺序排列)将变为FABCDE。如果我错了,请纠正我。

该代码应类似于:

static void crypt_enc(char *data, int size)
{
    char last = 0;

    //...

    // Pass 2
    for (i = 0; i < size; i++)
    {
        nibles *n = (nibles *)&data[i];

        unsigned char old_low = n->low;
        n->low = last;
        last = n->high;
        n->high = old_low;
    }
    ((nibles *)&data[0])->low = last;
}

现在一切都好吗?否。仅当nibbles*的对齐方式不严格于nibbles的对齐方式时,才强制转换为char。以及that is not guaranteed(但是,对于small change,GCC会生成具有相同对齐方式的类型)。

就个人而言,我将完全避免此问题。这是我的处理方式:
void set_low_nibble(char& c, unsigned char nibble) {
    // assumes nibble has no bits set in the four higher bits)
    unsigned char& b = reinterpret_cast<unsigned char&>(c);
    b = (b & 0xF0) | nibble;
}

void set_high_nibble(char& c, unsigned char nibble) {
    unsigned char& b = reinterpret_cast<unsigned char&>(c);
    b = (b & 0x0F) | (nibble << 4);
}

unsigned char get_low_nibble(unsigned char c) {
    return c & 0x0F;
}

unsigned char get_high_nibble(unsigned char c) {
    return (c & 0xF0) >> 4;
}

static void crypt_enc(char *data, int size)
{
    char last;

    //...

    // Pass 2
    for (i = 0; i < size; ++i)
    {
        unsigned char old_low = get_low_nibble(data[i]);
        set_low_nibble(data[i], last);
        last = get_high_nibble(data[i]);
        set_high_nibble(data[i], old_low);
    }
    set_low_nibble(data[0], last);
}

相反,等于从“低”变为“高”,反之亦然。滚动到最后一个字节,而不是第一个;然后以相反的方向浏览数据:
for (i = size-1; i >= 0; --i)
{
    unsigned char old_high = get_high_nibble(data[i]);
    set_high_nibble(data[i], last);
    last = get_low_nibble(data[i]);
    set_low_nibble(data[i], old_high);
}
set_high_nibble(data[size-1], last);

如果您愿意,可以摆脱对临时last的所有转移。您只需要保存所有的最后半字节,然后直接移位半字节而不使用另一个变量:
last = get_high_nibble(data[size-1]);
for (i = size-1; i > 0; --i) // the last one needs special care
{
    set_high_nibble(data[i], get_low_nibble(data[i]));
    set_low_nibble(data[i], get_high_nibble(data[i-1]));
}
set_high_nibble(data[0], get_low_nibble(data[0]));
set_low_nibble(data[0], last);

09-06 03:09