1

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

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 是此代码的输入和输出。

4

5 回答 5

3

您将每个字节的两个半字节设置为相同的值,因为您最终将高半字节设置为与低半字节相同。我假设这是一个错误,您的意图是移动数据中的所有半字节,从一个字节传送到另一个字节,然后滚动。Id est,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*为才被明确定义。这并不能保证(但是,只需稍加更改,GCC 就会生成具有相同对齐方式的类型)。nibbleschar

就个人而言,我会完全避免这个问题。这是我的做法:

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);
于 2011-09-22T19:26:15.030 回答
1

看起来您只是将每个半字节移动一个位置,然后将最后一个字节的低半字节移到开头。只需反向解密(从 末尾开始data,移到开头)

于 2011-09-22T18:53:47.163 回答
0

反转代码是不可能的,因为该算法完全删除了第一个字节并丢弃了其余部分的下半部分。

在 for 循环的第一次迭代中,第一个字节的较低部分设置为零。

n->low = last;

它从来没有在任何地方保存过。它只是消失了。

// I think this is what you were trying for
last = ((nibbles *)&data[0])->low;
for (i = 0; i < size-1; i++)
{
    nibbles *n = (nibbles *)&data[i];
    nibbles *next = (nibbles *)&data[i+1];
    n->low = n->high;
    n->high = next->low;
}
((nibbles *)&data[size-1])->high = last;

要反转它:

last = ((nibbles *)&data[size-1])->high;
for (i = size-1; i > 0; i--)
{
    nibbles *n = (nibbles *)&data[i];
    nibbles *prev = (nibbles *)&data[i-1];
    n->high = n->low;
    n->low = prev->high;
}
((nibbles *)&data[0])->low = last;

...除非我倒退高低。

但无论如何,这在加密领域附近是绝无仅有的。这充其量是混淆。通过默默无闻的安全性是一种可怕的可怕做法,而自制加密会让人们陷入困境。如果你在玩,对你来说更有力量。但是,如果您确实希望某些东西是安全的,请出于对所有字节的热爱,使用众所周知的安全加密方案。

于 2011-09-22T19:35:36.633 回答
0

凯文的答案在您尝试做的事情中是正确的。但是,您犯了一个基本错误。最终结果是您的整个数组都填充了零而不是旋转半字节。

要了解为什么会这样,我建议您首先{a, b, c} -> {c, a, b}以相同的方式实现字节旋转() - 即使用循环计数器从 0 增加到数组大小。看看你是否可以通过减少对变量的转移来做得更好last

一旦你了解了如何做到这一点,你就可以简单地将相同的逻辑应用于半字节 ( {al:ah, bl:bh, cl:ch} -> {ch:al, ah:bl, bh:cl})。如果您从十六进制值的角度考虑,我在这里的表示是不正确的。十六进制值0xXYY:X我的符号中。如果您考虑一下您是如何完成字节轮换的,您可以弄清楚如何只保存一个 nibble,并简单地传输 nibbles 而无需将它们实际移动到last.

于 2011-09-22T19:06:34.460 回答
0

当您使用位域时,不太可能有移位样式的方法来移动半字节。如果这种转移对您很重要,那么我建议您考虑将它们存储在某种无符号整数中。在这种形式下,可以有效地执行位操作。

于 2011-09-22T18:52:47.250 回答