我正在研究加密算法,我想知道如何将以下代码更改为更简单的内容以及如何反转此代码。
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是此代码的输入和输出。
答案 0 :(得分: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*
的对齐方式不比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);
答案 1 :(得分:1)
看起来你只是将每个半字节移动一个位置,然后取最后一个字节的低半字节并将其移动到开头。只需反过来解密(从data
开始,移到开头)
答案 2 :(得分:0)
当您使用位字段时,不太可能存在移位样式方法来移动半字节。如果这种转移对你很重要,那么我建议你考虑将它们存储在某种无符号整数中。在该形式中,可以有效地执行位操作。
答案 3 :(得分:0)
Kevin's answer正是您正在尝试做的事情。但是,你犯了一个基本错误。最终结果是你的整个数组都用零填充而不是旋转半字节。
要知道为什么会这样,我建议你先用同样的方式实现一个字节旋转({a, b, c} -> {c, a, b}
) - 这是通过使用一个从0增加到数组大小的循环计数器。通过减少转换到变量last
来查看是否可以做得更好。
一旦你看到如何做到这一点,你可以简单地将相同的逻辑应用于半字节({al:ah, bl:bh, cl:ch} -> {ch:al, ah:bl, bh:cl}
)。如果您考虑十六进制值,我在此处的表示是不正确的。我的符号中的十六进制值0xXY
为Y:X
。如果你考虑如何完成字节旋转,你可以弄清楚如何只保存一个半字节,只需转移半字节而不实际将它们移动到last
。
答案 4 :(得分: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;
......除非我向后高低。
但无论如何,这在NOWHERE附近的加密领域。这充其量是混淆。通过默默无闻的安全是一种可怕的可怕做法,家庭酿造加密让人们陷入困境。如果你在玩,那就更有力了。但是,如果你真的想要一些安全的东西,那么请使用一个众所周知的安全加密方案来满足你所有字节的需要。