[英]How can I reliably transpose an array of chars to an array of uint64_t and back again
我有一个编码DES的类项目,并且在从输入文件中获取64位块时遇到问题。
在加密阶段一切正常,但是当我开始解密时,将文件读入缓冲区后,我的CharArrayToInt64()函数将输入缓冲区的大部分替换为F。
这是我的功能:
void charArrayToInt64(uint64_t *bufferText, char *buffer, long length){
for(size_t i = 0; i < length/8 + 1; i++){
bufferText[i] = 0x0;
bufferText[i] = ((uint64_t)buffer[i*8]<<56)
| ((uint64_t)buffer[i*8 + 1]<<48)
| ((uint64_t)buffer[i*8 + 2]<<40)
| ((uint64_t)buffer[i*8 + 3]<<32)
| ((uint64_t)buffer[i*8 + 4]<<24)
| ((uint64_t)buffer[i*8 + 5]<<16)
| ((uint64_t)buffer[i*8 + 6]<<8)
| ((uint64_t)buffer[i*8 + 7]);
}
}
这是缓冲区的输出,以及加密阶段的uint64_t数组:
Buffer: uint64_t array:
5468 6973 2069 7320 5468 6973 2069 7320
6120 7465 7874 2066 6120 7465 7874 2066
696c 6520 7772 6974 696c 6520 7772 6974
7465 6e20 666f 7220 7465 6e20 666f 7220
7465 7374 2070 7572 7465 7374 2070 7572
706f 7365 732e 2049 706f 7365 732e 2049
6620 4445 5320 776f 6620 4445 5320 776f
726b 7320 636f 7272 726b 7320 636f 7272
6563 746c 792c 2061 6563 746c 792c 2061
6e64 2074 6865 2066 6e64 2074 6865 2066
696c 6520 6973 2072 696c 6520 6973 2072
6561 6420 616e 6420 6561 6420 616e 6420
7370 6c69 7420 7072 7370 6c69 7420 7072
6f70 6572 6c79 2c20 6f70 6572 6c79 2c20
7468 6973 2074 6578 7468 6973 2074 6578
7420 7368 6f75 6c64 7420 7368 6f75 6c64
2072 6574 7572 6e20 2072 6574 7572 6e20
7265 6164 6162 6c65 7265 6164 6162 6c65
2efc ffff ffff fd7f 0000
以下是解密阶段缓冲区和uint64_t数组的输出(请注意,由于我使用的是先前加密的文本,因此它们与上面的不匹配):
Buffer: uint64_t array:
e824 8aa4 db58 5b12 ffff ffff db58 5b12
b8d2 2b8f 980c 915f ffff ffff ffff 915f
f942 a226 9c69 bcc4 ffff ffff ffff ffc4
c660 bd78 179d b628 ffff ffff ffff b628
1ed1 d846 ceb1 f8b5 ffff ffff ffff ffb5
2e67 fa25 66bd 0f13 ffff ffff ffbd 0f13
d11d 1203 d10f dc9e ffff ffff ffff ff9e
6124 0cf1 9393 3816 ffff ffff ff93 3816
efab b9ad fb20 23c0 ffff ffff ffff ffc0
6a2a 20c1 a610 1422 ffff ffff a610 1422
119d d9c5 9de1 0f08 ffff ffff ffe1 0f08
331e d4e7 2214 bdb1 ffff ffff ffff ffb1
c408 74e2 6e14 84e6 ffff ffff ffff ffe6
3fe6 5eca 04c5 70c6 ffff ffff ffff ffc6
12f8 bcaa 1df7 342d ffff ffff fff7 342d
93eb 15d8 eb8d b51e ffff ffff ffff b51e
7fd2 a2d7 b357 a6eb ffff ffff ffff ffeb
7fb9 bf2b 0ebe bb99 ffff ffff ffff ff99
3300 3300 0000 0000 0000
如您所见,在加密阶段,我的函数只会弄乱最后一行,而在解密阶段,完全相同的函数会弄乱最后一行。
在过去的几个小时中,我一直不遗余力地寻求解决方案,因此对您的任何帮助将不胜感激。
如果您需要/想要任何其他信息,我会尽力提供。
EDIT-1:在@ coderredoc,@ chux和@Myst的帮助下,我的问题已基本解决,代码也更加简洁!
(先前的函数
charArrayToInt64()
不再使用)
一个问题仍然存在:那就是如果
bufferText
的最后一个64位块没有被
fread()
完全填充,我最终会
bufferText
似乎无法摆脱的尾随位(即使我在填充它之前将完整块设置为0) )。
这在解密阶段会引起问题:
原始输入文件:
这是为测试目的而编写的文本文件。如果DES正常工作,并且文件已正确读取和拆分,则此文本应返回可读且没有错误。
带有尾随“随机”位的解密输出:
这是为测试目的而编写的文本文件。如果DES正常工作,并且可以正确读取和拆分文件,则此文本应返回可读且无错误†
我试过了:
memset(bufferText, 0, length + 8);
(以及最后一个参数的变体)
bufferText[length/8] = bufferText[length/8]<<((length%8)*8);
(以及之后将它们移回原始位置)
编辑-2
以前的编辑已过时,原来我跳过了一部分作业,该作业要求我一次读取一个字节,进而需要使用fgetc()
和fputc()
进行读写。 所有的答案仍然非常有帮助,虽然很重要,但还是要谢谢大家!
在这个答案中,我将解决实际的问题:
从输入文件获取64位块时遇到问题
...而不是目前为止解决的问题:
将文件读入缓冲区后,我的CharArrayToInt64()函数将输入缓冲区的大部分替换为F。
我建议(IMHO)您直接将文件读取到uint64_t
数组/缓冲区中 ,而不是从字节数组中复制数据。
当您使用unsigned char
数组可能会遇到内存对齐问题时,可以确保uint64_t
数组正确地进行了内存对齐,您只需要担心填充问题...
...哦,请使用unsigned
版本,如该线程上的其他人所指出的,这就是导致问题转移的原因。
一旦两个数组(加密和解密)使用相同的无符号类型,您的代码就会看起来更加整洁。
祝好运。
问题是在您的情况下char
是带符号的(这是实现定义的-char默认情况下在您的计算机上是带符号的)-因此,当移位时,它会针对具有MSB 1
字符进行符号扩展。 在数字的左侧产生一系列ff
。
例如,如果我们将0x24
扩展到所有这些移位,它将是
2400000000000000
24000000000000
240000000000
2400000000
24000000
240000
2400
24
对于0xe8
,将是
e800000000000000
ffe8000000000000
ffffe80000000000
ffffffe800000000
ffffffffe8000000
ffffffffffe80000
ffffffffffffe800
ffffffffffffffe8
现在想想看,当您与其他人进行OR
时, ff
的胜利和所有位都被置位。 您会看到ff
。
在您的情况下正确的解决方案是
bufferText[i] = (((uint64_t)buffer[i*8]<<56) & (uint64_t)0xff<<56)
| (((uint64_t)buffer[i*8 + 1]<<48) & (uint64_t)0xff<<48)
| (((uint64_t)buffer[i*8 + 2]<<40) & (uint64_t)0xff<<40)
| (((uint64_t)buffer[i*8 + 3]<<32) & (uint64_t)0xff<<32)
| (((uint64_t)buffer[i*8 + 4]<<24) & (uint64_t)0xff<<24)
| (((uint64_t)buffer[i*8 + 5]<<16) & (uint64_t)0xff<<16)
| (((uint64_t)buffer[i*8 + 6]<<8) & (uint64_t)0xff<<8)
| (((uint64_t)buffer[i*8 + 7]) & (uint64_t)0xff<<0);
正如chux所提到的,有一个使用unsigned char
typecast的更清洁的解决方案,它类似于
bufferText[i] = ((uint64_t)(unsigned char)buffer[i*8]<<56) |
...
编辑-1
如果您已经将char缓冲区类型声明为unsigned
,则不需要void charArrayToInt64(uint64_t *bufferText, char *buffer, long length){
而是在函数中明确提及它是unsigned char
缓冲区
void charArrayToInt64(uint64_t *bufferText,unsigned char *buffer, long length){ ...
然后,不需要显式强制转换。 使用原始方法,您会做的很好。
使用memset
可以将整个缓冲区归零。 另外,如果您是在使用bufferText[i] = 0x0;
那么从逻辑上讲,您甚至不需要将其初始化为0
因为毕竟您是在下次设置它。 这就是为什么您甚至可以从代码bufferText[i] = 0x0;
删除该行的原因bufferText[i] = 0x0;
另外还有一件事是使用size_t
而不是使用long
length更好,这与你使用length
一起使用更好。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.