如何可靠地将一组字符转换为uint64_t数组并再次返回

时间:2017-12-29 16:38:29

标签: c arrays encryption byte

我有一个编写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位bloc没有被fread()完全填充,我最终会得到我无法摆脱的尾随位(即使我在填充之前将整个块设置为0)。这会在解密阶段导致问题:

原始输入文件:

  

这是为测试目的而编写的文本文件。如果DES正常工作,并且文件被正确读取和分割,则该文本应该可读并且没有错误。

带有尾随“随机”位的解密输出:

  

这是为测试目的而编写的文本文件。如果DES工作正常,并且文件被正确读取和拆分,则该文本应该可以返回,并且没有错误的文件

我试过了:  memset(bufferText, 0, length + 8);(以及最后一个参数的变体) bufferText[length/8] = bufferText[length/8]<<((length%8)*8);(以及之后将它们移回原位)

EDIT-2

以前的编辑已经过时,结果我跳过了我的任务的一部分,要求我一次读取一个字节,这又需要使用fgetc()fputc()进行读写。所有的答案仍然非常有用,虽然如此,非常感谢![/ p>

2 个答案:

答案 0 :(得分:2)

在这个答案中,我将解决实际问题:

  

从输入文件中获取64位块时遇到问题

...而不是到目前为止提到的那个:

  
    

将文件读入缓冲区后,我的CharArrayToInt64()函数用F替换输入缓冲区的大部分。

  

我建议(恕我直言)你直接将文件读入uint64_t数组/缓冲区,而不是从字节数组中复制数据。

虽然unsigned char数组可能会遇到内存对齐问题,但uint64_t数组保证正确对齐内存,您只需要担心填充...

...哦,请使用unsigned版本,正如此帖子中的其他人所指出的那样,这就是造成转变问题的原因。

一旦两个数组(加密和解密)使用相同的无符号类型,您的代码看起来会更清晰。

祝你好运。

答案 1 :(得分:1)

问题出在你的情况下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类型转换有一个更清晰的解决方案,就像

 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;中删除这一行,而不是使用long长度,最好使用size_t,这与{{1}一起使用}}